PageRenderTime 57ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/jade_1_1/jade/style/primitive.cxx

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

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