PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/branches/jade_valid_fo/style/primitive.cxx

#
C++ | 2512 lines | 2368 code | 119 blank | 25 comment | 565 complexity | def5ec0a58ee42a99747b89b111a1755 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  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 "Insn.h"
  10. #include "macros.h"
  11. #include "ELObjMessageArg.h"
  12. #include "LocNode.h"
  13. #include "VM.h"
  14. #include "Pattern.h"
  15. #include "ELObjPropVal.h"
  16. #include <math.h>
  17. #include <limits.h>
  18. #include <stdio.h>
  19. #include <time.h>
  20. #include "LangObj.h"
  21. #include <ctype.h>
  22. #ifdef DSSSL_NAMESPACE
  23. namespace DSSSL_NAMESPACE {
  24. #endif
  25. class DescendantsNodeListObj : public NodeListObj {
  26. public:
  27. void *operator new(size_t, Collector &c) {
  28. return c.allocateObject(1);
  29. }
  30. DescendantsNodeListObj(const NodePtr &, unsigned = 0);
  31. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  32. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  33. NodeListObj *nodeListChunkRest(EvalContext &, Interpreter &, bool &);
  34. private:
  35. static void advance(NodePtr &, unsigned &);
  36. static void chunkAdvance(NodePtr &, unsigned &);
  37. // nodes in node list are strictly after this node
  38. NodePtr start_;
  39. unsigned depth_;
  40. };
  41. class SiblingNodeListObj : public NodeListObj {
  42. public:
  43. void *operator new(size_t, Collector &c) {
  44. return c.allocateObject(1);
  45. }
  46. SiblingNodeListObj(const NodePtr &first, const NodePtr &end);
  47. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  48. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  49. NodeListObj *nodeListChunkRest(EvalContext &, Interpreter &, bool &);
  50. private:
  51. NodePtr first_;
  52. NodePtr end_;
  53. };
  54. class SelectByClassNodeListObj : public NodeListObj {
  55. public:
  56. SelectByClassNodeListObj(NodeListObj *nl, ComponentName::Id);
  57. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  58. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  59. NodeListObj *nodeListChunkRest(EvalContext &, Interpreter &, bool &);
  60. void traceSubObjects(Collector &) const;
  61. private:
  62. NodeListObj *nodeList_;
  63. ComponentName::Id cls_;
  64. };
  65. class MapNodeListObj : public NodeListObj {
  66. public:
  67. class Context : public Resource {
  68. public:
  69. Context(const EvalContext &, const Location &);
  70. void set(EvalContext &) const;
  71. void traceSubObjects(Collector &) const;
  72. Location loc;
  73. private:
  74. NodePtr currentNode_;
  75. const ProcessingMode *processingMode_;
  76. StyleObj *overridingStyle_;
  77. bool haveStyleStack_;
  78. };
  79. void *operator new(size_t, Collector &c) {
  80. return c.allocateObject(1);
  81. }
  82. MapNodeListObj(FunctionObj *func, NodeListObj *nl, const ConstPtr<Context> &, NodeListObj *mapped = 0);
  83. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  84. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  85. void traceSubObjects(Collector &) const;
  86. bool suppressError();
  87. private:
  88. void mapNext(EvalContext &, Interpreter &);
  89. FunctionObj *func_;
  90. NodeListObj *nl_;
  91. NodeListObj *mapped_;
  92. ConstPtr<Context> context_;
  93. };
  94. class SelectElementsNodeListObj : public NodeListObj {
  95. public:
  96. struct PatternSet : public Resource, public NCVector<Pattern> { };
  97. void *operator new(size_t, Collector &c) {
  98. return c.allocateObject(1);
  99. }
  100. SelectElementsNodeListObj(NodeListObj *, NCVector<Pattern> &);
  101. SelectElementsNodeListObj(NodeListObj *, const ConstPtr<PatternSet> &);
  102. void traceSubObjects(Collector &) const;
  103. NodePtr nodeListFirst(EvalContext &, Interpreter &);
  104. NodeListObj *nodeListRest(EvalContext &, Interpreter &);
  105. private:
  106. NodeListObj *nodeList_;
  107. ConstPtr<PatternSet> patterns_;
  108. };
  109. #define PRIMITIVE(name, string, nRequired, nOptional, rest, feature) \
  110. class name ## PrimitiveObj : public PrimitiveObj { \
  111. public: \
  112. static const Signature signature_; \
  113. name ## PrimitiveObj() : PrimitiveObj(&signature_) { } \
  114. ELObj *primitiveCall(int, ELObj **, EvalContext &, Interpreter &, const Location &); \
  115. }; \
  116. const Signature name ## PrimitiveObj::signature_ \
  117. = { nRequired, nOptional, rest };
  118. #define SPRIMITIVE PRIMITIVE
  119. #define XPRIMITIVE(name, string, nRequired, nOptional, rest) \
  120. PRIMITIVE(name, string, nRequired, nOptional, rest, noFeature)
  121. #define XXPRIMITIVE XPRIMITIVE
  122. #define PRIMITIVE2 XPRIMITIVE
  123. #include "primitive.h"
  124. #undef PRIMITIVE
  125. #undef SPRIMITIVE
  126. #undef XPRIMITIVE
  127. #undef XXPRIMITIVE
  128. #undef PRIMITIVE2
  129. #define DEFPRIMITIVE(name, argc, argv, context, interp, loc) \
  130. ELObj *name ## PrimitiveObj \
  131. ::primitiveCall(int argc, ELObj **argv, EvalContext &context, Interpreter &interp, \
  132. const Location &loc)
  133. DEFPRIMITIVE(Cons, argc, argv, context, interp, loc)
  134. {
  135. return new (interp) PairObj(argv[0], argv[1]);
  136. }
  137. DEFPRIMITIVE(List, argc, argv, context, interp, loc)
  138. {
  139. if (argc == 0)
  140. return interp.makeNil();
  141. PairObj *head = new (interp) PairObj(argv[0], 0);
  142. ELObjDynamicRoot protect(interp, head);
  143. PairObj *tail = head;
  144. for (int i = 1; i < argc; i++) {
  145. PairObj *tem = new (interp) PairObj(argv[i], 0);
  146. tail->setCdr(tem);
  147. tail = tem;
  148. }
  149. tail->setCdr(interp.makeNil());
  150. return head;
  151. }
  152. DEFPRIMITIVE(IsNull, argc, argv, context, interp, loc)
  153. {
  154. if (argv[0]->isNil())
  155. return interp.makeTrue();
  156. else
  157. return interp.makeFalse();
  158. }
  159. DEFPRIMITIVE(IsList, argc, argv, context, interp, loc)
  160. {
  161. ELObj *obj = argv[0];
  162. for (;;) {
  163. PairObj *pair = obj->asPair();
  164. if (pair)
  165. obj = pair->cdr();
  166. else if (obj->isNil())
  167. return interp.makeTrue();
  168. else
  169. break;
  170. }
  171. return interp.makeFalse();
  172. }
  173. DEFPRIMITIVE(IsEqual, argc, argv, context, interp, loc)
  174. {
  175. if (ELObj::equal(*argv[0], *argv[1]))
  176. return interp.makeTrue();
  177. else
  178. return interp.makeFalse();
  179. }
  180. DEFPRIMITIVE(IsEqv, argc, argv, context, interp, loc)
  181. {
  182. if (ELObj::eqv(*argv[0], *argv[1]))
  183. return interp.makeTrue();
  184. else
  185. return interp.makeFalse();
  186. }
  187. DEFPRIMITIVE(Car, argc, argv, context, interp, loc)
  188. {
  189. PairObj *pair = argv[0]->asPair();
  190. if (!pair)
  191. return argError(interp, loc,
  192. InterpreterMessages::notAPair, 0, argv[0]);
  193. else
  194. return pair->car();
  195. }
  196. DEFPRIMITIVE(Cdr, argc, argv, context, interp, loc)
  197. {
  198. PairObj *pair = argv[0]->asPair();
  199. if (!pair)
  200. return argError(interp, loc,
  201. InterpreterMessages::notAPair, 0, argv[0]);
  202. else
  203. return pair->cdr();
  204. }
  205. DEFPRIMITIVE(Append, argc, argv, context, interp, loc)
  206. {
  207. if (argc == 0)
  208. return interp.makeNil();
  209. PairObj *tail = interp.makePair(0, 0);
  210. PairObj *head = tail;
  211. ELObjDynamicRoot protect(interp, head);
  212. for (int i = 0; i < argc - 1; i++) {
  213. for (ELObj *p = argv[i]; !p->isNil();) {
  214. PairObj *tem = p->asPair();
  215. if (!tem)
  216. return argError(interp, loc,
  217. InterpreterMessages::notAList, i, p);
  218. PairObj *newTail = new (interp) PairObj(tem->car(), 0);
  219. tail->setCdr(newTail);
  220. tail = newTail;
  221. p = tem->cdr();
  222. }
  223. }
  224. tail->setCdr(argv[argc - 1]);
  225. return head->cdr();
  226. }
  227. DEFPRIMITIVE(Reverse, argc, argv, context, interp, loc)
  228. {
  229. ELObjDynamicRoot protect(interp, interp.makeNil());
  230. ELObj *p = argv[0];
  231. while (!p->isNil()) {
  232. PairObj *tem = p->asPair();
  233. if (!tem)
  234. return argError(interp, loc,
  235. InterpreterMessages::notAList, 0, argv[0]);
  236. protect = new (interp) PairObj(tem->car(), protect);
  237. p = tem->cdr();
  238. }
  239. return protect;
  240. }
  241. DEFPRIMITIVE(ListTail, argc, argv, context, interp, loc)
  242. {
  243. long k;
  244. if (!argv[1]->exactIntegerValue(k))
  245. return argError(interp, loc,
  246. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  247. if (k < 0) {
  248. interp.setNextLocation(loc);
  249. interp.message(InterpreterMessages::outOfRange);
  250. return interp.makeError();
  251. }
  252. ELObj *p = argv[0];
  253. for (; k > 0; k--) {
  254. PairObj *tem = p->asPair();
  255. if (!tem) {
  256. if (p->isNil()) {
  257. interp.setNextLocation(loc);
  258. interp.message(InterpreterMessages::outOfRange);
  259. return interp.makeError();
  260. }
  261. else
  262. return argError(interp, loc,
  263. InterpreterMessages::notAList, 0, argv[0]);
  264. }
  265. p = tem->cdr();
  266. }
  267. return p;
  268. }
  269. DEFPRIMITIVE(ListRef, argc, argv, context, interp, loc)
  270. {
  271. long k;
  272. if (!argv[1]->exactIntegerValue(k))
  273. return argError(interp, loc,
  274. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  275. if (k < 0) {
  276. interp.setNextLocation(loc);
  277. interp.message(InterpreterMessages::outOfRange);
  278. return interp.makeError();
  279. }
  280. ELObj *p = argv[0];
  281. for (;;) {
  282. PairObj *tem = p->asPair();
  283. if (!tem)
  284. break;
  285. if (k == 0)
  286. return tem->car();
  287. --k;
  288. p = tem->cdr();
  289. }
  290. if (p->isNil()) {
  291. interp.setNextLocation(loc);
  292. interp.message(InterpreterMessages::outOfRange);
  293. return interp.makeError();
  294. }
  295. else
  296. return argError(interp, loc,
  297. InterpreterMessages::notAList, 0, argv[0]);
  298. }
  299. DEFPRIMITIVE(Member, argc, argv, context, interp, loc)
  300. {
  301. ELObj *p = argv[1];
  302. while (!p->isNil()) {
  303. PairObj *tem = p->asPair();
  304. if (!tem)
  305. return argError(interp, loc,
  306. InterpreterMessages::notAList, 1, argv[1]);
  307. if (ELObj::equal(*argv[0], *tem->car()))
  308. return p;
  309. p = tem->cdr();
  310. }
  311. return interp.makeFalse();
  312. }
  313. DEFPRIMITIVE(Memv, argc, argv, context, interp, loc)
  314. {
  315. ELObj *p = argv[1];
  316. while (!p->isNil()) {
  317. PairObj *tem = p->asPair();
  318. if (!tem)
  319. return argError(interp, loc,
  320. InterpreterMessages::notAList, 1, argv[1]);
  321. if (ELObj::eqv(*argv[0], *tem->car()))
  322. return p;
  323. p = tem->cdr();
  324. }
  325. return interp.makeFalse();
  326. }
  327. DEFPRIMITIVE(Length, argc, argv, context, interp, loc)
  328. {
  329. ELObj *obj = argv[0];
  330. long n = 0;
  331. for (;;) {
  332. PairObj *pair = obj->asPair();
  333. if (pair) {
  334. n++;
  335. obj = pair->cdr();
  336. }
  337. else if (obj->isNil())
  338. break;
  339. else if (interp.isError(obj))
  340. return obj;
  341. else
  342. return argError(interp, loc,
  343. InterpreterMessages::notAList, 0, obj);
  344. }
  345. return interp.makeInteger(n);
  346. }
  347. DEFPRIMITIVE(Not, argc, argv, context, interp, loc)
  348. {
  349. if (argv[0]->isTrue())
  350. return interp.makeFalse();
  351. else
  352. return interp.makeTrue();
  353. }
  354. DEFPRIMITIVE(IsSymbol, argc, argv, context, interp, loc)
  355. {
  356. if (argv[0]->asSymbol())
  357. return interp.makeTrue();
  358. else
  359. return interp.makeFalse();
  360. }
  361. DEFPRIMITIVE(IsKeyword, argc, argv, context, interp, loc)
  362. {
  363. if (argv[0]->asKeyword())
  364. return interp.makeTrue();
  365. else
  366. return interp.makeFalse();
  367. }
  368. DEFPRIMITIVE(IsInteger, argc, argv, context, interp, loc)
  369. {
  370. long n;
  371. if (argv[0]->exactIntegerValue(n))
  372. return interp.makeTrue();
  373. double x;
  374. if (argv[0]->realValue(x) && modf(x, &x) == 0.0)
  375. return interp.makeTrue();
  376. else
  377. return interp.makeFalse();
  378. }
  379. DEFPRIMITIVE(IsReal, argc, argv, context, interp, loc)
  380. {
  381. double x;
  382. if (argv[0]->realValue(x))
  383. return interp.makeTrue();
  384. else
  385. return interp.makeFalse();
  386. }
  387. DEFPRIMITIVE(IsNumber, argc, argv, context, interp, loc)
  388. {
  389. double x;
  390. if (argv[0]->realValue(x))
  391. return interp.makeTrue();
  392. else
  393. return interp.makeFalse();
  394. }
  395. DEFPRIMITIVE(IsQuantity, argc, argv, context, interp, loc)
  396. {
  397. long n;
  398. double d;
  399. int dim;
  400. if (argv[0]->quantityValue(n, d, dim) != ELObj::noQuantity)
  401. return interp.makeTrue();
  402. else
  403. return interp.makeFalse();
  404. }
  405. DEFPRIMITIVE(IsPair, argc, argv, context, interp, loc)
  406. {
  407. if (argv[0]->asPair())
  408. return interp.makeTrue();
  409. else
  410. return interp.makeFalse();
  411. }
  412. DEFPRIMITIVE(IsProcedure, argc, argv, context, interp, loc)
  413. {
  414. if (argv[0]->asFunction())
  415. return interp.makeTrue();
  416. else
  417. return interp.makeFalse();
  418. }
  419. DEFPRIMITIVE(IsBoolean, argc, argv, context, interp, loc)
  420. {
  421. if (argv[0] == interp.makeTrue())
  422. return argv[0];
  423. else if (argv[0] == interp.makeFalse())
  424. return interp.makeTrue();
  425. else
  426. return interp.makeFalse();
  427. }
  428. DEFPRIMITIVE(IsChar, argc, argv, context, interp, loc)
  429. {
  430. Char c;
  431. if (argv[0]->charValue(c))
  432. return interp.makeTrue();
  433. else
  434. return interp.makeFalse();
  435. }
  436. DEFPRIMITIVE(IsCharEqual, argc, argv, context, interp, loc)
  437. {
  438. Char c1, c2;
  439. if (!argv[0]->charValue(c1))
  440. return argError(interp, loc,
  441. InterpreterMessages::notAChar, 0, argv[0]);
  442. if (!argv[1]->charValue(c2))
  443. return argError(interp, loc,
  444. InterpreterMessages::notAChar, 1, argv[1]);
  445. if (c1 == c2)
  446. return interp.makeTrue();
  447. else
  448. return interp.makeFalse();
  449. }
  450. DEFPRIMITIVE(String, argc, argv, context, interp, loc)
  451. {
  452. StringObj *obj = new (interp) StringObj;
  453. for (int i = 0; i < argc; i++) {
  454. Char c;
  455. if (!argv[i]->charValue(c))
  456. return argError(interp, loc,
  457. InterpreterMessages::notAChar, i, argv[i]);
  458. *obj += c;
  459. }
  460. return obj;
  461. }
  462. DEFPRIMITIVE(SymbolToString, argc, argv, context, interp, loc)
  463. {
  464. SymbolObj *obj = argv[0]->asSymbol();
  465. if (!obj)
  466. return argError(interp, loc,
  467. InterpreterMessages::notASymbol, 0, argv[0]);
  468. return obj->name();
  469. }
  470. DEFPRIMITIVE(StringToSymbol, argc, argv, context, interp, loc)
  471. {
  472. const Char *s;
  473. size_t n;
  474. if (!argv[0]->stringData(s, n))
  475. return argError(interp, loc,
  476. InterpreterMessages::notAString, 0, argv[0]);
  477. return interp.makeSymbol(StringC(s, n));
  478. }
  479. DEFPRIMITIVE(IsString, argc, argv, context, interp, loc)
  480. {
  481. const Char *s;
  482. size_t n;
  483. if (argv[0]->stringData(s, n))
  484. return interp.makeTrue();
  485. else
  486. return interp.makeFalse();
  487. }
  488. DEFPRIMITIVE(StringLength, argc, argv, context, interp, loc)
  489. {
  490. const Char *s;
  491. size_t n;
  492. if (!argv[0]->stringData(s, n))
  493. return argError(interp, loc,
  494. InterpreterMessages::notAString, 0, argv[0]);
  495. return interp.makeInteger(n);
  496. }
  497. DEFPRIMITIVE(IsStringEqual, argc, argv, context, interp, loc)
  498. {
  499. const Char *s1, *s2;
  500. size_t n1, n2;
  501. if (!argv[0]->stringData(s1, n1))
  502. return argError(interp, loc,
  503. InterpreterMessages::notAString, 0, argv[0]);
  504. if (!argv[1]->stringData(s2, n2))
  505. return argError(interp, loc,
  506. InterpreterMessages::notAString, 1, argv[1]);
  507. if (n1 == n2
  508. && (n1 == 0 || memcmp(s1, s2, n1*sizeof(Char)) == 0))
  509. return interp.makeTrue();
  510. else
  511. return interp.makeFalse();
  512. }
  513. DEFPRIMITIVE(StringAppend, argc, argv, context, interp, loc)
  514. {
  515. StringObj *result = new (interp) StringObj;
  516. for (int i = 0; i < argc; i++) {
  517. const Char *s;
  518. size_t n;
  519. if (!argv[i]->stringData(s, n))
  520. return argError(interp, loc,
  521. InterpreterMessages::notAString, i,
  522. argv[i]);
  523. result->append(s, n);
  524. }
  525. return result;
  526. }
  527. DEFPRIMITIVE(StringRef, argc, argv, context, interp, loc)
  528. {
  529. const Char *s;
  530. size_t n;
  531. if (!argv[0]->stringData(s, n))
  532. return argError(interp, loc,
  533. InterpreterMessages::notAString, 0, argv[0]);
  534. long k;
  535. if (!argv[1]->exactIntegerValue(k))
  536. return argError(interp, loc,
  537. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  538. if (k < 0 || (unsigned long)k >= n) {
  539. interp.setNextLocation(loc);
  540. interp.message(InterpreterMessages::outOfRange);
  541. return interp.makeError();
  542. }
  543. return interp.makeChar(s[size_t(k)]);
  544. }
  545. DEFPRIMITIVE(Substring, argc, argv, context, interp, loc)
  546. {
  547. const Char *s;
  548. size_t n;
  549. if (!argv[0]->stringData(s, n))
  550. return argError(interp, loc,
  551. InterpreterMessages::notAString, 0, argv[0]);
  552. long start;
  553. if (!argv[1]->exactIntegerValue(start))
  554. return argError(interp, loc,
  555. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  556. long end;
  557. if (!argv[2]->exactIntegerValue(end))
  558. return argError(interp, loc,
  559. InterpreterMessages::notAnExactInteger, 2, argv[2]);
  560. if (start < 0 || (unsigned long)end > n || start > end) {
  561. interp.setNextLocation(loc);
  562. interp.message(InterpreterMessages::outOfRange);
  563. return interp.makeError();
  564. }
  565. return new (interp) StringObj(s + size_t(start), size_t(end - start));
  566. }
  567. DEFPRIMITIVE(Equal, argc, argv, context, interp, loc)
  568. {
  569. if (argc == 0)
  570. return interp.makeTrue();
  571. long lResult;
  572. double dResult;
  573. int dim;
  574. int i = 1;
  575. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  576. case ELObj::noQuantity:
  577. return argError(interp, loc,
  578. InterpreterMessages::notAQuantity, 0, argv[0]);
  579. case ELObj::longQuantity:
  580. break;
  581. case ELObj::doubleQuantity:
  582. goto useDouble;
  583. break;
  584. default:
  585. CANNOT_HAPPEN();
  586. }
  587. long lResult2;
  588. double dResult2;
  589. int dim2;
  590. for (; i < argc; i++) {
  591. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  592. case ELObj::noQuantity:
  593. return argError(interp, loc,
  594. InterpreterMessages::notAQuantity, i, argv[i]);
  595. case ELObj::longQuantity:
  596. if (lResult2 != lResult || dim2 != dim)
  597. return interp.makeFalse();
  598. break;
  599. case ELObj::doubleQuantity:
  600. dResult = lResult;
  601. if (dResult2 != dResult || dim2 != dim)
  602. return interp.makeFalse();
  603. i++;
  604. goto useDouble;
  605. default:
  606. CANNOT_HAPPEN();
  607. }
  608. }
  609. return interp.makeTrue();
  610. useDouble:
  611. for (; i < argc; i++) {
  612. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  613. case ELObj::noQuantity:
  614. return argError(interp, loc,
  615. InterpreterMessages::notAQuantity, i, argv[i]);
  616. case ELObj::longQuantity:
  617. if (lResult2 != dResult || dim2 != dim)
  618. return interp.makeFalse();
  619. break;
  620. case ELObj::doubleQuantity:
  621. if (dResult2 != dResult || dim2 != dim)
  622. return interp.makeFalse();
  623. break;
  624. }
  625. }
  626. return interp.makeTrue();
  627. }
  628. DEFPRIMITIVE(Plus, argc, argv, context, interp, loc)
  629. {
  630. if (argc == 0)
  631. return interp.makeInteger(0);
  632. long lResult;
  633. double dResult;
  634. bool usingD;
  635. bool spec = 0;
  636. int dim;
  637. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  638. case ELObj::noQuantity:
  639. dim = 1;
  640. spec = 1;
  641. break;
  642. case ELObj::longQuantity:
  643. usingD = 0;
  644. break;
  645. case ELObj::doubleQuantity:
  646. usingD = 1;
  647. break;
  648. default:
  649. CANNOT_HAPPEN();
  650. }
  651. for (int i = 1; !spec && i < argc; i++) {
  652. long lResult2;
  653. double dResult2;
  654. int dim2;
  655. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  656. case ELObj::noQuantity:
  657. // FIXME shouldn't quantityValue set dim to 1 for length-specs ?
  658. dim2 = 1;
  659. spec = 1;
  660. break;
  661. case ELObj::longQuantity:
  662. if (!usingD) {
  663. if (lResult2 < 0) {
  664. if (lResult >= LONG_MIN - lResult2) {
  665. lResult += lResult2;
  666. break;
  667. }
  668. }
  669. else {
  670. if (lResult <= LONG_MAX - lResult2) {
  671. lResult += lResult2;
  672. break;
  673. }
  674. }
  675. usingD = 1;
  676. dResult = double(lResult);
  677. }
  678. dResult += double(lResult2);
  679. break;
  680. case ELObj::doubleQuantity:
  681. if (!usingD) {
  682. dResult = lResult;
  683. usingD = 1;
  684. }
  685. dResult += dResult2;
  686. break;
  687. default:
  688. CANNOT_HAPPEN();
  689. }
  690. if (dim2 != dim) {
  691. interp.setNextLocation(loc);
  692. interp.message(InterpreterMessages::incompatibleDimensions);
  693. return interp.makeError();
  694. }
  695. }
  696. if (spec) {
  697. LengthSpec ls;
  698. for (int i = 0; i < argc; i++) {
  699. const LengthSpec *lsp = argv[i]->lengthSpec();
  700. if (lsp)
  701. ls += *lsp;
  702. else {
  703. switch (argv[i]->quantityValue(lResult, dResult, dim)) {
  704. case ELObj::noQuantity:
  705. return argError(interp, loc, InterpreterMessages::notAQuantityOrLengthSpec,
  706. i, argv[i]);
  707. case ELObj::longQuantity:
  708. dResult = lResult;
  709. // fall through
  710. case ELObj::doubleQuantity:
  711. if (dim != 1) {
  712. interp.setNextLocation(loc);
  713. interp.message(InterpreterMessages::incompatibleDimensions);
  714. return interp.makeError();
  715. }
  716. ls += dResult;
  717. break;
  718. }
  719. }
  720. }
  721. return new (interp) LengthSpecObj(ls);
  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. bool spec = 0;
  742. int dim;
  743. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  744. case ELObj::noQuantity:
  745. spec = 1;
  746. break;
  747. case ELObj::longQuantity:
  748. usingD = 0;
  749. break;
  750. case ELObj::doubleQuantity:
  751. usingD = 1;
  752. break;
  753. default:
  754. CANNOT_HAPPEN();
  755. }
  756. if (argc == 1) {
  757. if (usingD)
  758. dResult = -dResult;
  759. else
  760. lResult = -lResult;
  761. }
  762. else {
  763. for (int i = 1; !spec && i < argc; i++) {
  764. long lResult2;
  765. double dResult2;
  766. int dim2;
  767. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  768. case ELObj::noQuantity:
  769. dim2 = dim;
  770. spec = 1;
  771. break;
  772. case ELObj::longQuantity:
  773. if (!usingD) {
  774. if (lResult2 > 0) {
  775. if (lResult >= LONG_MIN + lResult2) {
  776. lResult -= lResult2;
  777. break;
  778. }
  779. }
  780. else {
  781. if (lResult <= LONG_MAX + lResult2) {
  782. lResult -= lResult2;
  783. break;
  784. }
  785. }
  786. usingD = 1;
  787. dResult = double(lResult);
  788. }
  789. dResult -= double(lResult2);
  790. break;
  791. case ELObj::doubleQuantity:
  792. if (!usingD) {
  793. dResult = lResult;
  794. usingD = 1;
  795. }
  796. dResult -= dResult2;
  797. break;
  798. default:
  799. CANNOT_HAPPEN();
  800. }
  801. if (dim2 != dim) {
  802. interp.setNextLocation(loc);
  803. interp.message(InterpreterMessages::incompatibleDimensions);
  804. return interp.makeError();
  805. }
  806. }
  807. }
  808. if (spec) {
  809. LengthSpec ls;
  810. for (int i = 0; i < argc; i++) {
  811. const LengthSpec *lsp = argv[i]->lengthSpec();
  812. if (lsp) {
  813. if (i > 0 || argc == 1)
  814. ls -= *lsp;
  815. else
  816. ls += *lsp;
  817. }
  818. else {
  819. switch (argv[i]->quantityValue(lResult, dResult, dim)) {
  820. case ELObj::noQuantity:
  821. return argError(interp, loc, InterpreterMessages::notAQuantityOrLengthSpec,
  822. i, argv[i]);
  823. case ELObj::longQuantity:
  824. dResult = lResult;
  825. // fall through
  826. case ELObj::doubleQuantity:
  827. if (dim != 1) {
  828. interp.setNextLocation(loc);
  829. interp.message(InterpreterMessages::incompatibleDimensions);
  830. return interp.makeError();
  831. }
  832. if (i > 0 || argc == 1)
  833. ls -= dResult;
  834. else
  835. ls += dResult;
  836. break;
  837. }
  838. }
  839. }
  840. return new (interp) LengthSpecObj(ls);
  841. }
  842. if (!usingD) {
  843. if (dim == 0)
  844. return interp.makeInteger(lResult);
  845. else if (dim == 1)
  846. return new (interp) LengthObj(lResult);
  847. else
  848. dResult = lResult;
  849. }
  850. if (dim == 0)
  851. return new (interp) RealObj(dResult);
  852. else
  853. return new (interp) QuantityObj(dResult, dim);
  854. }
  855. DEFPRIMITIVE(Multiply, argc, argv, context, interp, loc)
  856. {
  857. if (argc == 0)
  858. return interp.makeInteger(1);
  859. long lResult;
  860. double dResult;
  861. int dim;
  862. int i = 1;
  863. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  864. case ELObj::noQuantity:
  865. {
  866. const LengthSpec *ls = argv[0]->lengthSpec();
  867. if (ls) {
  868. LengthSpec result(*ls);
  869. double d;
  870. for (; i < argc; i++) {
  871. if (!argv[i]->realValue(d))
  872. return argError(interp, loc,
  873. InterpreterMessages::notANumber, 1, argv[1]);
  874. result *= d;
  875. }
  876. return new (interp) LengthSpecObj(result);
  877. }
  878. }
  879. return argError(interp, loc,
  880. InterpreterMessages::notAQuantity, 0, argv[0]);
  881. case ELObj::longQuantity:
  882. break;
  883. case ELObj::doubleQuantity:
  884. goto useDouble;
  885. default:
  886. CANNOT_HAPPEN();
  887. }
  888. long lResult2;
  889. double dResult2;
  890. int dim2;
  891. for (; i < argc; i++) {
  892. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  893. case ELObj::noQuantity:
  894. return argError(interp, loc,
  895. InterpreterMessages::notAQuantity, i, argv[i]);
  896. case ELObj::longQuantity:
  897. dim += dim2;
  898. if (dim > 1
  899. || (lResult2 != 0
  900. && (lResult2 < 0
  901. ? (lResult > 0
  902. ? lResult > -(unsigned)LONG_MIN / -(unsigned)lResult2
  903. : -(unsigned)lResult > LONG_MAX / -(unsigned)lResult2)
  904. : (lResult > 0
  905. ? lResult > LONG_MAX / lResult2
  906. : -(unsigned)lResult > -(unsigned)LONG_MIN / lResult2)))) {
  907. dResult = double(lResult) * lResult2;
  908. i++;
  909. goto useDouble;
  910. }
  911. lResult *= lResult2;
  912. break;
  913. case ELObj::doubleQuantity:
  914. dim += dim2;
  915. dResult = lResult * dResult2;
  916. i++;
  917. goto useDouble;
  918. default:
  919. CANNOT_HAPPEN();
  920. }
  921. }
  922. if (dim == 0)
  923. return interp.makeInteger(lResult);
  924. else
  925. return new (interp) LengthObj(lResult);
  926. useDouble:
  927. for (; i < argc; i++) {
  928. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  929. case ELObj::noQuantity:
  930. return argError(interp, loc,
  931. InterpreterMessages::notAQuantity, i, argv[i]);
  932. case ELObj::longQuantity:
  933. dResult *= lResult2;
  934. break;
  935. case ELObj::doubleQuantity:
  936. dResult *= dResult2;
  937. break;
  938. }
  939. dim += dim2;
  940. }
  941. if (dim == 0)
  942. return new (interp) RealObj(dResult);
  943. else
  944. return new (interp) QuantityObj(dResult, dim);
  945. }
  946. DEFPRIMITIVE(Divide, argc, argv, context, interp, loc)
  947. {
  948. long lResult;
  949. double dResult;
  950. int dim;
  951. if (argc == 1) {
  952. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  953. case ELObj::noQuantity:
  954. return argError(interp, loc,
  955. InterpreterMessages::notAQuantity, 0, argv[0]);
  956. case ELObj::longQuantity:
  957. if (lResult == 0)
  958. goto divide0;
  959. dResult = 1.0/lResult;
  960. break;
  961. case ELObj::doubleQuantity:
  962. if (dResult == 0.0)
  963. goto divide0;
  964. dResult = 1.0/dResult;
  965. break;
  966. default:
  967. CANNOT_HAPPEN();
  968. }
  969. dim = -dim;
  970. }
  971. else {
  972. int i = 1;
  973. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  974. case ELObj::noQuantity:
  975. {
  976. const LengthSpec *ls = argv[0]->lengthSpec();
  977. if (ls) {
  978. LengthSpec result(*ls);
  979. double d;
  980. for (; i < argc; i++) {
  981. if (!argv[i]->realValue(d))
  982. return argError(interp, loc,
  983. InterpreterMessages::notANumber, 1, argv[1]);
  984. if (d == 0.0)
  985. goto divide0;
  986. result /= d;
  987. }
  988. return new (interp) LengthSpecObj(result);
  989. }
  990. }
  991. return argError(interp, loc,
  992. InterpreterMessages::notAQuantity, 0, argv[0]);
  993. case ELObj::longQuantity:
  994. break;
  995. case ELObj::doubleQuantity:
  996. goto useDouble;
  997. default:
  998. CANNOT_HAPPEN();
  999. }
  1000. long lResult2;
  1001. double dResult2;
  1002. int dim2;
  1003. for (; i < argc; i++) {
  1004. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1005. case ELObj::noQuantity:
  1006. return argError(interp, loc,
  1007. InterpreterMessages::notAQuantity, 0, argv[0]);
  1008. case ELObj::longQuantity:
  1009. if (lResult2 == 0)
  1010. goto divide0;
  1011. dim -= dim2;
  1012. // If dim and dim2 are both 1, must goto useDouble:
  1013. // since lengths are inexact, result must be inexact.
  1014. if (dim2 == 0 && lResult % lResult2 == 0) {
  1015. lResult /= lResult2;
  1016. break;
  1017. }
  1018. dResult = double(lResult)/lResult2;
  1019. i++;
  1020. goto useDouble;
  1021. case ELObj::doubleQuantity:
  1022. dim -= dim2;
  1023. dResult = lResult;
  1024. if (dResult2 == 0.0)
  1025. goto divide0;
  1026. dResult /= dResult2;
  1027. i++;
  1028. goto useDouble;
  1029. default:
  1030. CANNOT_HAPPEN();
  1031. }
  1032. }
  1033. if (dim == 0)
  1034. return interp.makeInteger(lResult);
  1035. else
  1036. return new (interp) LengthObj(lResult);
  1037. useDouble:
  1038. for (; i < argc; i++) {
  1039. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1040. case ELObj::noQuantity:
  1041. return argError(interp, loc,
  1042. InterpreterMessages::notAQuantity, i, argv[i]);
  1043. case ELObj::longQuantity:
  1044. if (lResult2 == 0)
  1045. goto divide0;
  1046. dResult /= lResult2;
  1047. break;
  1048. case ELObj::doubleQuantity:
  1049. dResult /= dResult2;
  1050. if (dResult2 == 0.0)
  1051. goto divide0;
  1052. break;
  1053. }
  1054. dim -= dim2;
  1055. }
  1056. }
  1057. if (dim == 0)
  1058. return new (interp) RealObj(dResult);
  1059. else
  1060. return new (interp) QuantityObj(dResult, dim);
  1061. divide0:
  1062. interp.setNextLocation(loc);
  1063. interp.message(InterpreterMessages::divideBy0);
  1064. return interp.makeError();
  1065. }
  1066. DEFPRIMITIVE(Quotient, argc, argv, context, interp, loc)
  1067. {
  1068. long n1;
  1069. long n2;
  1070. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1071. if (n2 == 0) {
  1072. interp.setNextLocation(loc);
  1073. interp.message(InterpreterMessages::divideBy0);
  1074. return interp.makeError();
  1075. }
  1076. // This isn't strictly portable.
  1077. return interp.makeInteger(n1 / n2);
  1078. }
  1079. double d1;
  1080. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1081. return argError(interp, loc,
  1082. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1083. double d2;
  1084. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1085. return argError(interp, loc,
  1086. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1087. if (d2 == 0.0) {
  1088. interp.setNextLocation(loc);
  1089. interp.message(InterpreterMessages::divideBy0);
  1090. return interp.makeError();
  1091. }
  1092. return new (interp) RealObj((d1 - fmod(d1, d2))/d2);
  1093. }
  1094. DEFPRIMITIVE(Remainder, argc, argv, context, interp, loc)
  1095. {
  1096. long n1;
  1097. long n2;
  1098. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1099. if (n2 == 0) {
  1100. interp.setNextLocation(loc);
  1101. interp.message(InterpreterMessages::divideBy0);
  1102. return interp.makeError();
  1103. }
  1104. // This isn't strictly portable.
  1105. return interp.makeInteger(n1 % n2);
  1106. }
  1107. double d1;
  1108. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1109. return argError(interp, loc,
  1110. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1111. double d2;
  1112. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1113. return argError(interp, loc,
  1114. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1115. if (d2 == 0.0) {
  1116. interp.setNextLocation(loc);
  1117. interp.message(InterpreterMessages::divideBy0);
  1118. return interp.makeError();
  1119. }
  1120. return new (interp) RealObj(fmod(d1, d2));
  1121. }
  1122. DEFPRIMITIVE(Modulo, argc, argv, context, interp, loc)
  1123. {
  1124. long n1;
  1125. long n2;
  1126. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1127. if (n2 == 0) {
  1128. interp.setNextLocation(loc);
  1129. interp.message(InterpreterMessages::divideBy0);
  1130. return interp.makeError();
  1131. }
  1132. long r = n1 % n2;
  1133. if (n2 > 0 ? r < 0 : r > 0)
  1134. r += n2;
  1135. return interp.makeInteger(r);
  1136. }
  1137. double d1;
  1138. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1139. return argError(interp, loc,
  1140. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1141. double d2;
  1142. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1143. return argError(interp, loc,
  1144. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1145. if (d2 == 0.0) {
  1146. interp.setNextLocation(loc);
  1147. interp.message(InterpreterMessages::divideBy0);
  1148. return interp.makeError();
  1149. }
  1150. double r = fmod(d1, d2);
  1151. if (d2 > 0 ? r < 0 : r > 0)
  1152. r += d2;
  1153. return new (interp) RealObj(r);
  1154. }
  1155. #define DEFCOMPARE(NAME, OP) \
  1156. DEFPRIMITIVE(NAME, argc, argv, context, interp, loc) \
  1157. { \
  1158. if (argc == 0) \
  1159. return interp.makeTrue(); \
  1160. long lResult; \
  1161. double dResult; \
  1162. int dim; \
  1163. bool lastWasDouble; \
  1164. switch (argv[0]->quantityValue(lResult, dResult, dim)) { \
  1165. case ELObj::noQuantity: \
  1166. return argError(interp, loc, \
  1167. InterpreterMessages::notAQuantity, 0, argv[0]); \
  1168. case ELObj::longQuantity: \
  1169. lastWasDouble = 0; \
  1170. break; \
  1171. case ELObj::doubleQuantity: \
  1172. lastWasDouble = 1; \
  1173. break; \
  1174. default: \
  1175. CANNOT_HAPPEN(); \
  1176. } \
  1177. for (int i = 1; i < argc; i++) { \
  1178. long lResult2; \
  1179. double dResult2; \
  1180. int dim2; \
  1181. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) { \
  1182. case ELObj::noQuantity: \
  1183. return argError(interp, loc, \
  1184. InterpreterMessages::notAQuantity, i, argv[i]); \
  1185. case ELObj::longQuantity: \
  1186. if (dim2 != dim) \
  1187. goto badDim; \
  1188. if (!(lastWasDouble \
  1189. ? (dResult OP lResult2) \
  1190. : (lResult OP lResult2))) \
  1191. return interp.makeFalse(); \
  1192. lResult = lResult2; \
  1193. lastWasDouble = 0; \
  1194. break; \
  1195. case ELObj::doubleQuantity: \
  1196. if (dim != dim2) \
  1197. goto badDim; \
  1198. if (!(lastWasDouble \
  1199. ? (dResult OP dResult2) \
  1200. : (lResult OP dResult2))) \
  1201. return interp.makeFalse(); \
  1202. dResult = dResult2; \
  1203. lastWasDouble = 1; \
  1204. break; \
  1205. } \
  1206. } \
  1207. return interp.makeTrue(); \
  1208. badDim: \
  1209. interp.setNextLocation(loc); \
  1210. interp.message(InterpreterMessages::incompatibleDimensions); \
  1211. return interp.makeError(); \
  1212. }
  1213. DEFCOMPARE(Less, <)
  1214. DEFCOMPARE(Greater, >)
  1215. DEFCOMPARE(LessEqual, <=)
  1216. DEFCOMPARE(GreaterEqual, >=)
  1217. DEFPRIMITIVE(Min, argc, argv, context, interp, loc)
  1218. {
  1219. long lResult;
  1220. double dResult;
  1221. int dim;
  1222. int i = 1;
  1223. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1224. case ELObj::noQuantity:
  1225. return argError(interp, loc,
  1226. InterpreterMessages::notAQuantity, 0, argv[0]);
  1227. case ELObj::longQuantity:
  1228. break;
  1229. case ELObj::doubleQuantity:
  1230. goto useDouble;
  1231. default:
  1232. CANNOT_HAPPEN();
  1233. }
  1234. // Note that result is inexact if any of the arguments are
  1235. for (; i < argc; i++) {
  1236. long lResult2;
  1237. double dResult2;
  1238. int dim2;
  1239. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1240. case ELObj::noQuantity:
  1241. return argError(interp, loc,
  1242. InterpreterMessages::notAQuantity, i, argv[i]);
  1243. case ELObj::longQuantity:
  1244. if (dim2 != dim)
  1245. goto badDim;
  1246. if (lResult2 < lResult)
  1247. lResult = lResult2;
  1248. break;
  1249. case ELObj::doubleQuantity:
  1250. if (dim != dim2)
  1251. goto badDim;
  1252. if (dResult2 < lResult)
  1253. dResult = dResult2;
  1254. else if (dim)
  1255. break;
  1256. else
  1257. dResult = lResult;
  1258. i++;
  1259. goto useDouble;
  1260. }
  1261. }
  1262. if (dim == 0)
  1263. return interp.makeInteger(lResult);
  1264. else
  1265. return new (interp) LengthObj(lResult);
  1266. useDouble:
  1267. for (; i < argc; i++) {
  1268. long lResult2;
  1269. double dResult2;
  1270. int dim2;
  1271. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1272. case ELObj::noQuantity:
  1273. return argError(interp, loc,
  1274. InterpreterMessages::notAQuantity, i, argv[i]);
  1275. case ELObj::longQuantity:
  1276. if (dim2 != dim)
  1277. goto badDim;
  1278. if (lResult2 < dResult)
  1279. dResult = lResult2;
  1280. break;
  1281. case ELObj::doubleQuantity:
  1282. if (dim != dim2)
  1283. goto badDim;
  1284. if (dResult2 < dResult)
  1285. dResult = dResult2;
  1286. break;
  1287. }
  1288. }
  1289. if (dim == 0)
  1290. return new (interp) RealObj(dResult);
  1291. else
  1292. return new (interp) QuantityObj(dResult, dim);
  1293. badDim:
  1294. interp.setNextLocation(loc);
  1295. interp.message(InterpreterMessages::incompatibleDimensions);
  1296. return interp.makeError();
  1297. }
  1298. DEFPRIMITIVE(Max, argc, argv, context, interp, loc)
  1299. {
  1300. long lResult;
  1301. double dResult;
  1302. int dim;
  1303. int i = 1;
  1304. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1305. case ELObj::noQuantity:
  1306. return argError(interp, loc,
  1307. InterpreterMessages::notAQuantity, 0, argv[0]);
  1308. case ELObj::longQuantity:
  1309. break;
  1310. case ELObj::doubleQuantity:
  1311. goto useDouble;
  1312. default:
  1313. CANNOT_HAPPEN();
  1314. }
  1315. // Note that result is inexact if any of the arguments are
  1316. for (; i < argc; i++) {
  1317. long lResult2;
  1318. double dResult2;
  1319. int dim2;
  1320. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1321. case ELObj::noQuantity:
  1322. return argError(interp, loc,
  1323. InterpreterMessages::notAQuantity, i, argv[i]);
  1324. case ELObj::longQuantity:
  1325. if (dim2 != dim)
  1326. goto badDim;
  1327. if (lResult2 > lResult)
  1328. lResult = lResult2;
  1329. break;
  1330. case ELObj::doubleQuantity:
  1331. if (dim != dim2)
  1332. goto badDim;
  1333. if (dResult2 > lResult)
  1334. dResult = dResult2;
  1335. else if (dim)
  1336. break;
  1337. else
  1338. dResult = lResult;
  1339. i++;
  1340. goto useDouble;
  1341. }
  1342. }
  1343. if (dim == 0)
  1344. return interp.makeInteger(lResult);
  1345. else
  1346. return new (interp) LengthObj(lResult);
  1347. useDouble:
  1348. for (; i < argc; i++) {
  1349. long lResult2;
  1350. double dResult2;
  1351. int dim2;
  1352. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1353. case ELObj::noQuantity:
  1354. return argError(interp, loc,
  1355. InterpreterMessages::notAQuantity, i, argv[i]);
  1356. case ELObj::longQuantity:
  1357. if (dim2 != dim)
  1358. goto badDim;
  1359. if (lResult2 > dResult)
  1360. dResult = lResult2;
  1361. break;
  1362. case ELObj::doubleQuantity:
  1363. if (dim != dim2)
  1364. goto badDim;
  1365. if (dResult2 > dResult)
  1366. dResult = dResult2;
  1367. break;
  1368. }
  1369. }
  1370. if (dim == 0)
  1371. return new (interp) RealObj(dResult);
  1372. else
  1373. return new (interp) QuantityObj(dResult, dim);
  1374. badDim:
  1375. interp.setNextLocation(loc);
  1376. interp.message(InterpreterMessages::incompatibleDimensions);
  1377. return interp.makeError();
  1378. }
  1379. DEFPRIMITIVE(Floor, argc, argv, context, interp, loc)
  1380. {
  1381. double d;
  1382. if (argv[0]->inexactRealValue(d))
  1383. return new (interp) RealObj(floor(d));
  1384. long n;
  1385. if (argv[0]->exactIntegerValue(n))
  1386. return argv[0];
  1387. return argError(interp, loc,
  1388. InterpreterMessages::notANumber, 0, argv[0]);
  1389. }
  1390. DEFPRIMITIVE(Ceiling, argc, argv, context, interp, loc)
  1391. {
  1392. double d;
  1393. if (argv[0]->inexactRealValue(d))
  1394. return new (interp) RealObj(ceil(d));
  1395. long n;
  1396. if (argv[0]->exactIntegerValue(n))
  1397. return argv[0];
  1398. return argError(interp, loc,
  1399. InterpreterMessages::notANumber, 0, argv[0]);
  1400. }
  1401. DEFPRIMITIVE(Round, argc, argv, context, interp, loc)
  1402. {
  1403. double d;
  1404. if (argv[0]->inexactRealValue(d)) {
  1405. double result = floor(d + .5);
  1406. // That rounded it upwards.
  1407. // Now figure out if that was different from round to
  1408. // even.
  1409. if (result - d == 0.5 && fmod(result, 2.0) != 0)
  1410. result -= 1.0;
  1411. return new (interp) RealObj(result);
  1412. }
  1413. long n;
  1414. if (argv[0]->exactIntegerValue(n))
  1415. return argv[0];
  1416. return argError(interp, loc,
  1417. InterpreterMessages::notANumber, 0, argv[0]);
  1418. }
  1419. DEFPRIMITIVE(Truncate, argc, argv, context, interp, loc)
  1420. {
  1421. double d;
  1422. if (argv[0]->inexactRealValue(d)) {
  1423. double iPart;
  1424. modf(d, &iPart);
  1425. return new (interp) RealObj(iPart);
  1426. }
  1427. long n;
  1428. if (argv[0]->exactIntegerValue(n))
  1429. return argv[0];
  1430. return argError(interp, loc,
  1431. InterpreterMessages::notANumber, 0, argv[0]);
  1432. }
  1433. DEFPRIMITIVE(Abs, argc, argv, context, interp, loc)
  1434. {
  1435. long lResult;
  1436. double dResult;
  1437. int dim;
  1438. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1439. case ELObj::noQuantity:
  1440. return argError(interp, loc,
  1441. InterpreterMessages::notAQuantity, 0, argv[0]);
  1442. case ELObj::longQuantity:
  1443. if (lResult != LONG_MIN) {
  1444. if (lResult >= 0)
  1445. return argv[0];
  1446. if (dim == 0)
  1447. return interp.makeInteger(-lResult);
  1448. else
  1449. return new (interp) LengthObj(-lResult);
  1450. }
  1451. dResult = lResult;
  1452. break;
  1453. case ELObj::doubleQuantity:
  1454. break;
  1455. default:
  1456. CANNOT_HAPPEN();
  1457. }
  1458. if (dResult >= 0)
  1459. return argv[0];
  1460. if (dim == 0)
  1461. return new (interp) RealObj(-dResult);
  1462. else
  1463. return new (interp) QuantityObj(-dResult, dim);
  1464. }
  1465. DEFPRIMITIVE(Sqrt, argc, argv, context, interp, loc)
  1466. {
  1467. long lResult;
  1468. double dResult;
  1469. int dim;
  1470. ELObj::QuantityType type
  1471. = argv[0]->quantityValue(lResult, dResult, dim);
  1472. switch (type) {
  1473. case ELObj::noQuantity:
  1474. return argError(interp, loc,
  1475. InterpreterMessages::notAQuantity, 0, argv[0]);
  1476. case ELObj::longQuantity:
  1477. dResult = lResult;
  1478. break;
  1479. case ELObj::doubleQuantity:
  1480. break;
  1481. default:
  1482. CANNOT_HAPPEN();
  1483. }
  1484. if ((dim & 1) || dResult < 0.0) {
  1485. interp.setNextLocation(loc);
  1486. interp.message(InterpreterMessages::outOfRange);
  1487. return interp.makeError();
  1488. }
  1489. dim /= 2;
  1490. dResult = sqrt(dResult);
  1491. if (type == ELObj::longQuantity && dim == 0) {
  1492. long n = long(dResult);
  1493. if (n*n == lResult)
  1494. return interp.makeInteger(n);
  1495. }
  1496. return new (interp) QuantityObj(dResult, dim);
  1497. }
  1498. DEFPRIMITIVE(Time, argc, argv, context, interp, loc)
  1499. {
  1500. // This assumes a Posix compatible time().
  1501. time_t t = time(0);
  1502. return interp.makeInteger(long(t));
  1503. }
  1504. DEFPRIMITIVE(TimeToString, argc, argv, context, interp, loc)
  1505. {
  1506. long k;
  1507. if (!argv[0]->exactIntegerValue(k))
  1508. return argError(interp, loc,
  1509. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1510. time_t t = time_t(k);
  1511. const struct tm *p;
  1512. if (argc > 1 && argv[1] != interp.makeFalse())
  1513. p = gmtime(&t);
  1514. else
  1515. p = localtime(&t);
  1516. char buf[64];
  1517. sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d",
  1518. p->tm_year + 1900, p->tm_mon + 1, p->tm_mday,
  1519. p->tm_hour, p->tm_min, p->tm_sec);
  1520. return new (interp) StringObj(interp.makeStringC(buf));
  1521. }
  1522. DEFPRIMITIVE(CharProperty, argc, argv, context, interp, loc)
  1523. {
  1524. SymbolObj *sym = argv[0]->asSymbol();
  1525. if (!sym)
  1526. return argError(interp, loc,
  1527. InterpreterMessages::notASymbol, 0, argv[0]);
  1528. StringObj *prop = argv[0]->asSymbol()->convertToString();
  1529. Char c;
  1530. if (!argv[1]->charValue(c))
  1531. return argError(interp, loc,
  1532. InterpreterMessages::notAChar, 1, argv[1]);
  1533. return interp.lookupCharProperty(*prop)->
  1534. value(c, (argc > 2) ? argv[2] : 0, loc, interp);
  1535. }
  1536. DEFPRIMITIVE(Literal, argc, argv, context, interp, loc)
  1537. {
  1538. if (argc == 0)
  1539. return new (interp) EmptySosofoObj;
  1540. const Char *s;
  1541. size_t n;
  1542. if (!argv[0]->stringData(s, n))
  1543. return argError(interp, loc, InterpreterMessages::notAString,
  1544. 0, argv[0]);
  1545. if (argc == 1)
  1546. return new (interp) LiteralSosofoObj(argv[0], loc);
  1547. StringObj *strObj = new (interp) StringObj(s, n);
  1548. for (int i = 1; i < argc; i++) {
  1549. if (!argv[i]->stringData(s, n))
  1550. return argError(interp, loc, InterpreterMessages::notAString,
  1551. i, argv[i]);
  1552. strObj->append(s, n);
  1553. }
  1554. ELObjDynamicRoot protect(interp, strObj);
  1555. return new (interp) LiteralSosofoObj(strObj, loc);
  1556. }
  1557. DEFPRIMITIVE(ProcessChildren, argc, argv, context, interp, loc)
  1558. {
  1559. if (!context.processingMode) {
  1560. interp.setNextLocation(loc);
  1561. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1562. return interp.makeError();
  1563. }
  1564. return new (interp) ProcessChildrenSosofoObj(context.processingMode, loc);
  1565. }
  1566. DEFPRIMITIVE(ProcessChildrenTrim, argc, argv, context, interp, loc)
  1567. {
  1568. if (!context.processingMode) {
  1569. interp.setNextLocation(loc);
  1570. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1571. return interp.makeError();
  1572. }
  1573. return new (interp) ProcessChildrenTrimSosofoObj(context.processingMode,
  1574. loc);
  1575. }
  1576. DEFPRIMITIVE(SosofoAppend, argc, argv, context, interp, loc)
  1577. {
  1578. AppendSosofoObj *obj = new (interp) AppendSosofoObj;
  1579. for (int i = 0; i < argc; i++) {
  1580. SosofoObj *sosofo = argv[i]->asSosofo();
  1581. if (!sosofo)
  1582. return argError(interp, loc, InterpreterMessages::notASosofo,
  1583. i, argv[i]);
  1584. obj->append(sosofo);
  1585. }
  1586. return obj;
  1587. }
  1588. DEFPRIMITIVE(NextMatch, argc, argv, context, interp, loc)
  1589. {
  1590. if (!context.processingMode) {
  1591. interp.setNextLocation(loc);
  1592. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1593. return interp.makeError();
  1594. }
  1595. StyleObj *style;
  1596. if (argc == 0)
  1597. style = 0;
  1598. else {
  1599. style = argv[0]->asStyle();
  1600. if (!style)
  1601. return argError(interp, loc, InterpreterMessages::notAStyle, 0, argv[0]);
  1602. }
  1603. return new (interp) NextMatchSosofoObj(style, loc);
  1604. }
  1605. DEFPRIMITIVE(EmptySosofo, argc, argv, context, interp, loc)
  1606. {
  1607. return new (interp) EmptySosofoObj;
  1608. }
  1609. DEFPRIMITIVE(SosofoLabel, argc, argv, context, interp, loc)
  1610. {
  1611. SosofoObj *sosofo = argv[0]->asSosofo();
  1612. if (!sosofo)
  1613. return argError(interp, loc, InterpreterMessages::notASosofo,
  1614. 0, argv[0]);
  1615. SymbolObj *sym = argv[1]->asSymbol();
  1616. if (!sym)
  1617. return argError(interp, loc,
  1618. InterpreterMessages::notASymbol, 1, argv[1]);
  1619. return new (interp) LabelSosofoObj(sym, loc, sosofo);
  1620. }
  1621. DEFPRIMITIVE(SosofoDiscardLabeled, argc, argv, context, interp, loc)
  1622. {
  1623. SosofoObj *sosofo = argv[0]->asSosofo();
  1624. if (!sosofo)
  1625. return argError(interp, loc, InterpreterMessages::notASosofo,
  1626. 0, argv[0]);
  1627. SymbolObj *sym = argv[1]->asSymbol();
  1628. if (!sym)
  1629. return argError(interp, loc,
  1630. InterpreterMessages::notASymbol, 1, argv[1]);
  1631. return new (interp) DiscardLabeledSosofoObj(sym, sosofo);
  1632. }
  1633. DEFPRIMITIVE(IsSosofo, argc, argv, context, interp, loc)
  1634. {
  1635. if (argv[0]->asSosofo())
  1636. return interp.makeTrue();
  1637. else
  1638. return interp.makeFalse();
  1639. }
  1640. DEFPRIMITIVE(MergeStyle, argc, argv, context, interp, loc)
  1641. {
  1642. MergeStyleObj *merged = new (interp) MergeStyleObj;
  1643. for (int i = 0; i < argc; i++) {
  1644. StyleObj *style = argv[i]->asStyle();
  1645. if (!style)
  1646. return argError(interp, loc,
  1647. InterpreterMessages::notAStyle, i, argv[i]);
  1648. merged->append(style);
  1649. }
  1650. return merged;
  1651. }
  1652. DEFPRIMITIVE(IsStyle, argc, argv, context, interp, loc)
  1653. {
  1654. if (argv[0]->asStyle())
  1655. return interp.makeTrue();
  1656. else
  1657. return interp.makeFalse();
  1658. }
  1659. DEFPRIMITIVE(CurrentNodePageNumberSosofo, argc, argv, context, interp, loc)
  1660. {
  1661. if (!context.currentNode)
  1662. return noCurrentNodeError(interp, loc);
  1663. return new (interp) CurrentNodePageNumberSosofoObj(context.currentNode);
  1664. }
  1665. DEFPRIMITIVE(PageNumberSosofo, argc, argv, context, interp, loc)
  1666. {
  1667. return new (interp) PageNumberSosofoObj;
  1668. }
  1669. DEFPRIMITIVE(ProcessElementWithId, argc, argv, context, interp, loc)
  1670. {
  1671. const Char *s;
  1672. size_t n;
  1673. if (!argv[0]->stringData(s, n))
  1674. return argError(interp, loc, InterpreterMessages::notAString, 0, argv[0]);
  1675. if (!context.currentNode)
  1676. return noCurrentNodeError(interp, loc);
  1677. if (!context.processingMode) {
  1678. interp.setNextLocation(loc);
  1679. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1680. return interp.makeError();
  1681. }
  1682. NodePtr root;
  1683. NamedNodeListPtr elements;
  1684. if (context.currentNode->getGroveRoot(root) == accessOK
  1685. && root->getElements(elements) == accessOK) {
  1686. NodePtr node;
  1687. if (elements->namedNode(GroveString(s, n), node) == accessOK)
  1688. return new (interp) ProcessNodeSosofoObj(node, context.processingMode,
  1689. loc);
  1690. }
  1691. return new (interp) EmptySosofoObj;
  1692. }
  1693. DEFPRIMITIVE(ProcessFirstDescendant, argc, argv, context, interp, loc)
  1694. {
  1695. if (!context.processingMode) {
  1696. interp.setNextLocation(loc);
  1697. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1698. return interp.makeError();
  1699. }
  1700. if (!context.currentNode)
  1701. return noCurrentNodeError(interp, loc);
  1702. NCVector<Pattern> patterns(argc);
  1703. for (size_t i = 0; i < argc; i++) {
  1704. if (!interp.convertToPattern(argv[i], loc, patterns[i]))
  1705. return interp.makeError();
  1706. }
  1707. NodeListObj *nl = new (interp) DescendantsNodeListObj(context.currentNode);
  1708. ELObjDynamicRoot protect(interp, nl);
  1709. nl = new (interp) SelectElementsNodeListObj(nl, patterns);
  1710. protect = nl;
  1711. NodePtr nd(nl->nodeListFirst(context, interp));
  1712. if (!nd)
  1713. return new (interp) EmptySosofoObj;
  1714. return new (interp) ProcessNodeSosofoObj(nd, context.processingMode, loc);
  1715. }
  1716. DEFPRIMITIVE(ProcessMatchingChildren, argc, argv, context, interp, loc)
  1717. {
  1718. if (!context.processingMode) {
  1719. interp.setNextLocation(loc);
  1720. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1721. return interp.makeError();
  1722. }
  1723. if (!context.currentNode)
  1724. return noCurrentNodeError(interp, loc);
  1725. NCVector<Pattern> patterns(argc);
  1726. for (size_t i = 0; i < argc; i++) {
  1727. if (!interp.convertToPattern(argv[i], loc, patterns[i]))
  1728. return interp.makeError();
  1729. }
  1730. NodeListPtr nlPtr;
  1731. // FIXME handle root
  1732. if (patterns.size() == 0 || context.currentNode->children(nlPtr) != accessOK)
  1733. return new (interp) EmptySosofoObj;
  1734. NodeListObj *nl = new (interp) NodeListPtrNodeListObj(nlPtr);
  1735. ELObjDynamicRoot protect(interp, nl);
  1736. nl = new (interp) SelectElementsNodeListObj(nl, patterns);
  1737. protect = nl;
  1738. return new (interp) ProcessNodeListSosofoObj(nl, context.processingMode,
  1739. loc);
  1740. }
  1741. DEFPRIMITIVE(SelectElements, argc, argv, context, interp, loc)
  1742. {
  1743. NodeListObj *nl = argv[0]->asNodeList();
  1744. if (!nl)
  1745. return argError(interp, loc,
  1746. InterpreterMessages::notANodeList, 0, argv[0]);
  1747. NCVector<Pattern> patterns(1);
  1748. if (!interp.convertToPattern(argv[1], loc, patterns[0]))
  1749. return interp.makeError();
  1750. return new (interp) SelectElementsNodeListObj(nl, patterns);
  1751. }
  1752. DEFPRIMITIVE(IsMatchElement, argc, argv, context, interp, loc)
  1753. {
  1754. Pattern pattern;
  1755. if (!interp.convertToPattern(argv[0], loc, pattern))
  1756. return interp.makeError();
  1757. NodePtr node;
  1758. if (!argv[1]->optSingletonNodeList(context, interp, node) || !node)
  1759. return argError(interp, loc,
  1760. InterpreterMessages::notASingletonNode, 1, argv[1]);
  1761. if (pattern.matches(node, interp))
  1762. return interp.makeTrue();
  1763. return interp.makeFalse();
  1764. }
  1765. DEFPRIMITIVE(ProcessNodeList, argc, argv, context, interp, loc)
  1766. {
  1767. if (!context.processingMode) {
  1768. interp.setNextLocation(loc);
  1769. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1770. return interp.makeError();
  1771. }
  1772. NodeListObj *nl = argv[0]->asNodeList();
  1773. if (!nl)
  1774. return argError(interp, loc,
  1775. InterpreterMessages::notANodeList, 0, argv[0]);
  1776. return new (interp) ProcessNodeListSosofoObj(nl, context.processingMode, loc);
  1777. }
  1778. static
  1779. void reverse(StringC &s)
  1780. {
  1781. size_t i = 0;
  1782. size_t j = s.size() - 1;
  1783. while (i < j) {
  1784. Char tem = s[i];
  1785. s[i] = s[j];
  1786. s[j] = tem;
  1787. i++;
  1788. j--;
  1789. }
  1790. }
  1791. static
  1792. StringC formatNumberLetter(long n, const char *letters)
  1793. {
  1794. StringC result;
  1795. if (n == 0)
  1796. result += '0';
  1797. else {
  1798. bool neg;
  1799. // FIXME possibility of overflow
  1800. if (n < 0) {
  1801. n = -n;
  1802. neg = 1;
  1803. }
  1804. else
  1805. neg = 0;
  1806. do {
  1807. n--;
  1808. int r = n % 26;
  1809. n -= r;
  1810. n /= 26;
  1811. result += letters[r];
  1812. } while (n > 0);
  1813. if (neg)
  1814. result += '-';
  1815. reverse(result);
  1816. }
  1817. return result;
  1818. }
  1819. static
  1820. StringC formatNumberDecimal(long n, size_t minWidth)
  1821. {
  1822. StringC result;
  1823. char buf[32];
  1824. sprintf(buf, "%ld", n);
  1825. const char *p = buf;
  1826. if (*p == '-') {
  1827. p++;
  1828. result += '-';
  1829. }
  1830. size_t len = strlen(p);
  1831. while (len < minWidth) {
  1832. result += '0';
  1833. len++;
  1834. }
  1835. while (*p)
  1836. result += *p++;
  1837. return result;
  1838. }
  1839. static
  1840. StringC formatNumberRoman(long n, const char *letters)
  1841. {
  1842. StringC result;
  1843. if (n > 5000 || n < -5000 || n == 0)
  1844. return formatNumberDecimal(n, 1);
  1845. if (n < 0) {
  1846. n = -n;
  1847. result += '-';
  1848. }
  1849. while (n >= 1000) {
  1850. result += letters[0];
  1851. n -= 1000;
  1852. }
  1853. for (int i = 100; i > 0; i /= 10, letters += 2) {
  1854. long q = n / i;
  1855. n -= q * i;
  1856. switch (q) {
  1857. case 1:
  1858. result += letters[2];
  1859. break;
  1860. case 2:
  1861. result += letters[2];
  1862. result += letters[2];
  1863. break;
  1864. case 3:
  1865. result += letters[2];
  1866. result += letters[2];
  1867. result += letters[2];
  1868. break;
  1869. case 4:
  1870. result += letters[2];
  1871. result += letters[1];
  1872. break;
  1873. case 5:
  1874. result += letters[1];
  1875. break;
  1876. case 6:
  1877. result += letters[1];
  1878. result += letters[2];
  1879. break;
  1880. case 7:
  1881. result += letters[1];
  1882. result += letters[2];

Large files files are truncated, but you can click here to view the full file