PageRenderTime 68ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/tags/jade_0_7/jade/style/primitive.cxx

#
C++ | 2517 lines | 2365 code | 121 blank | 31 comment | 529 complexity | aa5a1165cde28bc2ad1d79e2fb7c0956 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0
  1. // Copyright (c) 1996 James Clark
  2. // See the file copying.txt for copying permission.
  3. #include "stylelib.h"
  4. #include "Interpreter.h"
  5. #include "InterpreterMessages.h"
  6. #include "EvalContext.h"
  7. #include "SosofoObj.h"
  8. #include "Style.h"
  9. #include "macros.h"
  10. #include "ELObjMessageArg.h"
  11. #include "LocNode.h"
  12. #include "VM.h"
  13. #include <math.h>
  14. #include <limits.h>
  15. #include <stdio.h>
  16. #include <time.h>
  17. #ifdef DSSSL_NAMESPACE
  18. namespace DSSSL_NAMESPACE {
  19. #endif
  20. class DescendantsNodeListObj : public NodeListObj {
  21. public:
  22. void *operator new(size_t, Collector &c) {
  23. return c.allocateObject(1);
  24. }
  25. DescendantsNodeListObj(const NodePtr &, unsigned = 0);
  26. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  27. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  28. NodeListObj *nodeListChunkRest(EvalContext &, Interpreter &, bool &);
  29. private:
  30. static void advance(NodePtr &, unsigned &);
  31. static void chunkAdvance(NodePtr &, unsigned &);
  32. // nodes in node list are strictly after this node
  33. NodePtr start_;
  34. unsigned depth_;
  35. };
  36. class SiblingNodeListObj : public NodeListObj {
  37. public:
  38. void *operator new(size_t, Collector &c) {
  39. return c.allocateObject(1);
  40. }
  41. SiblingNodeListObj(const NodePtr &first, const NodePtr &end);
  42. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  43. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  44. NodeListObj *nodeListChunkRest(EvalContext &, Interpreter &, bool &);
  45. private:
  46. NodePtr first_;
  47. NodePtr end_;
  48. };
  49. class SelectByClassNodeListObj : public NodeListObj {
  50. public:
  51. SelectByClassNodeListObj(NodeListObj *nl, ComponentName::Id);
  52. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  53. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  54. NodeListObj *nodeListChunkRest(EvalContext &, Interpreter &, bool &);
  55. void traceSubObjects(Collector &) const;
  56. private:
  57. NodeListObj *nodeList_;
  58. ComponentName::Id cls_;
  59. };
  60. class MapNodeListObj : public NodeListObj {
  61. public:
  62. class Context : public Resource {
  63. public:
  64. Context(const EvalContext &, const Location &);
  65. void set(EvalContext &) const;
  66. void traceSubObjects(Collector &) const;
  67. Location loc;
  68. private:
  69. NodePtr currentNode_;
  70. const ProcessingMode *processingMode_;
  71. StyleObj *overridingStyle_;
  72. bool haveStyleStack_;
  73. };
  74. void *operator new(size_t, Collector &c) {
  75. return c.allocateObject(1);
  76. }
  77. MapNodeListObj(FunctionObj *func, NodeListObj *nl, const ConstPtr<Context> &, NodeListObj *mapped = 0);
  78. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  79. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  80. void traceSubObjects(Collector &) const;
  81. bool suppressError();
  82. private:
  83. void mapNext(EvalContext &, Interpreter &);
  84. FunctionObj *func_;
  85. NodeListObj *nl_;
  86. NodeListObj *mapped_;
  87. ConstPtr<Context> context_;
  88. };
  89. class ElementPattern : public Resource {
  90. public:
  91. virtual ~ElementPattern();
  92. virtual bool matches(const NodePtr &, SdataMapper &) const = 0;
  93. };
  94. class SelectElementsNodeListObj : public NodeListObj {
  95. public:
  96. void *operator new(size_t, Collector &c) {
  97. return c.allocateObject(1);
  98. }
  99. SelectElementsNodeListObj(NodeListObj *, const ConstPtr<ElementPattern> &);
  100. void traceSubObjects(Collector &) const;
  101. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  102. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  103. private:
  104. NodeListObj *nodeList_;
  105. ConstPtr<ElementPattern> pattern_;
  106. };
  107. class UnionElementPattern : public ElementPattern {
  108. public:
  109. UnionElementPattern(const ConstPtr<ElementPattern> &,
  110. const ConstPtr<ElementPattern> &);
  111. bool matches(const NodePtr &, SdataMapper &) const;
  112. private:
  113. ConstPtr<ElementPattern> pat1_;
  114. ConstPtr<ElementPattern> pat2_;
  115. };
  116. class SimpleElementPattern : public ElementPattern {
  117. public:
  118. SimpleElementPattern(Vector<StringC> &);
  119. bool matches(const NodePtr &, SdataMapper &) const;
  120. private:
  121. // gi followed by att name/value pairs.
  122. // empty gi matches any gi
  123. Vector<StringC> giAtts_;
  124. };
  125. class ParentElementPattern : public ElementPattern {
  126. public:
  127. ParentElementPattern(const ConstPtr<ElementPattern> &pat,
  128. const ConstPtr<ElementPattern> &parentPat);
  129. bool matches(const NodePtr &, SdataMapper &) const;
  130. private:
  131. ConstPtr<ElementPattern> pat_;
  132. ConstPtr<ElementPattern> parentPat_;
  133. };
  134. class NoElementPattern : public ElementPattern {
  135. public:
  136. NoElementPattern() { }
  137. bool matches(const NodePtr &, SdataMapper &) const;
  138. };
  139. #define PRIMITIVE(name, string, nRequired, nOptional, rest) \
  140. class name ## PrimitiveObj : public PrimitiveObj { \
  141. public: \
  142. static const Signature signature_; \
  143. name ## PrimitiveObj() : PrimitiveObj(&signature_) { } \
  144. ELObj *primitiveCall(int, ELObj **, EvalContext &, Interpreter &, const Location &); \
  145. }; \
  146. const Signature name ## PrimitiveObj::signature_ \
  147. = { nRequired, nOptional, rest };
  148. #define XPRIMITIVE PRIMITIVE
  149. #include "primitive.h"
  150. #undef PRIMITIVE
  151. #undef XPRIMITIVE
  152. #define DEFPRIMITIVE(name, argc, argv, context, interp, loc) \
  153. ELObj *name ## PrimitiveObj \
  154. ::primitiveCall(int argc, ELObj **argv, EvalContext &context, Interpreter &interp, \
  155. const Location &loc)
  156. DEFPRIMITIVE(Cons, argc, argv, context, interp, loc)
  157. {
  158. return new (interp) PairObj(argv[0], argv[1]);
  159. }
  160. DEFPRIMITIVE(List, argc, argv, context, interp, loc)
  161. {
  162. if (argc == 0)
  163. return interp.makeNil();
  164. PairObj *head = new (interp) PairObj(argv[0], 0);
  165. ELObjDynamicRoot protect(interp, head);
  166. PairObj *tail = head;
  167. for (int i = 1; i < argc; i++) {
  168. PairObj *tem = new (interp) PairObj(argv[i], 0);
  169. tail->setCdr(tem);
  170. tail = tem;
  171. }
  172. tail->setCdr(interp.makeNil());
  173. return head;
  174. }
  175. DEFPRIMITIVE(IsNull, argc, argv, context, interp, loc)
  176. {
  177. if (argv[0]->isNil())
  178. return interp.makeTrue();
  179. else
  180. return interp.makeFalse();
  181. }
  182. DEFPRIMITIVE(IsList, argc, argv, context, interp, loc)
  183. {
  184. ELObj *obj = argv[0];
  185. for (;;) {
  186. PairObj *pair = obj->asPair();
  187. if (pair)
  188. obj = pair->cdr();
  189. else if (obj->isNil())
  190. return interp.makeTrue();
  191. else
  192. break;
  193. }
  194. return interp.makeFalse();
  195. }
  196. DEFPRIMITIVE(IsEqual, argc, argv, context, interp, loc)
  197. {
  198. if (*argv[0] == *argv[1])
  199. return interp.makeTrue();
  200. else
  201. return interp.makeFalse();
  202. }
  203. DEFPRIMITIVE(Car, argc, argv, context, interp, loc)
  204. {
  205. PairObj *pair = argv[0]->asPair();
  206. if (!pair)
  207. return argError(interp, loc,
  208. InterpreterMessages::notAPair, 0, argv[0]);
  209. else
  210. return pair->car();
  211. }
  212. DEFPRIMITIVE(Cdr, argc, argv, context, interp, loc)
  213. {
  214. PairObj *pair = argv[0]->asPair();
  215. if (!pair)
  216. return argError(interp, loc,
  217. InterpreterMessages::notAPair, 0, argv[0]);
  218. else
  219. return pair->cdr();
  220. }
  221. DEFPRIMITIVE(Append, argc, argv, context, interp, loc)
  222. {
  223. if (argc == 0)
  224. return interp.makeNil();
  225. PairObj *tail = interp.makePair(0, 0);
  226. PairObj *head = tail;
  227. ELObjDynamicRoot protect(interp, head);
  228. for (int i = 0; i < argc - 1; i++) {
  229. for (ELObj *p = argv[i]; !p->isNil();) {
  230. PairObj *tem = p->asPair();
  231. if (!tem)
  232. return argError(interp, loc,
  233. InterpreterMessages::notAList, i, p);
  234. PairObj *newTail = new (interp) PairObj(tem->car(), 0);
  235. tail->setCdr(newTail);
  236. tail = newTail;
  237. p = tem->cdr();
  238. }
  239. }
  240. tail->setCdr(argv[argc - 1]);
  241. return head->cdr();
  242. }
  243. DEFPRIMITIVE(Reverse, argc, argv, context, interp, loc)
  244. {
  245. ELObjDynamicRoot protect(interp, interp.makeNil());
  246. ELObj *p = argv[0];
  247. while (!p->isNil()) {
  248. PairObj *tem = p->asPair();
  249. if (!tem)
  250. return argError(interp, loc,
  251. InterpreterMessages::notAList, 0, argv[0]);
  252. protect = new (interp) PairObj(tem->car(), protect);
  253. p = tem->cdr();
  254. }
  255. return protect;
  256. }
  257. DEFPRIMITIVE(ListTail, argc, argv, context, interp, loc)
  258. {
  259. long k;
  260. if (!argv[1]->exactIntegerValue(k))
  261. return argError(interp, loc,
  262. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  263. if (k < 0) {
  264. interp.setNextLocation(loc);
  265. interp.message(InterpreterMessages::outOfRange);
  266. return interp.makeError();
  267. }
  268. ELObj *p = argv[0];
  269. for (; k > 0; k--) {
  270. PairObj *tem = p->asPair();
  271. if (!tem) {
  272. if (p->isNil()) {
  273. interp.setNextLocation(loc);
  274. interp.message(InterpreterMessages::outOfRange);
  275. return interp.makeError();
  276. }
  277. else
  278. return argError(interp, loc,
  279. InterpreterMessages::notAList, 0, argv[0]);
  280. }
  281. p = tem->cdr();
  282. }
  283. return p;
  284. }
  285. DEFPRIMITIVE(ListRef, argc, argv, context, interp, loc)
  286. {
  287. long k;
  288. if (!argv[1]->exactIntegerValue(k))
  289. return argError(interp, loc,
  290. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  291. if (k < 0) {
  292. interp.setNextLocation(loc);
  293. interp.message(InterpreterMessages::outOfRange);
  294. return interp.makeError();
  295. }
  296. ELObj *p = argv[0];
  297. for (;;) {
  298. PairObj *tem = p->asPair();
  299. if (!tem)
  300. break;
  301. if (k == 0)
  302. return tem->car();
  303. --k;
  304. p = tem->cdr();
  305. }
  306. if (p->isNil()) {
  307. interp.setNextLocation(loc);
  308. interp.message(InterpreterMessages::outOfRange);
  309. return interp.makeError();
  310. }
  311. else
  312. return argError(interp, loc,
  313. InterpreterMessages::notAList, 0, argv[0]);
  314. }
  315. DEFPRIMITIVE(Member, argc, argv, context, interp, loc)
  316. {
  317. ELObj *p = argv[1];
  318. while (!p->isNil()) {
  319. PairObj *tem = p->asPair();
  320. if (!tem)
  321. return argError(interp, loc,
  322. InterpreterMessages::notAList, 1, argv[1]);
  323. if (*argv[0] == *tem->car())
  324. return p;
  325. p = tem->cdr();
  326. }
  327. return interp.makeFalse();
  328. }
  329. DEFPRIMITIVE(Length, argc, argv, context, interp, loc)
  330. {
  331. ELObj *obj = argv[0];
  332. long n = 0;
  333. for (;;) {
  334. PairObj *pair = obj->asPair();
  335. if (pair) {
  336. n++;
  337. obj = pair->cdr();
  338. }
  339. else if (obj->isNil())
  340. break;
  341. else if (interp.isError(obj))
  342. return obj;
  343. else
  344. return argError(interp, loc,
  345. InterpreterMessages::notAList, 0, obj);
  346. }
  347. return interp.makeInteger(n);
  348. }
  349. DEFPRIMITIVE(Not, argc, argv, context, interp, loc)
  350. {
  351. if (argv[0]->isTrue())
  352. return interp.makeFalse();
  353. else
  354. return interp.makeTrue();
  355. }
  356. DEFPRIMITIVE(IsSymbol, argc, argv, context, interp, loc)
  357. {
  358. if (argv[0]->asSymbol())
  359. return interp.makeTrue();
  360. else
  361. return interp.makeFalse();
  362. }
  363. DEFPRIMITIVE(IsKeyword, argc, argv, context, interp, loc)
  364. {
  365. if (argv[0]->asKeyword())
  366. return interp.makeTrue();
  367. else
  368. return interp.makeFalse();
  369. }
  370. DEFPRIMITIVE(IsInteger, argc, argv, context, interp, loc)
  371. {
  372. long n;
  373. if (argv[0]->exactIntegerValue(n))
  374. return interp.makeTrue();
  375. double x;
  376. if (argv[0]->realValue(x) && modf(x, &x) == 0.0)
  377. return interp.makeTrue();
  378. else
  379. return interp.makeFalse();
  380. }
  381. DEFPRIMITIVE(IsReal, argc, argv, context, interp, loc)
  382. {
  383. double x;
  384. if (argv[0]->realValue(x))
  385. return interp.makeTrue();
  386. else
  387. return interp.makeFalse();
  388. }
  389. DEFPRIMITIVE(IsNumber, argc, argv, context, interp, loc)
  390. {
  391. double x;
  392. if (argv[0]->realValue(x))
  393. return interp.makeTrue();
  394. else
  395. return interp.makeFalse();
  396. }
  397. DEFPRIMITIVE(IsQuantity, argc, argv, context, interp, loc)
  398. {
  399. long n;
  400. double d;
  401. int dim;
  402. if (argv[0]->quantityValue(n, d, dim) != ELObj::noQuantity)
  403. return interp.makeTrue();
  404. else
  405. return interp.makeFalse();
  406. }
  407. DEFPRIMITIVE(IsPair, argc, argv, context, interp, loc)
  408. {
  409. if (argv[0]->asPair())
  410. return interp.makeTrue();
  411. else
  412. return interp.makeFalse();
  413. }
  414. DEFPRIMITIVE(IsProcedure, argc, argv, context, interp, loc)
  415. {
  416. if (argv[0]->asFunction())
  417. return interp.makeTrue();
  418. else
  419. return interp.makeFalse();
  420. }
  421. DEFPRIMITIVE(IsBoolean, argc, argv, context, interp, loc)
  422. {
  423. if (argv[0] == interp.makeTrue())
  424. return argv[0];
  425. else if (argv[0] == interp.makeFalse())
  426. return interp.makeTrue();
  427. else
  428. return interp.makeFalse();
  429. }
  430. DEFPRIMITIVE(IsChar, argc, argv, context, interp, loc)
  431. {
  432. Char c;
  433. if (argv[0]->charValue(c))
  434. return interp.makeTrue();
  435. else
  436. return interp.makeFalse();
  437. }
  438. DEFPRIMITIVE(IsCharEqual, argc, argv, context, interp, loc)
  439. {
  440. Char c1, c2;
  441. if (!argv[0]->charValue(c1))
  442. return argError(interp, loc,
  443. InterpreterMessages::notAChar, 0, argv[0]);
  444. if (!argv[1]->charValue(c2))
  445. return argError(interp, loc,
  446. InterpreterMessages::notAChar, 1, argv[1]);
  447. if (c1 == c2)
  448. return interp.makeTrue();
  449. else
  450. return interp.makeFalse();
  451. }
  452. DEFPRIMITIVE(String, argc, argv, context, interp, loc)
  453. {
  454. StringObj *obj = new (interp) StringObj;
  455. for (int i = 0; i < argc; i++) {
  456. Char c;
  457. if (!argv[i]->charValue(c))
  458. return argError(interp, loc,
  459. InterpreterMessages::notAChar, i, argv[i]);
  460. *obj += c;
  461. }
  462. return obj;
  463. }
  464. DEFPRIMITIVE(SymbolToString, argc, argv, context, interp, loc)
  465. {
  466. SymbolObj *obj = argv[0]->asSymbol();
  467. if (!obj)
  468. return argError(interp, loc,
  469. InterpreterMessages::notASymbol, 0, argv[0]);
  470. return obj->name();
  471. }
  472. DEFPRIMITIVE(StringToSymbol, argc, argv, context, interp, loc)
  473. {
  474. const Char *s;
  475. size_t n;
  476. if (!argv[0]->stringData(s, n))
  477. return argError(interp, loc,
  478. InterpreterMessages::notAString, 0, argv[0]);
  479. return interp.makeSymbol(StringC(s, n));
  480. }
  481. DEFPRIMITIVE(IsString, argc, argv, context, interp, loc)
  482. {
  483. const Char *s;
  484. size_t n;
  485. if (argv[0]->stringData(s, n))
  486. return interp.makeTrue();
  487. else
  488. return interp.makeFalse();
  489. }
  490. DEFPRIMITIVE(StringLength, argc, argv, context, interp, loc)
  491. {
  492. const Char *s;
  493. size_t n;
  494. if (!argv[0]->stringData(s, n))
  495. return argError(interp, loc,
  496. InterpreterMessages::notAString, 0, argv[0]);
  497. return interp.makeInteger(n);
  498. }
  499. DEFPRIMITIVE(IsStringEqual, argc, argv, context, interp, loc)
  500. {
  501. const Char *s1, *s2;
  502. size_t n1, n2;
  503. if (!argv[0]->stringData(s1, n1))
  504. return argError(interp, loc,
  505. InterpreterMessages::notAString, 0, argv[0]);
  506. if (!argv[1]->stringData(s2, n2))
  507. return argError(interp, loc,
  508. InterpreterMessages::notAString, 1, argv[1]);
  509. if (n1 == n2
  510. && (n1 == 0 || memcmp(s1, s2, n1*sizeof(Char)) == 0))
  511. return interp.makeTrue();
  512. else
  513. return interp.makeFalse();
  514. }
  515. DEFPRIMITIVE(StringAppend, argc, argv, context, interp, loc)
  516. {
  517. StringObj *result = new (interp) StringObj;
  518. for (int i = 0; i < argc; i++) {
  519. const Char *s;
  520. size_t n;
  521. if (!argv[i]->stringData(s, n))
  522. return argError(interp, loc,
  523. InterpreterMessages::notAString, i,
  524. argv[i]);
  525. result->append(s, n);
  526. }
  527. return result;
  528. }
  529. DEFPRIMITIVE(StringRef, argc, argv, context, interp, loc)
  530. {
  531. const Char *s;
  532. size_t n;
  533. if (!argv[0]->stringData(s, n))
  534. return argError(interp, loc,
  535. InterpreterMessages::notAString, 0, argv[0]);
  536. long k;
  537. if (!argv[1]->exactIntegerValue(k))
  538. return argError(interp, loc,
  539. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  540. if (k < 0 || (unsigned long)k >= n) {
  541. interp.setNextLocation(loc);
  542. interp.message(InterpreterMessages::outOfRange);
  543. return interp.makeError();
  544. }
  545. return interp.makeChar(s[size_t(k)]);
  546. }
  547. DEFPRIMITIVE(Substring, argc, argv, context, interp, loc)
  548. {
  549. const Char *s;
  550. size_t n;
  551. if (!argv[0]->stringData(s, n))
  552. return argError(interp, loc,
  553. InterpreterMessages::notAString, 0, argv[0]);
  554. long start;
  555. if (!argv[1]->exactIntegerValue(start))
  556. return argError(interp, loc,
  557. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  558. long end;
  559. if (!argv[2]->exactIntegerValue(end))
  560. return argError(interp, loc,
  561. InterpreterMessages::notAnExactInteger, 2, argv[2]);
  562. if (start < 0 || (unsigned long)end > n || start > end) {
  563. interp.setNextLocation(loc);
  564. interp.message(InterpreterMessages::outOfRange);
  565. return interp.makeError();
  566. }
  567. return new (interp) StringObj(s + size_t(start), size_t(end - start));
  568. }
  569. DEFPRIMITIVE(Equal, argc, argv, context, interp, loc)
  570. {
  571. if (argc == 0)
  572. return interp.makeTrue();
  573. long lResult;
  574. double dResult;
  575. int dim;
  576. int i = 1;
  577. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  578. case ELObj::noQuantity:
  579. return argError(interp, loc,
  580. InterpreterMessages::notAQuantity, 0, argv[0]);
  581. case ELObj::longQuantity:
  582. break;
  583. case ELObj::doubleQuantity:
  584. goto useDouble;
  585. break;
  586. default:
  587. CANNOT_HAPPEN();
  588. }
  589. long lResult2;
  590. double dResult2;
  591. int dim2;
  592. for (; i < argc; i++) {
  593. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  594. case ELObj::noQuantity:
  595. return argError(interp, loc,
  596. InterpreterMessages::notAQuantity, i, argv[i]);
  597. case ELObj::longQuantity:
  598. if (lResult2 != lResult || dim2 != dim)
  599. return interp.makeFalse();
  600. break;
  601. case ELObj::doubleQuantity:
  602. dResult = lResult;
  603. if (dResult2 != dResult || dim2 != dim)
  604. return interp.makeFalse();
  605. i++;
  606. goto useDouble;
  607. default:
  608. CANNOT_HAPPEN();
  609. }
  610. }
  611. return interp.makeTrue();
  612. useDouble:
  613. for (; i < argc; i++) {
  614. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  615. case ELObj::noQuantity:
  616. return argError(interp, loc,
  617. InterpreterMessages::notAQuantity, i, argv[i]);
  618. case ELObj::longQuantity:
  619. if (lResult2 != dResult || dim2 != dim)
  620. return interp.makeFalse();
  621. break;
  622. case ELObj::doubleQuantity:
  623. if (dResult2 != dResult || dim2 != dim)
  624. return interp.makeFalse();
  625. break;
  626. }
  627. }
  628. return interp.makeTrue();
  629. }
  630. DEFPRIMITIVE(Plus, argc, argv, context, interp, loc)
  631. {
  632. if (argc == 0)
  633. return interp.makeInteger(0);
  634. long lResult;
  635. double dResult;
  636. bool usingD;
  637. int dim;
  638. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  639. case ELObj::noQuantity:
  640. {
  641. const LengthSpec *lsp = argv[0]->lengthSpec();
  642. if (!lsp)
  643. return argError(interp, loc,
  644. InterpreterMessages::notAQuantityOrLengthSpec, 0, argv[0]);
  645. LengthSpec ls(*lsp);
  646. for (int i = 1; i < argc; i++) {
  647. lsp = argv[i]->lengthSpec();
  648. if (lsp)
  649. ls += *lsp;
  650. else {
  651. switch (argv[i]->quantityValue(lResult, dResult, dim)) {
  652. case ELObj::noQuantity:
  653. return argError(interp, loc, InterpreterMessages::notAQuantityOrLengthSpec,
  654. i, argv[i]);
  655. case ELObj::longQuantity:
  656. dResult = lResult;
  657. // fall through
  658. case ELObj::doubleQuantity:
  659. if (dim != 1) {
  660. interp.setNextLocation(loc);
  661. interp.message(InterpreterMessages::incompatibleDimensions);
  662. return interp.makeError();
  663. }
  664. ls += dResult;
  665. break;
  666. }
  667. }
  668. }
  669. return new (interp) LengthSpecObj(ls);
  670. }
  671. case ELObj::longQuantity:
  672. usingD = 0;
  673. break;
  674. case ELObj::doubleQuantity:
  675. usingD = 1;
  676. break;
  677. default:
  678. CANNOT_HAPPEN();
  679. }
  680. for (int i = 1; i < argc; i++) {
  681. long lResult2;
  682. double dResult2;
  683. int dim2;
  684. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  685. case ELObj::noQuantity:
  686. return argError(interp, loc, InterpreterMessages::notAQuantity,
  687. i, argv[i]);
  688. case ELObj::longQuantity:
  689. if (!usingD) {
  690. if (lResult2 < 0) {
  691. if (lResult >= LONG_MIN - lResult2) {
  692. lResult += lResult2;
  693. break;
  694. }
  695. }
  696. else {
  697. if (lResult <= LONG_MAX - lResult2) {
  698. lResult += lResult2;
  699. break;
  700. }
  701. }
  702. usingD = 1;
  703. dResult = double(lResult);
  704. }
  705. dResult += double(lResult2);
  706. break;
  707. case ELObj::doubleQuantity:
  708. if (!usingD) {
  709. dResult = lResult;
  710. usingD = 1;
  711. }
  712. dResult += dResult2;
  713. break;
  714. default:
  715. CANNOT_HAPPEN();
  716. }
  717. if (dim2 != dim) {
  718. interp.setNextLocation(loc);
  719. interp.message(InterpreterMessages::incompatibleDimensions);
  720. return interp.makeError();
  721. }
  722. }
  723. if (!usingD) {
  724. if (dim == 0)
  725. return interp.makeInteger(lResult);
  726. else if (dim == 1)
  727. return new (interp) LengthObj(lResult);
  728. else
  729. dResult = lResult;
  730. }
  731. if (dim == 0)
  732. return new (interp) RealObj(dResult);
  733. else
  734. return new (interp) QuantityObj(dResult, dim);
  735. }
  736. DEFPRIMITIVE(Minus, argc, argv, context, interp, loc)
  737. {
  738. long lResult;
  739. double dResult;
  740. bool usingD;
  741. int dim;
  742. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  743. case ELObj::noQuantity:
  744. {
  745. const LengthSpec *lsp = argv[0]->lengthSpec();
  746. if (!lsp)
  747. return argError(interp, loc,
  748. InterpreterMessages::notAQuantityOrLengthSpec, 0, argv[0]);
  749. LengthSpec ls(*lsp);
  750. for (int i = 1; i < argc; i++) {
  751. lsp = argv[i]->lengthSpec();
  752. if (lsp)
  753. ls -= *lsp;
  754. else {
  755. switch (argv[i]->quantityValue(lResult, dResult, dim)) {
  756. case ELObj::noQuantity:
  757. return argError(interp, loc, InterpreterMessages::notAQuantityOrLengthSpec,
  758. i, argv[i]);
  759. case ELObj::longQuantity:
  760. dResult = lResult;
  761. // fall through
  762. case ELObj::doubleQuantity:
  763. if (dim != 1) {
  764. interp.setNextLocation(loc);
  765. interp.message(InterpreterMessages::incompatibleDimensions);
  766. return interp.makeError();
  767. }
  768. ls -= dResult;
  769. break;
  770. }
  771. }
  772. }
  773. return new (interp) LengthSpecObj(ls);
  774. }
  775. case ELObj::longQuantity:
  776. usingD = 0;
  777. break;
  778. case ELObj::doubleQuantity:
  779. usingD = 1;
  780. break;
  781. default:
  782. CANNOT_HAPPEN();
  783. }
  784. if (argc == 1) {
  785. if (usingD)
  786. dResult = -dResult;
  787. else
  788. lResult = -lResult;
  789. }
  790. else {
  791. for (int i = 1; i < argc; i++) {
  792. long lResult2;
  793. double dResult2;
  794. int dim2;
  795. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  796. case ELObj::noQuantity:
  797. return argError(interp, loc,
  798. InterpreterMessages::notAQuantity, i,
  799. argv[i]);
  800. case ELObj::longQuantity:
  801. if (!usingD) {
  802. if (lResult2 > 0) {
  803. if (lResult >= LONG_MIN + lResult2) {
  804. lResult -= lResult2;
  805. break;
  806. }
  807. }
  808. else {
  809. if (lResult <= LONG_MAX + lResult2) {
  810. lResult -= lResult2;
  811. break;
  812. }
  813. }
  814. usingD = 1;
  815. dResult = double(lResult);
  816. }
  817. dResult -= double(lResult2);
  818. break;
  819. case ELObj::doubleQuantity:
  820. if (!usingD) {
  821. dResult = lResult;
  822. usingD = 1;
  823. }
  824. dResult -= dResult2;
  825. break;
  826. default:
  827. CANNOT_HAPPEN();
  828. }
  829. if (dim2 != dim) {
  830. interp.setNextLocation(loc);
  831. interp.message(InterpreterMessages::incompatibleDimensions);
  832. return interp.makeError();
  833. }
  834. }
  835. }
  836. if (!usingD) {
  837. if (dim == 0)
  838. return interp.makeInteger(lResult);
  839. else if (dim == 1)
  840. return new (interp) LengthObj(lResult);
  841. else
  842. dResult = lResult;
  843. }
  844. if (dim == 0)
  845. return new (interp) RealObj(dResult);
  846. else
  847. return new (interp) QuantityObj(dResult, dim);
  848. }
  849. DEFPRIMITIVE(Multiply, argc, argv, context, interp, loc)
  850. {
  851. if (argc == 0)
  852. return interp.makeInteger(1);
  853. long lResult;
  854. double dResult;
  855. int dim;
  856. int i = 1;
  857. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  858. case ELObj::noQuantity:
  859. {
  860. const LengthSpec *ls = argv[0]->lengthSpec();
  861. if (ls) {
  862. LengthSpec result(*ls);
  863. double d;
  864. for (; i < argc; i++) {
  865. if (!argv[i]->realValue(d))
  866. return argError(interp, loc,
  867. InterpreterMessages::notANumber, 1, argv[1]);
  868. result *= d;
  869. }
  870. return new (interp) LengthSpecObj(result);
  871. }
  872. }
  873. return argError(interp, loc,
  874. InterpreterMessages::notAQuantity, 0, argv[0]);
  875. case ELObj::longQuantity:
  876. break;
  877. case ELObj::doubleQuantity:
  878. goto useDouble;
  879. default:
  880. CANNOT_HAPPEN();
  881. }
  882. long lResult2;
  883. double dResult2;
  884. int dim2;
  885. for (; i < argc; i++) {
  886. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  887. case ELObj::noQuantity:
  888. return argError(interp, loc,
  889. InterpreterMessages::notAQuantity, i, argv[i]);
  890. case ELObj::longQuantity:
  891. dim += dim2;
  892. if (dim > 1
  893. || (lResult2 != 0
  894. && (lResult2 < 0
  895. ? (lResult > 0
  896. ? lResult > -(unsigned)LONG_MIN / -(unsigned)lResult2
  897. : -(unsigned)lResult > LONG_MAX / -(unsigned)lResult2)
  898. : (lResult > 0
  899. ? lResult > LONG_MAX / lResult2
  900. : -(unsigned)lResult > -(unsigned)LONG_MIN / lResult2)))) {
  901. dResult = double(lResult) * lResult2;
  902. i++;
  903. goto useDouble;
  904. }
  905. lResult *= lResult2;
  906. break;
  907. case ELObj::doubleQuantity:
  908. dim += dim2;
  909. dResult = lResult * dResult2;
  910. i++;
  911. goto useDouble;
  912. default:
  913. CANNOT_HAPPEN();
  914. }
  915. }
  916. if (dim == 0)
  917. return interp.makeInteger(lResult);
  918. else
  919. return new (interp) LengthObj(lResult);
  920. useDouble:
  921. for (; i < argc; i++) {
  922. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  923. case ELObj::noQuantity:
  924. return argError(interp, loc,
  925. InterpreterMessages::notAQuantity, i, argv[i]);
  926. case ELObj::longQuantity:
  927. dResult *= lResult2;
  928. break;
  929. case ELObj::doubleQuantity:
  930. dResult *= dResult2;
  931. break;
  932. }
  933. dim += dim2;
  934. }
  935. if (dim == 0)
  936. return new (interp) RealObj(dResult);
  937. else
  938. return new (interp) QuantityObj(dResult, dim);
  939. }
  940. DEFPRIMITIVE(Divide, argc, argv, context, interp, loc)
  941. {
  942. long lResult;
  943. double dResult;
  944. int dim;
  945. if (argc == 1) {
  946. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  947. case ELObj::noQuantity:
  948. return argError(interp, loc,
  949. InterpreterMessages::notAQuantity, 0, argv[0]);
  950. case ELObj::longQuantity:
  951. if (lResult == 0)
  952. goto divide0;
  953. dResult = 1.0/lResult;
  954. break;
  955. case ELObj::doubleQuantity:
  956. if (dResult == 0.0)
  957. goto divide0;
  958. dResult = 1.0/dResult;
  959. break;
  960. default:
  961. CANNOT_HAPPEN();
  962. }
  963. dim = -dim;
  964. }
  965. else {
  966. int i = 1;
  967. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  968. case ELObj::noQuantity:
  969. {
  970. const LengthSpec *ls = argv[0]->lengthSpec();
  971. if (ls) {
  972. LengthSpec result(*ls);
  973. double d;
  974. for (; i < argc; i++) {
  975. if (!argv[i]->realValue(d))
  976. return argError(interp, loc,
  977. InterpreterMessages::notANumber, 1, argv[1]);
  978. if (d == 0.0)
  979. goto divide0;
  980. result /= d;
  981. }
  982. return new (interp) LengthSpecObj(result);
  983. }
  984. }
  985. return argError(interp, loc,
  986. InterpreterMessages::notAQuantity, 0, argv[0]);
  987. case ELObj::longQuantity:
  988. break;
  989. case ELObj::doubleQuantity:
  990. goto useDouble;
  991. default:
  992. CANNOT_HAPPEN();
  993. }
  994. long lResult2;
  995. double dResult2;
  996. int dim2;
  997. for (; i < argc; i++) {
  998. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  999. case ELObj::noQuantity:
  1000. return argError(interp, loc,
  1001. InterpreterMessages::notAQuantity, 0, argv[0]);
  1002. case ELObj::longQuantity:
  1003. if (lResult2 == 0)
  1004. goto divide0;
  1005. dim -= dim2;
  1006. // If dim and dim2 are both 1, must goto useDouble:
  1007. // since lengths are inexact, result must be inexact.
  1008. if (dim2 == 0 && lResult % lResult2 == 0) {
  1009. lResult /= lResult2;
  1010. break;
  1011. }
  1012. dResult = double(lResult)/lResult2;
  1013. i++;
  1014. goto useDouble;
  1015. case ELObj::doubleQuantity:
  1016. dim -= dim2;
  1017. dResult = lResult;
  1018. if (dResult2 == 0.0)
  1019. goto divide0;
  1020. dResult /= dResult2;
  1021. i++;
  1022. goto useDouble;
  1023. default:
  1024. CANNOT_HAPPEN();
  1025. }
  1026. }
  1027. if (dim == 0)
  1028. return interp.makeInteger(lResult);
  1029. else
  1030. return new (interp) LengthObj(lResult);
  1031. useDouble:
  1032. for (; i < argc; i++) {
  1033. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1034. case ELObj::noQuantity:
  1035. return argError(interp, loc,
  1036. InterpreterMessages::notAQuantity, i, argv[i]);
  1037. case ELObj::longQuantity:
  1038. if (lResult2 == 0)
  1039. goto divide0;
  1040. dResult /= lResult2;
  1041. break;
  1042. case ELObj::doubleQuantity:
  1043. dResult /= dResult2;
  1044. if (dResult2 == 0.0)
  1045. goto divide0;
  1046. break;
  1047. }
  1048. dim -= dim2;
  1049. }
  1050. }
  1051. if (dim == 0)
  1052. return new (interp) RealObj(dResult);
  1053. else
  1054. return new (interp) QuantityObj(dResult, dim);
  1055. divide0:
  1056. interp.setNextLocation(loc);
  1057. interp.message(InterpreterMessages::divideBy0);
  1058. return interp.makeError();
  1059. }
  1060. DEFPRIMITIVE(Quotient, argc, argv, context, interp, loc)
  1061. {
  1062. long n1;
  1063. long n2;
  1064. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1065. if (n2 == 0) {
  1066. interp.setNextLocation(loc);
  1067. interp.message(InterpreterMessages::divideBy0);
  1068. return interp.makeError();
  1069. }
  1070. // This isn't strictly portable.
  1071. return interp.makeInteger(n1 / n2);
  1072. }
  1073. double d1;
  1074. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1075. return argError(interp, loc,
  1076. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1077. double d2;
  1078. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1079. return argError(interp, loc,
  1080. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1081. if (d2 == 0.0) {
  1082. interp.setNextLocation(loc);
  1083. interp.message(InterpreterMessages::divideBy0);
  1084. return interp.makeError();
  1085. }
  1086. return new (interp) RealObj((d1 - fmod(d1, d2))/d2);
  1087. }
  1088. DEFPRIMITIVE(Remainder, argc, argv, context, interp, loc)
  1089. {
  1090. long n1;
  1091. long n2;
  1092. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1093. if (n2 == 0) {
  1094. interp.setNextLocation(loc);
  1095. interp.message(InterpreterMessages::divideBy0);
  1096. return interp.makeError();
  1097. }
  1098. // This isn't strictly portable.
  1099. return interp.makeInteger(n1 % n2);
  1100. }
  1101. double d1;
  1102. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1103. return argError(interp, loc,
  1104. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1105. double d2;
  1106. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1107. return argError(interp, loc,
  1108. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1109. if (d2 == 0.0) {
  1110. interp.setNextLocation(loc);
  1111. interp.message(InterpreterMessages::divideBy0);
  1112. return interp.makeError();
  1113. }
  1114. return new (interp) RealObj(fmod(d1, d2));
  1115. }
  1116. DEFPRIMITIVE(Modulo, argc, argv, context, interp, loc)
  1117. {
  1118. long n1;
  1119. long n2;
  1120. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1121. if (n2 == 0) {
  1122. interp.setNextLocation(loc);
  1123. interp.message(InterpreterMessages::divideBy0);
  1124. return interp.makeError();
  1125. }
  1126. long r = n1 % n2;
  1127. if (n2 > 0 ? r < 0 : r > 0)
  1128. r += n2;
  1129. return interp.makeInteger(r);
  1130. }
  1131. double d1;
  1132. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1133. return argError(interp, loc,
  1134. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1135. double d2;
  1136. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1137. return argError(interp, loc,
  1138. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1139. if (d2 == 0.0) {
  1140. interp.setNextLocation(loc);
  1141. interp.message(InterpreterMessages::divideBy0);
  1142. return interp.makeError();
  1143. }
  1144. double r = fmod(d1, d2);
  1145. if (d2 > 0 ? r < 0 : r > 0)
  1146. r += d2;
  1147. return new (interp) RealObj(r);
  1148. }
  1149. #define DEFCOMPARE(NAME, OP) \
  1150. DEFPRIMITIVE(NAME, argc, argv, context, interp, loc) \
  1151. { \
  1152. if (argc == 0) \
  1153. return interp.makeTrue(); \
  1154. long lResult; \
  1155. double dResult; \
  1156. int dim; \
  1157. bool lastWasDouble; \
  1158. switch (argv[0]->quantityValue(lResult, dResult, dim)) { \
  1159. case ELObj::noQuantity: \
  1160. return argError(interp, loc, \
  1161. InterpreterMessages::notAQuantity, 0, argv[0]); \
  1162. case ELObj::longQuantity: \
  1163. lastWasDouble = 0; \
  1164. break; \
  1165. case ELObj::doubleQuantity: \
  1166. lastWasDouble = 1; \
  1167. break; \
  1168. default: \
  1169. CANNOT_HAPPEN(); \
  1170. } \
  1171. for (int i = 1; i < argc; i++) { \
  1172. long lResult2; \
  1173. double dResult2; \
  1174. int dim2; \
  1175. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) { \
  1176. case ELObj::noQuantity: \
  1177. return argError(interp, loc, \
  1178. InterpreterMessages::notAQuantity, i, argv[i]); \
  1179. case ELObj::longQuantity: \
  1180. if (dim2 != dim) \
  1181. goto badDim; \
  1182. if (!(lastWasDouble \
  1183. ? (dResult OP lResult2) \
  1184. : (lResult OP lResult2))) \
  1185. return interp.makeFalse(); \
  1186. lResult = lResult2; \
  1187. lastWasDouble = 0; \
  1188. break; \
  1189. case ELObj::doubleQuantity: \
  1190. if (dim != dim2) \
  1191. goto badDim; \
  1192. if (!(lastWasDouble \
  1193. ? (dResult OP dResult2) \
  1194. : (lResult OP dResult2))) \
  1195. return interp.makeFalse(); \
  1196. dResult = dResult2; \
  1197. lastWasDouble = 1; \
  1198. break; \
  1199. } \
  1200. } \
  1201. return interp.makeTrue(); \
  1202. badDim: \
  1203. interp.setNextLocation(loc); \
  1204. interp.message(InterpreterMessages::incompatibleDimensions); \
  1205. return interp.makeError(); \
  1206. }
  1207. DEFCOMPARE(Less, <)
  1208. DEFCOMPARE(Greater, >)
  1209. DEFCOMPARE(LessEqual, <=)
  1210. DEFCOMPARE(GreaterEqual, >=)
  1211. DEFPRIMITIVE(Min, argc, argv, context, interp, loc)
  1212. {
  1213. long lResult;
  1214. double dResult;
  1215. int dim;
  1216. int i = 1;
  1217. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1218. case ELObj::noQuantity:
  1219. return argError(interp, loc,
  1220. InterpreterMessages::notAQuantity, 0, argv[0]);
  1221. case ELObj::longQuantity:
  1222. break;
  1223. case ELObj::doubleQuantity:
  1224. goto useDouble;
  1225. default:
  1226. CANNOT_HAPPEN();
  1227. }
  1228. // Note that result is inexact if any of the arguments are
  1229. for (; i < argc; i++) {
  1230. long lResult2;
  1231. double dResult2;
  1232. int dim2;
  1233. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1234. case ELObj::noQuantity:
  1235. return argError(interp, loc,
  1236. InterpreterMessages::notAQuantity, i, argv[i]);
  1237. case ELObj::longQuantity:
  1238. if (dim2 != dim)
  1239. goto badDim;
  1240. if (lResult2 < lResult)
  1241. lResult = lResult2;
  1242. break;
  1243. case ELObj::doubleQuantity:
  1244. if (dim != dim2)
  1245. goto badDim;
  1246. if (dResult2 < lResult)
  1247. dResult = dResult2;
  1248. else if (dim)
  1249. break;
  1250. else
  1251. dResult = lResult;
  1252. i++;
  1253. goto useDouble;
  1254. }
  1255. }
  1256. if (dim == 0)
  1257. return interp.makeInteger(lResult);
  1258. else
  1259. return new (interp) LengthObj(lResult);
  1260. useDouble:
  1261. for (; i < argc; i++) {
  1262. long lResult2;
  1263. double dResult2;
  1264. int dim2;
  1265. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1266. case ELObj::noQuantity:
  1267. return argError(interp, loc,
  1268. InterpreterMessages::notAQuantity, i, argv[i]);
  1269. case ELObj::longQuantity:
  1270. if (dim2 != dim)
  1271. goto badDim;
  1272. if (lResult2 < dResult)
  1273. dResult = lResult2;
  1274. break;
  1275. case ELObj::doubleQuantity:
  1276. if (dim != dim2)
  1277. goto badDim;
  1278. if (dResult2 < dResult)
  1279. dResult = dResult2;
  1280. break;
  1281. }
  1282. }
  1283. if (dim == 0)
  1284. return new (interp) RealObj(dResult);
  1285. else
  1286. return new (interp) QuantityObj(dResult, dim);
  1287. badDim:
  1288. interp.setNextLocation(loc);
  1289. interp.message(InterpreterMessages::incompatibleDimensions);
  1290. return interp.makeError();
  1291. }
  1292. DEFPRIMITIVE(Max, argc, argv, context, interp, loc)
  1293. {
  1294. long lResult;
  1295. double dResult;
  1296. int dim;
  1297. int i = 1;
  1298. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1299. case ELObj::noQuantity:
  1300. return argError(interp, loc,
  1301. InterpreterMessages::notAQuantity, 0, argv[0]);
  1302. case ELObj::longQuantity:
  1303. break;
  1304. case ELObj::doubleQuantity:
  1305. goto useDouble;
  1306. default:
  1307. CANNOT_HAPPEN();
  1308. }
  1309. // Note that result is inexact if any of the arguments are
  1310. for (; i < argc; i++) {
  1311. long lResult2;
  1312. double dResult2;
  1313. int dim2;
  1314. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1315. case ELObj::noQuantity:
  1316. return argError(interp, loc,
  1317. InterpreterMessages::notAQuantity, i, argv[i]);
  1318. case ELObj::longQuantity:
  1319. if (dim2 != dim)
  1320. goto badDim;
  1321. if (lResult2 > lResult)
  1322. lResult = lResult2;
  1323. break;
  1324. case ELObj::doubleQuantity:
  1325. if (dim != dim2)
  1326. goto badDim;
  1327. if (dResult2 > lResult)
  1328. dResult = dResult2;
  1329. else if (dim)
  1330. break;
  1331. else
  1332. dResult = lResult;
  1333. i++;
  1334. goto useDouble;
  1335. }
  1336. }
  1337. if (dim == 0)
  1338. return interp.makeInteger(lResult);
  1339. else
  1340. return new (interp) LengthObj(lResult);
  1341. useDouble:
  1342. for (; i < argc; i++) {
  1343. long lResult2;
  1344. double dResult2;
  1345. int dim2;
  1346. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1347. case ELObj::noQuantity:
  1348. return argError(interp, loc,
  1349. InterpreterMessages::notAQuantity, i, argv[i]);
  1350. case ELObj::longQuantity:
  1351. if (dim2 != dim)
  1352. goto badDim;
  1353. if (lResult2 > dResult)
  1354. dResult = lResult2;
  1355. break;
  1356. case ELObj::doubleQuantity:
  1357. if (dim != dim2)
  1358. goto badDim;
  1359. if (dResult2 > dResult)
  1360. dResult = dResult2;
  1361. break;
  1362. }
  1363. }
  1364. if (dim == 0)
  1365. return new (interp) RealObj(dResult);
  1366. else
  1367. return new (interp) QuantityObj(dResult, dim);
  1368. badDim:
  1369. interp.setNextLocation(loc);
  1370. interp.message(InterpreterMessages::incompatibleDimensions);
  1371. return interp.makeError();
  1372. }
  1373. DEFPRIMITIVE(Floor, argc, argv, context, interp, loc)
  1374. {
  1375. double d;
  1376. if (argv[0]->inexactRealValue(d))
  1377. return new (interp) RealObj(floor(d));
  1378. long n;
  1379. if (argv[0]->exactIntegerValue(n))
  1380. return argv[0];
  1381. return argError(interp, loc,
  1382. InterpreterMessages::notANumber, 0, argv[0]);
  1383. }
  1384. DEFPRIMITIVE(Ceiling, argc, argv, context, interp, loc)
  1385. {
  1386. double d;
  1387. if (argv[0]->inexactRealValue(d))
  1388. return new (interp) RealObj(ceil(d));
  1389. long n;
  1390. if (argv[0]->exactIntegerValue(n))
  1391. return argv[0];
  1392. return argError(interp, loc,
  1393. InterpreterMessages::notANumber, 0, argv[0]);
  1394. }
  1395. DEFPRIMITIVE(Round, argc, argv, context, interp, loc)
  1396. {
  1397. double d;
  1398. if (argv[0]->inexactRealValue(d)) {
  1399. double result = floor(d + .5);
  1400. // That rounded it upwards.
  1401. // Now figure out if that was different from round to
  1402. // even.
  1403. if (result - d == 0.5 && fmod(result, 2.0) != 0)
  1404. result -= 1.0;
  1405. return new (interp) RealObj(result);
  1406. }
  1407. long n;
  1408. if (argv[0]->exactIntegerValue(n))
  1409. return argv[0];
  1410. return argError(interp, loc,
  1411. InterpreterMessages::notANumber, 0, argv[0]);
  1412. }
  1413. DEFPRIMITIVE(Truncate, argc, argv, context, interp, loc)
  1414. {
  1415. double d;
  1416. if (argv[0]->inexactRealValue(d)) {
  1417. double iPart;
  1418. modf(d, &iPart);
  1419. return new (interp) RealObj(iPart);
  1420. }
  1421. long n;
  1422. if (argv[0]->exactIntegerValue(n))
  1423. return argv[0];
  1424. return argError(interp, loc,
  1425. InterpreterMessages::notANumber, 0, argv[0]);
  1426. }
  1427. DEFPRIMITIVE(Abs, argc, argv, context, interp, loc)
  1428. {
  1429. long lResult;
  1430. double dResult;
  1431. int dim;
  1432. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1433. case ELObj::noQuantity:
  1434. return argError(interp, loc,
  1435. InterpreterMessages::notAQuantity, 0, argv[0]);
  1436. case ELObj::longQuantity:
  1437. if (lResult != LONG_MIN) {
  1438. if (lResult >= 0)
  1439. return argv[0];
  1440. if (dim == 0)
  1441. return interp.makeInteger(-lResult);
  1442. else
  1443. return new (interp) LengthObj(-lResult);
  1444. }
  1445. dResult = lResult;
  1446. break;
  1447. case ELObj::doubleQuantity:
  1448. break;
  1449. default:
  1450. CANNOT_HAPPEN();
  1451. }
  1452. if (dResult >= 0)
  1453. return argv[0];
  1454. if (dim == 0)
  1455. return new (interp) RealObj(-dResult);
  1456. else
  1457. return new (interp) QuantityObj(-dResult, dim);
  1458. }
  1459. DEFPRIMITIVE(Sqrt, argc, argv, context, interp, loc)
  1460. {
  1461. long lResult;
  1462. double dResult;
  1463. int dim;
  1464. ELObj::QuantityType type
  1465. = argv[0]->quantityValue(lResult, dResult, dim);
  1466. switch (type) {
  1467. case ELObj::noQuantity:
  1468. return argError(interp, loc,
  1469. InterpreterMessages::notAQuantity, 0, argv[0]);
  1470. case ELObj::longQuantity:
  1471. dResult = lResult;
  1472. break;
  1473. case ELObj::doubleQuantity:
  1474. break;
  1475. default:
  1476. CANNOT_HAPPEN();
  1477. }
  1478. if ((dim & 1) || dResult < 0.0) {
  1479. interp.setNextLocation(loc);
  1480. interp.message(InterpreterMessages::outOfRange);
  1481. return interp.makeError();
  1482. }
  1483. dim /= 2;
  1484. dResult = sqrt(dResult);
  1485. if (type == ELObj::longQuantity && dim == 0) {
  1486. long n = long(dResult);
  1487. if (n*n == lResult)
  1488. return interp.makeInteger(n);
  1489. }
  1490. return new (interp) QuantityObj(dResult, dim);
  1491. }
  1492. DEFPRIMITIVE(Time, argc, argv, context, interp, loc)
  1493. {
  1494. // This assumes a Posix compatible time().
  1495. time_t t = time(0);
  1496. return interp.makeInteger(long(t));
  1497. }
  1498. DEFPRIMITIVE(TimeToString, argc, argv, context, interp, loc)
  1499. {
  1500. long k;
  1501. if (!argv[0]->exactIntegerValue(k))
  1502. return argError(interp, loc,
  1503. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1504. time_t t = time_t(k);
  1505. const struct tm *p;
  1506. if (argc > 1 && argv[1] != interp.makeFalse())
  1507. p = gmtime(&t);
  1508. else
  1509. p = localtime(&t);
  1510. char buf[64];
  1511. sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d",
  1512. p->tm_year + 1900, p->tm_mon + 1, p->tm_mday,
  1513. p->tm_hour, p->tm_min, p->tm_sec);
  1514. return new (interp) StringObj(interp.makeStringC(buf));
  1515. }
  1516. DEFPRIMITIVE(CharProperty, argc, argv, context, interp, loc)
  1517. {
  1518. SymbolObj *sym = argv[0]->asSymbol();
  1519. if (!sym)
  1520. return argError(interp, loc,
  1521. InterpreterMessages::notASymbol, 0, argv[0]);
  1522. Char c;
  1523. if (!argv[1]->charValue(c))
  1524. return argError(interp, loc,
  1525. InterpreterMessages::notAChar, 1, argv[1]);
  1526. // FIXME
  1527. if (argc > 2)
  1528. return argv[2];
  1529. else
  1530. return interp.makeFalse();
  1531. }
  1532. DEFPRIMITIVE(Literal, argc, argv, context, interp, loc)
  1533. {
  1534. if (argc == 0)
  1535. return new (interp) EmptySosofoObj;
  1536. const Char *s;
  1537. size_t n;
  1538. if (!argv[0]->stringData(s, n))
  1539. return argError(interp, loc, InterpreterMessages::notAString,
  1540. 0, argv[0]);
  1541. if (argc == 1)
  1542. return new (interp) LiteralSosofoObj(argv[0]);
  1543. StringObj *strObj = new (interp) StringObj(s, n);
  1544. for (int i = 1; i < argc; i++) {
  1545. if (!argv[i]->stringData(s, n))
  1546. return argError(interp, loc, InterpreterMessages::notAString,
  1547. i, argv[i]);
  1548. strObj->append(s, n);
  1549. }
  1550. ELObjDynamicRoot protect(interp, strObj);
  1551. return new (interp) LiteralSosofoObj(strObj);
  1552. }
  1553. DEFPRIMITIVE(ProcessChildren, argc, argv, context, interp, loc)
  1554. {
  1555. if (!context.processingMode) {
  1556. interp.setNextLocation(loc);
  1557. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1558. return interp.makeError();
  1559. }
  1560. return new (interp) ProcessChildrenSosofoObj(context.processingMode);
  1561. }
  1562. DEFPRIMITIVE(ProcessChildrenTrim, argc, argv, context, interp, loc)
  1563. {
  1564. if (!context.processingMode) {
  1565. interp.setNextLocation(loc);
  1566. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1567. return interp.makeError();
  1568. }
  1569. return new (interp) ProcessChildrenTrimSosofoObj(context.processingMode);
  1570. }
  1571. DEFPRIMITIVE(SosofoAppend, argc, argv, context, interp, loc)
  1572. {
  1573. AppendSosofoObj *obj = new (interp) AppendSosofoObj;
  1574. for (int i = 0; i < argc; i++) {
  1575. SosofoObj *sosofo = argv[i]->asSosofo();
  1576. if (!sosofo)
  1577. return argError(interp, loc, InterpreterMessages::notASosofo,
  1578. i, argv[i]);
  1579. obj->append(sosofo);
  1580. }
  1581. return obj;
  1582. }
  1583. DEFPRIMITIVE(NextMatch, argc, argv, context, interp, loc)
  1584. {
  1585. if (!context.processingMode) {
  1586. interp.setNextLocation(loc);
  1587. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1588. return interp.makeError();
  1589. }
  1590. StyleObj *style;
  1591. if (argc == 0)
  1592. style = 0;
  1593. else {
  1594. style = argv[0]->asStyle();
  1595. if (!style)
  1596. return argError(interp, loc, InterpreterMessages::notAStyle, 0, argv[0]);
  1597. }
  1598. return new (interp) NextMatchSosofoObj(style);
  1599. }
  1600. DEFPRIMITIVE(EmptySosofo, argc, argv, context, interp, loc)
  1601. {
  1602. return new (interp) EmptySosofoObj;
  1603. }
  1604. DEFPRIMITIVE(SosofoLabel, argc, argv, context, interp, loc)
  1605. {
  1606. SosofoObj *sosofo = argv[0]->asSosofo();
  1607. if (!sosofo)
  1608. return argError(interp, loc, InterpreterMessages::notASosofo,
  1609. 0, argv[0]);
  1610. SymbolObj *sym = argv[1]->asSymbol();
  1611. if (!sym)
  1612. return argError(interp, loc,
  1613. InterpreterMessages::notASymbol, 1, argv[1]);
  1614. return new (interp) LabelSosofoObj(sym, loc, sosofo);
  1615. }
  1616. DEFPRIMITIVE(SosofoDiscardLabeled, argc, argv, context, interp, loc)
  1617. {
  1618. SosofoObj *sosofo = argv[0]->asSosofo();
  1619. if (!sosofo)
  1620. return argError(interp, loc, InterpreterMessages::notASosofo,
  1621. 0, argv[0]);
  1622. SymbolObj *sym = argv[1]->asSymbol();
  1623. if (!sym)
  1624. return argError(interp, loc,
  1625. InterpreterMessages::notASymbol, 1, argv[1]);
  1626. return new (interp) DiscardLabeledSosofoObj(sym, sosofo);
  1627. }
  1628. DEFPRIMITIVE(IsSosofo, argc, argv, context, interp, loc)
  1629. {
  1630. if (argv[0]->asSosofo())
  1631. return interp.makeTrue();
  1632. else
  1633. return interp.makeFalse();
  1634. }
  1635. DEFPRIMITIVE(MergeStyle, argc, argv, context, interp, loc)
  1636. {
  1637. MergeStyleObj *merged = new (interp) MergeStyleObj;
  1638. for (int i = 0; i < argc; i++) {
  1639. StyleObj *style = argv[i]->asStyle();
  1640. if (!style)
  1641. return argError(interp, loc,
  1642. InterpreterMessages::notAStyle, i, argv[i]);
  1643. merged->append(style);
  1644. }
  1645. return merged;
  1646. }
  1647. DEFPRIMITIVE(IsStyle, argc, argv, context, interp, loc)
  1648. {
  1649. if (argv[0]->asStyle())
  1650. return interp.makeTrue();
  1651. else
  1652. return interp.makeFalse();
  1653. }
  1654. DEFPRIMITIVE(CurrentNodePageNumberSosofo, argc, argv, context, interp, loc)
  1655. {
  1656. if (!context.currentNode)
  1657. return noCurrentNodeError(interp, loc);
  1658. return new (interp) CurrentNodePageNumberSosofoObj(context.currentNode);
  1659. }
  1660. DEFPRIMITIVE(PageNumberSosofo, argc, argv, context, interp, loc)
  1661. {
  1662. return new (interp) PageNumberSosofoObj;
  1663. }
  1664. DEFPRIMITIVE(ProcessElementWithId, argc, argv, context, interp, loc)
  1665. {
  1666. const Char *s;
  1667. size_t n;
  1668. if (!argv[0]->stringData(s, n))
  1669. return argError(interp, loc, InterpreterMessages::notAString, 0, argv[0]);
  1670. if (!context.currentNode)
  1671. return noCurrentNodeError(interp, loc);
  1672. if (!context.processingMode) {
  1673. interp.setNextLocation(loc);
  1674. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1675. return interp.makeError();
  1676. }
  1677. NodePtr root;
  1678. NamedNodeListPtr elements;
  1679. if (context.currentNode->getGroveRoot(root) == accessOK
  1680. && root->getElements(elements) == accessOK) {
  1681. NodePtr node;
  1682. if (elements->namedNode(GroveString(s, n), node) == accessOK)
  1683. return new (interp) ProcessNodeSosofoObj(node, context.processingMode);
  1684. }
  1685. return new (interp) EmptySosofoObj;
  1686. }
  1687. static
  1688. ConstPtr<ElementPattern> convertToPattern(ELObj *obj, Interpreter &interp)
  1689. {
  1690. Vector<StringC> giAtts(1);
  1691. StringObj *str = obj->convertToString();
  1692. if (str) {
  1693. const Char *s;
  1694. size_t n;
  1695. str->stringData(s, n);
  1696. if (!n)
  1697. return new NoElementPattern;
  1698. giAtts[0].assign(s, n);
  1699. interp.normalizeGeneralName(giAtts[0]);
  1700. return new SimpleElementPattern(giAtts);
  1701. }
  1702. else if (obj == interp.makeTrue() || obj->isNil())
  1703. return new SimpleElementPattern(giAtts);
  1704. PairObj *pair = obj->asPair();
  1705. if (!pair)
  1706. return 0;
  1707. str = pair->car()->convertToString();
  1708. if (str) {
  1709. const Char *s;
  1710. size_t n;
  1711. str->stringData(s, n);
  1712. if (!n)
  1713. return new NoElementPattern;
  1714. giAtts[0].assign(s, n);
  1715. interp.normalizeGeneralName(giAtts[0]);
  1716. }
  1717. else if (pair->car() != interp.makeTrue())
  1718. return 0;
  1719. obj = pair->cdr();
  1720. if (!obj->isNil()) {
  1721. pair = obj->asPair();
  1722. if (!pair)
  1723. return 0;
  1724. if (pair->car()->isNil())
  1725. obj = pair->cdr();
  1726. else {
  1727. PairObj *atts = pair->car()->asPair();
  1728. if (atts) {
  1729. obj = pair->cdr();
  1730. for (;;) {
  1731. str = atts->car()->convertToString();
  1732. if (!str)
  1733. return 0;
  1734. const Char *s;
  1735. size_t n;
  1736. str->stringData(s, n);
  1737. giAtts.push_back(StringC(s, n));
  1738. if (atts->cdr()->isNil())
  1739. break;
  1740. atts = atts->cdr()->asPair();
  1741. if (!atts)
  1742. return 0;
  1743. }
  1744. if ((giAtts.size() & 1) == 0)
  1745. return 0;
  1746. }
  1747. }
  1748. if (!obj->isNil()) {
  1749. ConstPtr<ElementPattern> parentPat = convertToPattern(obj, interp);
  1750. if (parentPat.isNull())
  1751. return parentPat;
  1752. return new ParentElementPattern(new SimpleElementPattern(giAtts), parentPat);
  1753. }
  1754. }
  1755. return new SimpleElementPattern(giAtts);
  1756. }
  1757. DEFPRIMITIVE(ProcessFirstDescendant, argc, argv, context, interp, loc)
  1758. {
  1759. if (!context.processingMode) {
  1760. interp.setNextLocation(loc);
  1761. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1762. return interp.makeError();
  1763. }
  1764. if (!context.currentNode)
  1765. return noCurrentNodeError(interp, loc);
  1766. ConstPtr<ElementPattern> pattern;
  1767. for (size_t i = 0; i < argc; i++) {
  1768. ConstPtr<ElementPattern> tem = convertToPattern(argv[i], interp);
  1769. if (tem.isNull())
  1770. return argError(interp, loc,
  1771. InterpreterMessages::notAPattern, i, argv[i]);
  1772. if (pattern.isNull())
  1773. pattern = tem;
  1774. else
  1775. pattern = new UnionElementPattern(tem, pattern);
  1776. }
  1777. if (pattern.isNull())
  1778. return new (interp) EmptySosofoObj;
  1779. NodeListObj *nl = new (interp) DescendantsNodeListObj(context.currentNode);
  1780. ELObjDynamicRoot protect(interp, nl);
  1781. nl = new (interp) SelectElementsNodeListObj(nl, pattern);
  1782. protect = nl;
  1783. NodePtr nd(nl->nodeListFirst(context, interp));
  1784. if (!nd)
  1785. return new (interp) EmptySosofoObj;
  1786. return new (interp) ProcessNodeSosofoObj(nd, context.processingMode);
  1787. }
  1788. DEFPRIMITIVE(ProcessMatchingChildren, argc, argv, context, interp, loc)
  1789. {
  1790. if (!context.processingMode) {
  1791. interp.setNextLocation(loc);
  1792. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1793. return interp.makeError();
  1794. }
  1795. if (!context.currentNode)
  1796. return noCurrentNodeError(interp, loc);
  1797. ConstPtr<ElementPattern> pattern;
  1798. for (size_t i = 0; i < argc; i++) {
  1799. ConstPtr<ElementPattern> tem = convertToPattern(argv[i], interp);
  1800. if (tem.isNull())
  1801. return argError(interp, loc,
  1802. InterpreterMessages::notAPattern, i, argv[i]);
  1803. if (pattern.isNull())
  1804. pattern = tem;
  1805. else
  1806. pattern = new UnionElementPattern(tem, pattern);
  1807. }
  1808. NodeListPtr nlPtr;
  1809. // FIXME handle root
  1810. if (pattern.isNull() || context.currentNode->children(nlPtr) != accessOK)
  1811. return new (interp) EmptySosofoObj;
  1812. NodeListObj *nl = new (interp) NodeListPtrNodeListObj(nlPtr);
  1813. ELObjDynamicRoot protect(interp, nl);
  1814. nl = new (interp) SelectElementsNodeListObj(nl, pattern);
  1815. protect = nl;
  1816. return new (interp) ProcessNodeListSosofoObj(nl, context.processingMode);
  1817. }
  1818. DEFPRIMITIVE(SelectElements, argc, argv, context, interp, loc)
  1819. {
  1820. NodeListObj *nl = argv[0]->asNodeList();
  1821. if (!nl)
  1822. return argError(interp, loc,
  1823. InterpreterMessages::notANodeList, 0, argv[0]);
  1824. ConstPtr<ElementPattern> pattern(convertToPattern(argv[1], interp));
  1825. if (pattern.isNull())
  1826. return argError(interp, loc,
  1827. InterpreterMessages::notAPattern, 1, argv[1]);
  1828. return new (interp) SelectElementsNodeListObj(nl, pattern);
  1829. }
  1830. DEFPRIMITIVE(ProcessNodeList, argc, argv, context, interp, loc)
  1831. {
  1832. if (!context.processingMode) {
  1833. interp.setNextLocation(loc);
  1834. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1835. return interp.makeError();
  1836. }
  1837. NodeListObj *nl = argv[0]->asNodeList();
  1838. if (!nl)
  1839. return argError(interp, loc,
  1840. InterpreterMessages::notANodeList, 0, argv[0]);
  1841. return new (interp) ProcessNodeListSosofoObj(nl, context.processingMode);
  1842. }
  1843. static
  1844. void reverse(StringC &s)
  1845. {
  1846. size_t i = 0;
  1847. size_t j = s.size() - 1;
  1848. while (i < j) {
  1849. Char tem = s[i];
  1850. s[i] = s[j];
  1851. s[j] = tem;
  1852. i++;
  1853. j--;
  1854. }
  1855. }
  1856. static
  1857. StringC formatNumberLetter(long n, const char *letters)
  1858. {
  1859. StringC result;
  1860. if (n == 0)
  1861. result += '0';
  1862. else {
  1863. bool neg;
  1864. // FIXME possibility of overflow
  1865. if (n < 0) {
  1866. n = -n;
  1867. neg = 1;
  1868. }
  1869. else
  1870. neg = 0;
  1871. do {
  1872. n--;
  1873. int r = n % 26;
  1874. n -= r;
  1875. n /= 26;
  1876. result += letters[r];
  1877. } while (n > 0);
  1878. if (neg)
  1879. result += '-';
  1880. reverse(result);
  1881. }
  1882. return result;
  1883. }
  1884. static
  1885. StringC formatNumberDecimal(long n, size_t minWidth)
  1886. {
  1887. StringC result;
  1888. char buf[32];
  1889. sprintf(buf, "%ld", n);
  1890. const char *p = buf;
  1891. if (*p == '-') {
  1892. p++;
  1893. result += '-';
  1894. }
  1895. size_t len = strlen(p);
  1896. while (len < minWidth) {
  1897. result += '0';
  1898. len++;
  1899. }
  1900. while (*p)
  1901. result += *p++;
  1902. return result;
  1903. }
  1904. static
  1905. StringC formatNumberRoman(long n, const char *letters)
  1906. {
  1907. StringC result;
  1908. if (n > 5000 || n < -5000 || n == 0)
  1909. return formatNumberDecimal(n, 1);
  1910. if (n < 0) {
  1911. n = -n;
  1912. result += '-';
  1913. }
  1914. while (n >= 1000) {
  1915. result += letters[0];
  1916. n -= 1000;
  1917. }
  1918. for (int i = 100; i > 0; i /= 10, letters += 2) {
  1919. long q = n / i;
  1920. n -= q * i;
  1921. switch (q) {
  1922. case 1:
  1923. result += letters[2];
  1924. break;
  1925. case 2:
  1926. result += letters[2];
  1927. result += letters[2];
  1928. break;
  1929. case 3:
  1930. result += letters[2];
  1931. result += letters[2];
  1932. result += letters[2];
  1933. break;
  1934. case 4:
  1935. result += letters[2];
  1936. result += letters[1];
  1937. break;
  1938. case 5:
  1939. result += letters[1];
  1940. break;
  1941. case 6:
  1942. result += letters[1];
  1943. result += letters[2];
  1944. break;
  1945. case 7:
  1946. result += letters[1];
  1947. result += letters[2];
  1948. result += letters[2];
  1949. break;
  1950. case 8:
  1951. result += letters[1];
  1952. result += letters[2];
  1953. result += letters[2];
  1954. result += letters[2];
  1955. break;
  1956. case 9:
  1957. result += letters[2];
  1958. result += letters[0];
  1959. break;
  1960. }
  1961. }
  1962. return result;
  1963. }
  1964. static
  1965. bool formatNumber(long n, const Char *s, size_t len, StringC &result)
  1966. {
  1967. if (len > 0) {
  1968. switch (s[len - 1]) {
  1969. case 'a':
  1970. result += formatNumberLetter(n, "abcdefghijklmnopqrstuvwxyz");
  1971. return 1;
  1972. case 'A':
  1973. result += formatNumberLetter(n, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  1974. return 1;
  1975. case 'i':
  1976. result += formatNumberRoman(n, "mdclxvi");
  1977. return 1;
  1978. case 'I':
  1979. result += formatNumberRoman(n, "MDCLXVI");
  1980. return 1;
  1981. case '1':
  1982. result += formatNumberDecimal(n, len);
  1983. return 1;
  1984. default:
  1985. break;
  1986. }
  1987. }
  1988. result += formatNumberDecimal(n, 1);
  1989. return 0;
  1990. }
  1991. DEFPRIMITIVE(FormatNumber, argc, argv, context, interp, loc)
  1992. {
  1993. long n;
  1994. if (!argv[0]->exactIntegerValue(n))
  1995. return argError(interp, loc,
  1996. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1997. const Char *s;
  1998. size_t len;
  1999. if (!argv[1]->stringData(s, len))
  2000. return argError(interp, loc, InterpreterMessages::notAString, 1, argv[1]);
  2001. StringObj *result = new (interp) StringObj;
  2002. if (!formatNumber(n, s, len, *result)) {
  2003. interp.setNextLocation(loc);
  2004. interp.message(InterpreterMessages::invalidNumberFormat,
  2005. StringMessageArg(StringC(s, len)));
  2006. }
  2007. return result;
  2008. }
  2009. DEFPRIMITIVE(FormatNumberList, argc, argv, context, interp, loc)
  2010. {
  2011. ELObj *numbers = argv[0];
  2012. ELObj *formats = argv[1];
  2013. ELObj *seps = argv[2];
  2014. StringObj *result = new (interp) StringObj;
  2015. while (!numbers->isNil()) {
  2016. PairObj *tem;
  2017. const Char *s;
  2018. size_t len;
  2019. if (numbers != argv[0]) {
  2020. if (!seps->stringData(s, len)) {
  2021. tem = seps->asPair();
  2022. if (!tem)
  2023. return argError(interp, loc,
  2024. InterpreterMessages::notAList, 2, argv[2]);
  2025. if (!tem->car()->stringData(s, len))
  2026. return argError(interp, loc,
  2027. InterpreterMessages::notAString, 2, tem->car());
  2028. seps = tem->cdr();
  2029. }
  2030. result->append(s, len);
  2031. }
  2032. tem = numbers->asPair();
  2033. if (!tem)
  2034. return argError(interp, loc,
  2035. InterpreterMessages::notAList, 0, argv[0]);
  2036. long k;
  2037. if (!tem->car()->exactIntegerValue(k))
  2038. // FIXME message not quite right
  2039. return argError(interp, loc,
  2040. InterpreterMessages::notAnExactInteger, 0, tem->car());
  2041. numbers = tem->cdr();
  2042. if (!formats->stringData(s, len)) {
  2043. tem = formats->asPair();
  2044. if (!tem)
  2045. return argError(interp, loc,
  2046. InterpreterMessages::notAList, 1, argv[1]);
  2047. if (!tem->car()->stringData(s, len))
  2048. return argError(interp, loc,
  2049. InterpreterMessages::notAString, 0, tem->car());
  2050. formats = tem->cdr();
  2051. }
  2052. if (!formatNumber(k, s, len, *result)) {
  2053. interp.setNextLocation(loc);
  2054. interp.message(InterpreterMessages::invalidNumberFormat,
  2055. StringMessageArg(StringC(s, len)));
  2056. }
  2057. }
  2058. return result;
  2059. }
  2060. DEFPRIMITIVE(ExternalProcedure, argc, argv, context, interp, loc)
  2061. {
  2062. const Char *s;
  2063. size_t n;
  2064. if (!argv[0]->stringData(s, n))
  2065. return argError(interp, loc,
  2066. InterpreterMessages::notAString, 0, argv[0]);
  2067. StringC tem(s, n);
  2068. FunctionObj *func = interp.lookupExternalProc(tem);
  2069. if (func)
  2070. return func;
  2071. return interp.makeFalse();
  2072. }
  2073. DEFPRIMITIVE(Error, argc, argv, context, interp, loc)
  2074. {
  2075. const Char *s;
  2076. size_t n;
  2077. if (!argv[0]->stringData(s, n))
  2078. return argError(interp, loc,
  2079. InterpreterMessages::notAString, 0, argv[0]);
  2080. interp.setNextLocation(loc);
  2081. interp.message(InterpreterMessages::errorProc,
  2082. StringMessageArg(StringC(s, n)));
  2083. return interp.makeError();
  2084. }
  2085. DEFPRIMITIVE(StringToNumber, argc, argv, context, interp, loc)
  2086. {
  2087. const Char *s;
  2088. size_t n;
  2089. if (!argv[0]->stringData(s, n))
  2090. return argError(interp, loc,
  2091. InterpreterMessages::notAString, 0, argv[0]);
  2092. long radix;
  2093. if (argc > 1) {
  2094. if (!argv[1]->exactIntegerValue(radix))
  2095. return argError(interp, loc,
  2096. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  2097. switch (radix) {
  2098. case 2:
  2099. case 8:
  2100. case 10:
  2101. case 16:
  2102. break;
  2103. default:
  2104. interp.setNextLocation(loc);
  2105. interp.message(InterpreterMessages::invalidRadix);
  2106. radix = 10;
  2107. break;
  2108. }
  2109. }
  2110. else
  2111. radix = 10;
  2112. StringC tem(s, n);
  2113. return interp.convertNumber(tem, 0, int(radix));
  2114. }
  2115. DEFPRIMITIVE(NumberToString, argc, argv, context, interp, loc)
  2116. {
  2117. // FIXME use optional radix
  2118. double x;
  2119. if (!argv[0]->realValue(x))
  2120. return argError(interp, loc,
  2121. InterpreterMessages::notANumber, 0, argv[0]);
  2122. StrOutputCharStream os;
  2123. argv[0]->print(interp, os);
  2124. StringC tem;
  2125. os.extractString(tem);
  2126. return new (interp) StringObj(tem);
  2127. }
  2128. DEFPRIMITIVE(DisplaySize, argc, argv, context, interp, loc)
  2129. {
  2130. return new (interp) LengthSpecObj(LengthSpec(LengthSpec::displaySize, 1.0));
  2131. }
  2132. DEFPRIMITIVE(TableUnit, argc, argv, context, interp, loc)
  2133. {
  2134. long k;
  2135. if (!argv[0]->exactIntegerValue(k))
  2136. return argError(interp, loc,
  2137. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  2138. return new (interp) LengthSpecObj(LengthSpec(LengthSpec::tableUnit, double(k)));
  2139. }
  2140. DEFPRIMITIVE(IsDisplaySpace, argc, argv, context, interp, loc)
  2141. {
  2142. if (argv[0]->asDisplaySpace())
  2143. return interp.makeTrue();
  2144. else
  2145. return interp.makeFalse();
  2146. }
  2147. DEFPRIMITIVE(DisplaySpace, argc, argv, context, interp, loc)
  2148. {
  2149. FOTBuilder::DisplaySpace displaySpace;
  2150. if (!interp.convertLengthSpec(argv[0], displaySpace.nominal))
  2151. return argError(interp, loc,
  2152. InterpreterMessages::notALengthSpec, 0, argv[0]);
  2153. displaySpace.min = displaySpace.nominal;
  2154. displaySpace.max = displaySpace.nominal;
  2155. // first specified keyword argument takes priority,
  2156. // so scan them backwards...
  2157. for (int i = argc - 1; i > 0; i -= 2) {
  2158. if ((argc & 1) == 0) {
  2159. interp.setNextLocation(loc);
  2160. interp.message(InterpreterMessages::oddKeyArgs);
  2161. return interp.makeError();
  2162. }
  2163. KeywordObj *keyObj = argv[i - 1]->asKeyword();
  2164. if (!keyObj) {
  2165. interp.setNextLocation(loc);
  2166. interp.message(InterpreterMessages::keyArgsNotKey);
  2167. return interp.makeError();
  2168. }
  2169. Identifier::SyntacticKey key;
  2170. if (!keyObj->identifier()->syntacticKey(key)) {
  2171. interp.setNextLocation(loc);
  2172. interp.message(InterpreterMessages::invalidKeyArg,
  2173. StringMessageArg(keyObj->identifier()->name()));
  2174. return interp.makeError();
  2175. }
  2176. else {
  2177. switch (key) {
  2178. case Identifier::keyMin:
  2179. if (!interp.convertLengthSpec(argv[i], displaySpace.min))
  2180. return argError(interp, loc,
  2181. InterpreterMessages::notALengthSpec, i, argv[i]);
  2182. break;
  2183. case Identifier::keyMax:
  2184. if (!interp.convertLengthSpec(argv[i], displaySpace.max))
  2185. return argError(interp, loc,
  2186. InterpreterMessages::notALengthSpec, i, argv[i]);
  2187. break;
  2188. case Identifier::keyIsConditional:
  2189. if (argv[i] == interp.makeTrue())
  2190. displaySpace.conditional = 1;
  2191. else if (argv[i] == interp.makeFalse())
  2192. displaySpace.conditional = 0;
  2193. else
  2194. return argError(interp, loc,
  2195. InterpreterMessages::notABoolean, i, argv[i]);
  2196. break;
  2197. case Identifier::keyPriority:
  2198. if (argv[i]->exactIntegerValue(displaySpace.priority))
  2199. displaySpace.force = 0;
  2200. else {
  2201. SymbolObj *sym = argv[i]->asSymbol();
  2202. if (sym && sym->cValue() == FOTBuilder::symbolForce)
  2203. displaySpace.force = 1;
  2204. else
  2205. return argError(interp, loc,
  2206. InterpreterMessages::notAPriority, i, argv[i]);
  2207. }
  2208. break;
  2209. default:
  2210. interp.setNextLocation(loc);
  2211. interp.message(InterpreterMessages::invalidKeyArg,
  2212. StringMessageArg(keyObj->identifier()->name()));
  2213. return interp.makeError();
  2214. }
  2215. }
  2216. }
  2217. return new (interp) DisplaySpaceObj(displaySpace);
  2218. }
  2219. DEFPRIMITIVE(IsInlineSpace, argc, argv, context, interp, loc)
  2220. {
  2221. if (argv[0]->asInlineSpace())
  2222. return interp.makeTrue();
  2223. else
  2224. return interp.makeFalse();
  2225. }
  2226. DEFPRIMITIVE(InlineSpace, argc, argv, context, interp, loc)
  2227. {
  2228. FOTBuilder::InlineSpace inlineSpace;
  2229. if (!interp.convertLengthSpec(argv[0], inlineSpace.nominal))
  2230. return argError(interp, loc,
  2231. InterpreterMessages::notALengthSpec, 0, argv[0]);
  2232. inlineSpace.min = inlineSpace.nominal;
  2233. inlineSpace.max = inlineSpace.nominal;
  2234. // first specified keyword argument takes priority,
  2235. // so scan them backwards...
  2236. for (int i = argc - 1; i > 0; i -= 2) {
  2237. if ((argc & 1) == 0) {
  2238. interp.setNextLocation(loc);
  2239. interp.message(InterpreterMessages::oddKeyArgs);
  2240. return interp.makeError();
  2241. }
  2242. KeywordObj *keyObj = argv[i - 1]->asKeyword();
  2243. if (!keyObj) {
  2244. interp.setNextLocation(loc);
  2245. interp.message(InterpreterMessages::keyArgsNotKey);
  2246. return interp.makeError();
  2247. }
  2248. Identifier::SyntacticKey key;
  2249. if (!keyObj->identifier()->syntacticKey(key)) {
  2250. interp.setNextLocation(loc);
  2251. interp.message(InterpreterMessages::invalidKeyArg,
  2252. StringMessageArg(keyObj->identifier()->name()));
  2253. return interp.makeError();
  2254. }
  2255. else {
  2256. switch (key) {
  2257. case Identifier::keyMin:
  2258. if (!interp.convertLengthSpec(argv[i], inlineSpace.min))
  2259. return argError(interp, loc,
  2260. InterpreterMessages::notALengthSpec, i, argv[i]);
  2261. break;
  2262. case Identifier::keyMax:
  2263. if (!interp.convertLengthSpec(argv[i], inlineSpace.max))
  2264. return argError(interp, loc,
  2265. InterpreterMessages::notALengthSpec, i, argv[i]);
  2266. break;
  2267. default:
  2268. interp.setNextLocation(loc);
  2269. interp.message(InterpreterMessages::invalidKeyArg,
  2270. StringMessageArg(keyObj->identifier()->name()));
  2271. return interp.makeError();
  2272. }
  2273. }
  2274. }
  2275. return new (interp) InlineSpaceObj(inlineSpace);
  2276. return argv[0];
  2277. }
  2278. DEFPRIMITIVE(IsColor, argc, argv, context, interp, loc)
  2279. {
  2280. if (argv[0]->asColor())
  2281. return interp.makeTrue();
  2282. else
  2283. return interp.makeFalse();
  2284. }
  2285. DEFPRIMITIVE(IsColorSpace, argc, argv, context, interp, loc)
  2286. {
  2287. if (argv[0]->asColorSpace())
  2288. return interp.makeTrue();
  2289. else
  2290. return interp.makeFalse();
  2291. }
  2292. DEFPRIMITIVE(ColorSpace, argc, argv, context, interp, loc)
  2293. {
  2294. const Char *s;
  2295. size_t n;
  2296. if (!argv[0]->stringData(s, n))
  2297. return argError(interp, loc,
  2298. InterpreterMessages::notAString, 0, argv[0]);
  2299. if (StringC(s, n)
  2300. != interp.makeStringC("ISO/IEC 10179:1996//Color-Space Family::Device RGB")) {
  2301. interp.setNextLocation(loc);
  2302. interp.message(InterpreterMessages::unknownColorSpaceFamily,
  2303. StringMessageArg(StringC(s, n)));
  2304. return interp.makeError();
  2305. }
  2306. if (argc > 1) {
  2307. interp.setNextLocation(loc);
  2308. interp.message(InterpreterMessages::deviceRGBColorSpaceNoArgs);
  2309. }
  2310. return new (interp) DeviceRGBColorSpaceObj;
  2311. }
  2312. DEFPRIMITIVE(Color, argc, argv, context, interp, loc)
  2313. {
  2314. ColorSpaceObj *colorSpace = argv[0]->asColorSpace();
  2315. if (!colorSpace)
  2316. return argError(interp, loc,
  2317. InterpreterMessages::notAColorSpace, 0, argv[0]);
  2318. return colorSpace->makeColor(argc - 1, argv + 1, interp, loc);
  2319. }
  2320. DEFPRIMITIVE(IsAddress, argc, argv, context, interp, loc)
  2321. {
  2322. if (argv[0]->asAddress())
  2323. return interp.makeTrue();
  2324. else
  2325. return interp.makeFalse();
  2326. }
  2327. DEFPRIMITIVE(IsAddressLocal, argc, argv, context, interp, loc)
  2328. {
  2329. AddressObj *address = argv[0]->asAddress();
  2330. if (!address)
  2331. return argError(interp, loc,
  2332. InterpreterMessages::notAnAddress, 0, argv[0]);
  2333. if (!context.currentNode)
  2334. return noCurrentNodeError(interp, loc);
  2335. switch (address->address().type) {
  2336. case FOTBuilder::Address::resolvedNode:
  2337. if (address->address().node->sameGrove(*context.currentNode))
  2338. return interp.makeTrue();
  2339. else
  2340. return interp.makeFalse();
  2341. case FOTBuilder::Address::idref:
  2342. return interp.makeTrue();
  2343. case FOTBuilder::Address::entity:
  2344. return interp.makeFalse();
  2345. default:
  2346. break;
  2347. }
  2348. return interp.makeFalse();
  2349. }
  2350. DEFPRIMITIVE(IsAddressVisited, argc, argv, context, interp, loc)
  2351. {
  2352. AddressObj *address = argv[0]->asAddress();
  2353. if (!address)
  2354. return argError(interp, loc,
  2355. InterpreterMessages::notAnAddress, 0, argv[0]);
  2356. // FIXME
  2357. return interp.makeFalse();
  2358. }
  2359. DEFPRIMITIVE(CurrentNodeAddress, argc, argv, context, interp, loc)
  2360. {
  2361. if (!context.currentNode)
  2362. return noCurrentNodeError(interp, loc);
  2363. return new (interp) AddressObj(FOTBuilder::Address::resolvedNode, context.currentNode);
  2364. }
  2365. DEFPRIMITIVE(HytimeLinkend, argc, argv, context, interp, loc)
  2366. {
  2367. if (!context.currentNode)
  2368. return noCurrentNodeError(interp, loc);
  2369. return new (interp) AddressObj(FOTBuilder::Address::hytimeLinkend, context.currentNode);
  2370. }
  2371. DEFPRIMITIVE(SgmlDocumentAddress, argc, argv, context, interp, loc)
  2372. {
  2373. const Char *s;
  2374. size_t n;
  2375. if (!argv[0]->stringData(s, n))
  2376. return argError(interp, loc,
  2377. InterpreterMessages::notAString, 0, argv[0]);
  2378. StringC sysid(s, n);
  2379. if (!argv[1]->stringData(s, n))
  2380. return argError(interp, loc,
  2381. InterpreterMessages::notAString, 1, argv[1]);
  2382. return new (interp) AddressObj(FOTBuilder::Address::sgmlDocument, NodePtr(), sysid, StringC(s, n));
  2383. }
  2384. DEFPRIMITIVE(IdrefAddress, argc, argv, context, interp, loc)
  2385. {
  2386. // The advantage of doing this rather than using an NodeAddressObj,
  2387. // is that when it's a forward reference we don't have to
  2388. // wait for the node. It might be cleaner to use a ProxyNode class
  2389. // for this.
  2390. const Char *s;
  2391. size_t n;
  2392. if (!argv[0]->stringData(s, n))
  2393. return argError(interp, loc,
  2394. InterpreterMessages::notAString, 0, argv[0]);
  2395. if (!context.currentNode)
  2396. return noCurrentNodeError(interp, lo