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

/tags/jade_RELEASE-1_3_3-pre1/style/primitive.cxx

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

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