PageRenderTime 85ms CodeModel.GetById 12ms RepoModel.GetById 2ms app.codeStats 2ms

/tags/jade_1_2_2/jade/style/primitive.cxx

#
C++ | 2531 lines | 2374 code | 126 blank | 31 comment | 531 complexity | 7da8253fe5d8636a5b2da678d9bb879c 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. bool spec = 0;
  628. int dim;
  629. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  630. case ELObj::noQuantity:
  631. dim = 1;
  632. spec = 1;
  633. break;
  634. case ELObj::longQuantity:
  635. usingD = 0;
  636. break;
  637. case ELObj::doubleQuantity:
  638. usingD = 1;
  639. break;
  640. default:
  641. CANNOT_HAPPEN();
  642. }
  643. for (int i = 1; !spec && i < argc; i++) {
  644. long lResult2;
  645. double dResult2;
  646. int dim2;
  647. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  648. case ELObj::noQuantity:
  649. // FIXME shouldn't quantityValue set dim to 1 for length-specs ?
  650. dim2 = 1;
  651. spec = 1;
  652. break;
  653. case ELObj::longQuantity:
  654. if (!usingD) {
  655. if (lResult2 < 0) {
  656. if (lResult >= LONG_MIN - lResult2) {
  657. lResult += lResult2;
  658. break;
  659. }
  660. }
  661. else {
  662. if (lResult <= LONG_MAX - lResult2) {
  663. lResult += lResult2;
  664. break;
  665. }
  666. }
  667. usingD = 1;
  668. dResult = double(lResult);
  669. }
  670. dResult += double(lResult2);
  671. break;
  672. case ELObj::doubleQuantity:
  673. if (!usingD) {
  674. dResult = lResult;
  675. usingD = 1;
  676. }
  677. dResult += dResult2;
  678. break;
  679. default:
  680. CANNOT_HAPPEN();
  681. }
  682. if (dim2 != dim) {
  683. interp.setNextLocation(loc);
  684. interp.message(InterpreterMessages::incompatibleDimensions);
  685. return interp.makeError();
  686. }
  687. }
  688. if (spec) {
  689. LengthSpec ls;
  690. for (int i = 0; i < argc; i++) {
  691. const LengthSpec *lsp = argv[i]->lengthSpec();
  692. if (lsp)
  693. ls += *lsp;
  694. else {
  695. switch (argv[i]->quantityValue(lResult, dResult, dim)) {
  696. case ELObj::noQuantity:
  697. return argError(interp, loc, InterpreterMessages::notAQuantityOrLengthSpec,
  698. i, argv[i]);
  699. case ELObj::longQuantity:
  700. dResult = lResult;
  701. // fall through
  702. case ELObj::doubleQuantity:
  703. if (dim != 1) {
  704. interp.setNextLocation(loc);
  705. interp.message(InterpreterMessages::incompatibleDimensions);
  706. return interp.makeError();
  707. }
  708. ls += dResult;
  709. break;
  710. }
  711. }
  712. }
  713. return new (interp) LengthSpecObj(ls);
  714. }
  715. if (!usingD) {
  716. if (dim == 0)
  717. return interp.makeInteger(lResult);
  718. else if (dim == 1)
  719. return new (interp) LengthObj(lResult);
  720. else
  721. dResult = lResult;
  722. }
  723. if (dim == 0)
  724. return new (interp) RealObj(dResult);
  725. else
  726. return new (interp) QuantityObj(dResult, dim);
  727. }
  728. DEFPRIMITIVE(Minus, argc, argv, context, interp, loc)
  729. {
  730. long lResult;
  731. double dResult;
  732. bool usingD;
  733. bool spec = 0;
  734. int dim;
  735. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  736. case ELObj::noQuantity:
  737. spec = 1;
  738. break;
  739. case ELObj::longQuantity:
  740. usingD = 0;
  741. break;
  742. case ELObj::doubleQuantity:
  743. usingD = 1;
  744. break;
  745. default:
  746. CANNOT_HAPPEN();
  747. }
  748. if (argc == 1) {
  749. if (usingD)
  750. dResult = -dResult;
  751. else
  752. lResult = -lResult;
  753. }
  754. else {
  755. for (int i = 1; !spec && i < argc; i++) {
  756. long lResult2;
  757. double dResult2;
  758. int dim2;
  759. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  760. case ELObj::noQuantity:
  761. dim2 = dim;
  762. spec = 1;
  763. break;
  764. case ELObj::longQuantity:
  765. if (!usingD) {
  766. if (lResult2 > 0) {
  767. if (lResult >= LONG_MIN + lResult2) {
  768. lResult -= lResult2;
  769. break;
  770. }
  771. }
  772. else {
  773. if (lResult <= LONG_MAX + lResult2) {
  774. lResult -= lResult2;
  775. break;
  776. }
  777. }
  778. usingD = 1;
  779. dResult = double(lResult);
  780. }
  781. dResult -= double(lResult2);
  782. break;
  783. case ELObj::doubleQuantity:
  784. if (!usingD) {
  785. dResult = lResult;
  786. usingD = 1;
  787. }
  788. dResult -= dResult2;
  789. break;
  790. default:
  791. CANNOT_HAPPEN();
  792. }
  793. if (dim2 != dim) {
  794. interp.setNextLocation(loc);
  795. interp.message(InterpreterMessages::incompatibleDimensions);
  796. return interp.makeError();
  797. }
  798. }
  799. }
  800. if (spec) {
  801. LengthSpec ls;
  802. for (int i = 0; i < argc; i++) {
  803. const LengthSpec *lsp = argv[i]->lengthSpec();
  804. if (lsp) {
  805. if (i > 0 || argc == 1)
  806. ls -= *lsp;
  807. else
  808. ls += *lsp;
  809. }
  810. else {
  811. switch (argv[i]->quantityValue(lResult, dResult, dim)) {
  812. case ELObj::noQuantity:
  813. return argError(interp, loc, InterpreterMessages::notAQuantityOrLengthSpec,
  814. i, argv[i]);
  815. case ELObj::longQuantity:
  816. dResult = lResult;
  817. // fall through
  818. case ELObj::doubleQuantity:
  819. if (dim != 1) {
  820. interp.setNextLocation(loc);
  821. interp.message(InterpreterMessages::incompatibleDimensions);
  822. return interp.makeError();
  823. }
  824. if (i > 0 || argc == 1)
  825. ls -= dResult;
  826. else
  827. ls += dResult;
  828. break;
  829. }
  830. }
  831. }
  832. return new (interp) LengthSpecObj(ls);
  833. }
  834. if (!usingD) {
  835. if (dim == 0)
  836. return interp.makeInteger(lResult);
  837. else if (dim == 1)
  838. return new (interp) LengthObj(lResult);
  839. else
  840. dResult = lResult;
  841. }
  842. if (dim == 0)
  843. return new (interp) RealObj(dResult);
  844. else
  845. return new (interp) QuantityObj(dResult, dim);
  846. }
  847. DEFPRIMITIVE(Multiply, argc, argv, context, interp, loc)
  848. {
  849. if (argc == 0)
  850. return interp.makeInteger(1);
  851. long lResult;
  852. double dResult;
  853. int dim;
  854. int i = 1;
  855. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  856. case ELObj::noQuantity:
  857. {
  858. const LengthSpec *ls = argv[0]->lengthSpec();
  859. if (ls) {
  860. LengthSpec result(*ls);
  861. double d;
  862. for (; i < argc; i++) {
  863. if (!argv[i]->realValue(d))
  864. return argError(interp, loc,
  865. InterpreterMessages::notANumber, 1, argv[1]);
  866. result *= d;
  867. }
  868. return new (interp) LengthSpecObj(result);
  869. }
  870. }
  871. return argError(interp, loc,
  872. InterpreterMessages::notAQuantity, 0, argv[0]);
  873. case ELObj::longQuantity:
  874. break;
  875. case ELObj::doubleQuantity:
  876. goto useDouble;
  877. default:
  878. CANNOT_HAPPEN();
  879. }
  880. long lResult2;
  881. double dResult2;
  882. int dim2;
  883. for (; i < argc; i++) {
  884. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  885. case ELObj::noQuantity:
  886. return argError(interp, loc,
  887. InterpreterMessages::notAQuantity, i, argv[i]);
  888. case ELObj::longQuantity:
  889. dim += dim2;
  890. if (dim > 1
  891. || (lResult2 != 0
  892. && (lResult2 < 0
  893. ? (lResult > 0
  894. ? lResult > -(unsigned)LONG_MIN / -(unsigned)lResult2
  895. : -(unsigned)lResult > LONG_MAX / -(unsigned)lResult2)
  896. : (lResult > 0
  897. ? lResult > LONG_MAX / lResult2
  898. : -(unsigned)lResult > -(unsigned)LONG_MIN / lResult2)))) {
  899. dResult = double(lResult) * lResult2;
  900. i++;
  901. goto useDouble;
  902. }
  903. lResult *= lResult2;
  904. break;
  905. case ELObj::doubleQuantity:
  906. dim += dim2;
  907. dResult = lResult * dResult2;
  908. i++;
  909. goto useDouble;
  910. default:
  911. CANNOT_HAPPEN();
  912. }
  913. }
  914. if (dim == 0)
  915. return interp.makeInteger(lResult);
  916. else
  917. return new (interp) LengthObj(lResult);
  918. useDouble:
  919. for (; i < argc; i++) {
  920. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  921. case ELObj::noQuantity:
  922. return argError(interp, loc,
  923. InterpreterMessages::notAQuantity, i, argv[i]);
  924. case ELObj::longQuantity:
  925. dResult *= lResult2;
  926. break;
  927. case ELObj::doubleQuantity:
  928. dResult *= dResult2;
  929. break;
  930. }
  931. dim += dim2;
  932. }
  933. if (dim == 0)
  934. return new (interp) RealObj(dResult);
  935. else
  936. return new (interp) QuantityObj(dResult, dim);
  937. }
  938. DEFPRIMITIVE(Divide, argc, argv, context, interp, loc)
  939. {
  940. long lResult;
  941. double dResult;
  942. int dim;
  943. if (argc == 1) {
  944. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  945. case ELObj::noQuantity:
  946. return argError(interp, loc,
  947. InterpreterMessages::notAQuantity, 0, argv[0]);
  948. case ELObj::longQuantity:
  949. if (lResult == 0)
  950. goto divide0;
  951. dResult = 1.0/lResult;
  952. break;
  953. case ELObj::doubleQuantity:
  954. if (dResult == 0.0)
  955. goto divide0;
  956. dResult = 1.0/dResult;
  957. break;
  958. default:
  959. CANNOT_HAPPEN();
  960. }
  961. dim = -dim;
  962. }
  963. else {
  964. int i = 1;
  965. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  966. case ELObj::noQuantity:
  967. {
  968. const LengthSpec *ls = argv[0]->lengthSpec();
  969. if (ls) {
  970. LengthSpec result(*ls);
  971. double d;
  972. for (; i < argc; i++) {
  973. if (!argv[i]->realValue(d))
  974. return argError(interp, loc,
  975. InterpreterMessages::notANumber, 1, argv[1]);
  976. if (d == 0.0)
  977. goto divide0;
  978. result /= d;
  979. }
  980. return new (interp) LengthSpecObj(result);
  981. }
  982. }
  983. return argError(interp, loc,
  984. InterpreterMessages::notAQuantity, 0, argv[0]);
  985. case ELObj::longQuantity:
  986. break;
  987. case ELObj::doubleQuantity:
  988. goto useDouble;
  989. default:
  990. CANNOT_HAPPEN();
  991. }
  992. long lResult2;
  993. double dResult2;
  994. int dim2;
  995. for (; i < argc; i++) {
  996. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  997. case ELObj::noQuantity:
  998. return argError(interp, loc,
  999. InterpreterMessages::notAQuantity, 0, argv[0]);
  1000. case ELObj::longQuantity:
  1001. if (lResult2 == 0)
  1002. goto divide0;
  1003. dim -= dim2;
  1004. // If dim and dim2 are both 1, must goto useDouble:
  1005. // since lengths are inexact, result must be inexact.
  1006. if (dim2 == 0 && lResult % lResult2 == 0) {
  1007. lResult /= lResult2;
  1008. break;
  1009. }
  1010. dResult = double(lResult)/lResult2;
  1011. i++;
  1012. goto useDouble;
  1013. case ELObj::doubleQuantity:
  1014. dim -= dim2;
  1015. dResult = lResult;
  1016. if (dResult2 == 0.0)
  1017. goto divide0;
  1018. dResult /= dResult2;
  1019. i++;
  1020. goto useDouble;
  1021. default:
  1022. CANNOT_HAPPEN();
  1023. }
  1024. }
  1025. if (dim == 0)
  1026. return interp.makeInteger(lResult);
  1027. else
  1028. return new (interp) LengthObj(lResult);
  1029. useDouble:
  1030. for (; i < argc; i++) {
  1031. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1032. case ELObj::noQuantity:
  1033. return argError(interp, loc,
  1034. InterpreterMessages::notAQuantity, i, argv[i]);
  1035. case ELObj::longQuantity:
  1036. if (lResult2 == 0)
  1037. goto divide0;
  1038. dResult /= lResult2;
  1039. break;
  1040. case ELObj::doubleQuantity:
  1041. dResult /= dResult2;
  1042. if (dResult2 == 0.0)
  1043. goto divide0;
  1044. break;
  1045. }
  1046. dim -= dim2;
  1047. }
  1048. }
  1049. if (dim == 0)
  1050. return new (interp) RealObj(dResult);
  1051. else
  1052. return new (interp) QuantityObj(dResult, dim);
  1053. divide0:
  1054. interp.setNextLocation(loc);
  1055. interp.message(InterpreterMessages::divideBy0);
  1056. return interp.makeError();
  1057. }
  1058. DEFPRIMITIVE(Quotient, argc, argv, context, interp, loc)
  1059. {
  1060. long n1;
  1061. long n2;
  1062. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1063. if (n2 == 0) {
  1064. interp.setNextLocation(loc);
  1065. interp.message(InterpreterMessages::divideBy0);
  1066. return interp.makeError();
  1067. }
  1068. // This isn't strictly portable.
  1069. return interp.makeInteger(n1 / n2);
  1070. }
  1071. double d1;
  1072. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1073. return argError(interp, loc,
  1074. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1075. double d2;
  1076. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1077. return argError(interp, loc,
  1078. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1079. if (d2 == 0.0) {
  1080. interp.setNextLocation(loc);
  1081. interp.message(InterpreterMessages::divideBy0);
  1082. return interp.makeError();
  1083. }
  1084. return new (interp) RealObj((d1 - fmod(d1, d2))/d2);
  1085. }
  1086. DEFPRIMITIVE(Remainder, argc, argv, context, interp, loc)
  1087. {
  1088. long n1;
  1089. long n2;
  1090. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1091. if (n2 == 0) {
  1092. interp.setNextLocation(loc);
  1093. interp.message(InterpreterMessages::divideBy0);
  1094. return interp.makeError();
  1095. }
  1096. // This isn't strictly portable.
  1097. return interp.makeInteger(n1 % n2);
  1098. }
  1099. double d1;
  1100. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1101. return argError(interp, loc,
  1102. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1103. double d2;
  1104. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1105. return argError(interp, loc,
  1106. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1107. if (d2 == 0.0) {
  1108. interp.setNextLocation(loc);
  1109. interp.message(InterpreterMessages::divideBy0);
  1110. return interp.makeError();
  1111. }
  1112. return new (interp) RealObj(fmod(d1, d2));
  1113. }
  1114. DEFPRIMITIVE(Modulo, argc, argv, context, interp, loc)
  1115. {
  1116. long n1;
  1117. long n2;
  1118. if (argv[0]->exactIntegerValue(n1) && argv[1]->exactIntegerValue(n2)) {
  1119. if (n2 == 0) {
  1120. interp.setNextLocation(loc);
  1121. interp.message(InterpreterMessages::divideBy0);
  1122. return interp.makeError();
  1123. }
  1124. long r = n1 % n2;
  1125. if (n2 > 0 ? r < 0 : r > 0)
  1126. r += n2;
  1127. return interp.makeInteger(r);
  1128. }
  1129. double d1;
  1130. if (!argv[0]->realValue(d1) || modf(d1, &d1) != 0.0)
  1131. return argError(interp, loc,
  1132. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1133. double d2;
  1134. if (!argv[1]->realValue(d2) || modf(d2, &d2) != 0.0)
  1135. return argError(interp, loc,
  1136. InterpreterMessages::notAnExactInteger, 1, argv[1]);
  1137. if (d2 == 0.0) {
  1138. interp.setNextLocation(loc);
  1139. interp.message(InterpreterMessages::divideBy0);
  1140. return interp.makeError();
  1141. }
  1142. double r = fmod(d1, d2);
  1143. if (d2 > 0 ? r < 0 : r > 0)
  1144. r += d2;
  1145. return new (interp) RealObj(r);
  1146. }
  1147. #define DEFCOMPARE(NAME, OP) \
  1148. DEFPRIMITIVE(NAME, argc, argv, context, interp, loc) \
  1149. { \
  1150. if (argc == 0) \
  1151. return interp.makeTrue(); \
  1152. long lResult; \
  1153. double dResult; \
  1154. int dim; \
  1155. bool lastWasDouble; \
  1156. switch (argv[0]->quantityValue(lResult, dResult, dim)) { \
  1157. case ELObj::noQuantity: \
  1158. return argError(interp, loc, \
  1159. InterpreterMessages::notAQuantity, 0, argv[0]); \
  1160. case ELObj::longQuantity: \
  1161. lastWasDouble = 0; \
  1162. break; \
  1163. case ELObj::doubleQuantity: \
  1164. lastWasDouble = 1; \
  1165. break; \
  1166. default: \
  1167. CANNOT_HAPPEN(); \
  1168. } \
  1169. for (int i = 1; i < argc; i++) { \
  1170. long lResult2; \
  1171. double dResult2; \
  1172. int dim2; \
  1173. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) { \
  1174. case ELObj::noQuantity: \
  1175. return argError(interp, loc, \
  1176. InterpreterMessages::notAQuantity, i, argv[i]); \
  1177. case ELObj::longQuantity: \
  1178. if (dim2 != dim) \
  1179. goto badDim; \
  1180. if (!(lastWasDouble \
  1181. ? (dResult OP lResult2) \
  1182. : (lResult OP lResult2))) \
  1183. return interp.makeFalse(); \
  1184. lResult = lResult2; \
  1185. lastWasDouble = 0; \
  1186. break; \
  1187. case ELObj::doubleQuantity: \
  1188. if (dim != dim2) \
  1189. goto badDim; \
  1190. if (!(lastWasDouble \
  1191. ? (dResult OP dResult2) \
  1192. : (lResult OP dResult2))) \
  1193. return interp.makeFalse(); \
  1194. dResult = dResult2; \
  1195. lastWasDouble = 1; \
  1196. break; \
  1197. } \
  1198. } \
  1199. return interp.makeTrue(); \
  1200. badDim: \
  1201. interp.setNextLocation(loc); \
  1202. interp.message(InterpreterMessages::incompatibleDimensions); \
  1203. return interp.makeError(); \
  1204. }
  1205. DEFCOMPARE(Less, <)
  1206. DEFCOMPARE(Greater, >)
  1207. DEFCOMPARE(LessEqual, <=)
  1208. DEFCOMPARE(GreaterEqual, >=)
  1209. DEFPRIMITIVE(Min, argc, argv, context, interp, loc)
  1210. {
  1211. long lResult;
  1212. double dResult;
  1213. int dim;
  1214. int i = 1;
  1215. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1216. case ELObj::noQuantity:
  1217. return argError(interp, loc,
  1218. InterpreterMessages::notAQuantity, 0, argv[0]);
  1219. case ELObj::longQuantity:
  1220. break;
  1221. case ELObj::doubleQuantity:
  1222. goto useDouble;
  1223. default:
  1224. CANNOT_HAPPEN();
  1225. }
  1226. // Note that result is inexact if any of the arguments are
  1227. for (; i < argc; i++) {
  1228. long lResult2;
  1229. double dResult2;
  1230. int dim2;
  1231. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1232. case ELObj::noQuantity:
  1233. return argError(interp, loc,
  1234. InterpreterMessages::notAQuantity, i, argv[i]);
  1235. case ELObj::longQuantity:
  1236. if (dim2 != dim)
  1237. goto badDim;
  1238. if (lResult2 < lResult)
  1239. lResult = lResult2;
  1240. break;
  1241. case ELObj::doubleQuantity:
  1242. if (dim != dim2)
  1243. goto badDim;
  1244. if (dResult2 < lResult)
  1245. dResult = dResult2;
  1246. else if (dim)
  1247. break;
  1248. else
  1249. dResult = lResult;
  1250. i++;
  1251. goto useDouble;
  1252. }
  1253. }
  1254. if (dim == 0)
  1255. return interp.makeInteger(lResult);
  1256. else
  1257. return new (interp) LengthObj(lResult);
  1258. useDouble:
  1259. for (; i < argc; i++) {
  1260. long lResult2;
  1261. double dResult2;
  1262. int dim2;
  1263. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1264. case ELObj::noQuantity:
  1265. return argError(interp, loc,
  1266. InterpreterMessages::notAQuantity, i, argv[i]);
  1267. case ELObj::longQuantity:
  1268. if (dim2 != dim)
  1269. goto badDim;
  1270. if (lResult2 < dResult)
  1271. dResult = lResult2;
  1272. break;
  1273. case ELObj::doubleQuantity:
  1274. if (dim != dim2)
  1275. goto badDim;
  1276. if (dResult2 < dResult)
  1277. dResult = dResult2;
  1278. break;
  1279. }
  1280. }
  1281. if (dim == 0)
  1282. return new (interp) RealObj(dResult);
  1283. else
  1284. return new (interp) QuantityObj(dResult, dim);
  1285. badDim:
  1286. interp.setNextLocation(loc);
  1287. interp.message(InterpreterMessages::incompatibleDimensions);
  1288. return interp.makeError();
  1289. }
  1290. DEFPRIMITIVE(Max, argc, argv, context, interp, loc)
  1291. {
  1292. long lResult;
  1293. double dResult;
  1294. int dim;
  1295. int i = 1;
  1296. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1297. case ELObj::noQuantity:
  1298. return argError(interp, loc,
  1299. InterpreterMessages::notAQuantity, 0, argv[0]);
  1300. case ELObj::longQuantity:
  1301. break;
  1302. case ELObj::doubleQuantity:
  1303. goto useDouble;
  1304. default:
  1305. CANNOT_HAPPEN();
  1306. }
  1307. // Note that result is inexact if any of the arguments are
  1308. for (; i < argc; i++) {
  1309. long lResult2;
  1310. double dResult2;
  1311. int dim2;
  1312. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1313. case ELObj::noQuantity:
  1314. return argError(interp, loc,
  1315. InterpreterMessages::notAQuantity, i, argv[i]);
  1316. case ELObj::longQuantity:
  1317. if (dim2 != dim)
  1318. goto badDim;
  1319. if (lResult2 > lResult)
  1320. lResult = lResult2;
  1321. break;
  1322. case ELObj::doubleQuantity:
  1323. if (dim != dim2)
  1324. goto badDim;
  1325. if (dResult2 > lResult)
  1326. dResult = dResult2;
  1327. else if (dim)
  1328. break;
  1329. else
  1330. dResult = lResult;
  1331. i++;
  1332. goto useDouble;
  1333. }
  1334. }
  1335. if (dim == 0)
  1336. return interp.makeInteger(lResult);
  1337. else
  1338. return new (interp) LengthObj(lResult);
  1339. useDouble:
  1340. for (; i < argc; i++) {
  1341. long lResult2;
  1342. double dResult2;
  1343. int dim2;
  1344. switch (argv[i]->quantityValue(lResult2, dResult2, dim2)) {
  1345. case ELObj::noQuantity:
  1346. return argError(interp, loc,
  1347. InterpreterMessages::notAQuantity, i, argv[i]);
  1348. case ELObj::longQuantity:
  1349. if (dim2 != dim)
  1350. goto badDim;
  1351. if (lResult2 > dResult)
  1352. dResult = lResult2;
  1353. break;
  1354. case ELObj::doubleQuantity:
  1355. if (dim != dim2)
  1356. goto badDim;
  1357. if (dResult2 > dResult)
  1358. dResult = dResult2;
  1359. break;
  1360. }
  1361. }
  1362. if (dim == 0)
  1363. return new (interp) RealObj(dResult);
  1364. else
  1365. return new (interp) QuantityObj(dResult, dim);
  1366. badDim:
  1367. interp.setNextLocation(loc);
  1368. interp.message(InterpreterMessages::incompatibleDimensions);
  1369. return interp.makeError();
  1370. }
  1371. DEFPRIMITIVE(Floor, argc, argv, context, interp, loc)
  1372. {
  1373. double d;
  1374. if (argv[0]->inexactRealValue(d))
  1375. return new (interp) RealObj(floor(d));
  1376. long n;
  1377. if (argv[0]->exactIntegerValue(n))
  1378. return argv[0];
  1379. return argError(interp, loc,
  1380. InterpreterMessages::notANumber, 0, argv[0]);
  1381. }
  1382. DEFPRIMITIVE(Ceiling, argc, argv, context, interp, loc)
  1383. {
  1384. double d;
  1385. if (argv[0]->inexactRealValue(d))
  1386. return new (interp) RealObj(ceil(d));
  1387. long n;
  1388. if (argv[0]->exactIntegerValue(n))
  1389. return argv[0];
  1390. return argError(interp, loc,
  1391. InterpreterMessages::notANumber, 0, argv[0]);
  1392. }
  1393. DEFPRIMITIVE(Round, argc, argv, context, interp, loc)
  1394. {
  1395. double d;
  1396. if (argv[0]->inexactRealValue(d)) {
  1397. double result = floor(d + .5);
  1398. // That rounded it upwards.
  1399. // Now figure out if that was different from round to
  1400. // even.
  1401. if (result - d == 0.5 && fmod(result, 2.0) != 0)
  1402. result -= 1.0;
  1403. return new (interp) RealObj(result);
  1404. }
  1405. long n;
  1406. if (argv[0]->exactIntegerValue(n))
  1407. return argv[0];
  1408. return argError(interp, loc,
  1409. InterpreterMessages::notANumber, 0, argv[0]);
  1410. }
  1411. DEFPRIMITIVE(Truncate, argc, argv, context, interp, loc)
  1412. {
  1413. double d;
  1414. if (argv[0]->inexactRealValue(d)) {
  1415. double iPart;
  1416. modf(d, &iPart);
  1417. return new (interp) RealObj(iPart);
  1418. }
  1419. long n;
  1420. if (argv[0]->exactIntegerValue(n))
  1421. return argv[0];
  1422. return argError(interp, loc,
  1423. InterpreterMessages::notANumber, 0, argv[0]);
  1424. }
  1425. DEFPRIMITIVE(Abs, argc, argv, context, interp, loc)
  1426. {
  1427. long lResult;
  1428. double dResult;
  1429. int dim;
  1430. switch (argv[0]->quantityValue(lResult, dResult, dim)) {
  1431. case ELObj::noQuantity:
  1432. return argError(interp, loc,
  1433. InterpreterMessages::notAQuantity, 0, argv[0]);
  1434. case ELObj::longQuantity:
  1435. if (lResult != LONG_MIN) {
  1436. if (lResult >= 0)
  1437. return argv[0];
  1438. if (dim == 0)
  1439. return interp.makeInteger(-lResult);
  1440. else
  1441. return new (interp) LengthObj(-lResult);
  1442. }
  1443. dResult = lResult;
  1444. break;
  1445. case ELObj::doubleQuantity:
  1446. break;
  1447. default:
  1448. CANNOT_HAPPEN();
  1449. }
  1450. if (dResult >= 0)
  1451. return argv[0];
  1452. if (dim == 0)
  1453. return new (interp) RealObj(-dResult);
  1454. else
  1455. return new (interp) QuantityObj(-dResult, dim);
  1456. }
  1457. DEFPRIMITIVE(Sqrt, argc, argv, context, interp, loc)
  1458. {
  1459. long lResult;
  1460. double dResult;
  1461. int dim;
  1462. ELObj::QuantityType type
  1463. = argv[0]->quantityValue(lResult, dResult, dim);
  1464. switch (type) {
  1465. case ELObj::noQuantity:
  1466. return argError(interp, loc,
  1467. InterpreterMessages::notAQuantity, 0, argv[0]);
  1468. case ELObj::longQuantity:
  1469. dResult = lResult;
  1470. break;
  1471. case ELObj::doubleQuantity:
  1472. break;
  1473. default:
  1474. CANNOT_HAPPEN();
  1475. }
  1476. if ((dim & 1) || dResult < 0.0) {
  1477. interp.setNextLocation(loc);
  1478. interp.message(InterpreterMessages::outOfRange);
  1479. return interp.makeError();
  1480. }
  1481. dim /= 2;
  1482. dResult = sqrt(dResult);
  1483. if (type == ELObj::longQuantity && dim == 0) {
  1484. long n = long(dResult);
  1485. if (n*n == lResult)
  1486. return interp.makeInteger(n);
  1487. }
  1488. return new (interp) QuantityObj(dResult, dim);
  1489. }
  1490. DEFPRIMITIVE(Time, argc, argv, context, interp, loc)
  1491. {
  1492. // This assumes a Posix compatible time().
  1493. time_t t = time(0);
  1494. return interp.makeInteger(long(t));
  1495. }
  1496. DEFPRIMITIVE(TimeToString, argc, argv, context, interp, loc)
  1497. {
  1498. long k;
  1499. if (!argv[0]->exactIntegerValue(k))
  1500. return argError(interp, loc,
  1501. InterpreterMessages::notAnExactInteger, 0, argv[0]);
  1502. time_t t = time_t(k);
  1503. const struct tm *p;
  1504. if (argc > 1 && argv[1] != interp.makeFalse())
  1505. p = gmtime(&t);
  1506. else
  1507. p = localtime(&t);
  1508. char buf[64];
  1509. sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d",
  1510. p->tm_year + 1900, p->tm_mon + 1, p->tm_mday,
  1511. p->tm_hour, p->tm_min, p->tm_sec);
  1512. return new (interp) StringObj(interp.makeStringC(buf));
  1513. }
  1514. DEFPRIMITIVE(CharProperty, argc, argv, context, interp, loc)
  1515. {
  1516. SymbolObj *sym = argv[0]->asSymbol();
  1517. if (!sym)
  1518. return argError(interp, loc,
  1519. InterpreterMessages::notASymbol, 0, argv[0]);
  1520. Char c;
  1521. if (!argv[1]->charValue(c))
  1522. return argError(interp, loc,
  1523. InterpreterMessages::notAChar, 1, argv[1]);
  1524. // FIXME
  1525. if (argc > 2)
  1526. return argv[2];
  1527. else
  1528. return interp.makeFalse();
  1529. }
  1530. DEFPRIMITIVE(Literal, argc, argv, context, interp, loc)
  1531. {
  1532. if (argc == 0)
  1533. return new (interp) EmptySosofoObj;
  1534. const Char *s;
  1535. size_t n;
  1536. if (!argv[0]->stringData(s, n))
  1537. return argError(interp, loc, InterpreterMessages::notAString,
  1538. 0, argv[0]);
  1539. if (argc == 1)
  1540. return new (interp) LiteralSosofoObj(argv[0]);
  1541. StringObj *strObj = new (interp) StringObj(s, n);
  1542. for (int i = 1; i < argc; i++) {
  1543. if (!argv[i]->stringData(s, n))
  1544. return argError(interp, loc, InterpreterMessages::notAString,
  1545. i, argv[i]);
  1546. strObj->append(s, n);
  1547. }
  1548. ELObjDynamicRoot protect(interp, strObj);
  1549. return new (interp) LiteralSosofoObj(strObj);
  1550. }
  1551. DEFPRIMITIVE(ProcessChildren, argc, argv, context, interp, loc)
  1552. {
  1553. if (!context.processingMode) {
  1554. interp.setNextLocation(loc);
  1555. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1556. return interp.makeError();
  1557. }
  1558. return new (interp) ProcessChildrenSosofoObj(context.processingMode);
  1559. }
  1560. DEFPRIMITIVE(ProcessChildrenTrim, argc, argv, context, interp, loc)
  1561. {
  1562. if (!context.processingMode) {
  1563. interp.setNextLocation(loc);
  1564. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1565. return interp.makeError();
  1566. }
  1567. return new (interp) ProcessChildrenTrimSosofoObj(context.processingMode);
  1568. }
  1569. DEFPRIMITIVE(SosofoAppend, argc, argv, context, interp, loc)
  1570. {
  1571. AppendSosofoObj *obj = new (interp) AppendSosofoObj;
  1572. for (int i = 0; i < argc; i++) {
  1573. SosofoObj *sosofo = argv[i]->asSosofo();
  1574. if (!sosofo)
  1575. return argError(interp, loc, InterpreterMessages::notASosofo,
  1576. i, argv[i]);
  1577. obj->append(sosofo);
  1578. }
  1579. return obj;
  1580. }
  1581. DEFPRIMITIVE(NextMatch, argc, argv, context, interp, loc)
  1582. {
  1583. if (!context.processingMode) {
  1584. interp.setNextLocation(loc);
  1585. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1586. return interp.makeError();
  1587. }
  1588. StyleObj *style;
  1589. if (argc == 0)
  1590. style = 0;
  1591. else {
  1592. style = argv[0]->asStyle();
  1593. if (!style)
  1594. return argError(interp, loc, InterpreterMessages::notAStyle, 0, argv[0]);
  1595. }
  1596. return new (interp) NextMatchSosofoObj(style);
  1597. }
  1598. DEFPRIMITIVE(EmptySosofo, argc, argv, context, interp, loc)
  1599. {
  1600. return new (interp) EmptySosofoObj;
  1601. }
  1602. DEFPRIMITIVE(SosofoLabel, argc, argv, context, interp, loc)
  1603. {
  1604. SosofoObj *sosofo = argv[0]->asSosofo();
  1605. if (!sosofo)
  1606. return argError(interp, loc, InterpreterMessages::notASosofo,
  1607. 0, argv[0]);
  1608. SymbolObj *sym = argv[1]->asSymbol();
  1609. if (!sym)
  1610. return argError(interp, loc,
  1611. InterpreterMessages::notASymbol, 1, argv[1]);
  1612. return new (interp) LabelSosofoObj(sym, loc, sosofo);
  1613. }
  1614. DEFPRIMITIVE(SosofoDiscardLabeled, argc, argv, context, interp, loc)
  1615. {
  1616. SosofoObj *sosofo = argv[0]->asSosofo();
  1617. if (!sosofo)
  1618. return argError(interp, loc, InterpreterMessages::notASosofo,
  1619. 0, argv[0]);
  1620. SymbolObj *sym = argv[1]->asSymbol();
  1621. if (!sym)
  1622. return argError(interp, loc,
  1623. InterpreterMessages::notASymbol, 1, argv[1]);
  1624. return new (interp) DiscardLabeledSosofoObj(sym, sosofo);
  1625. }
  1626. DEFPRIMITIVE(IsSosofo, argc, argv, context, interp, loc)
  1627. {
  1628. if (argv[0]->asSosofo())
  1629. return interp.makeTrue();
  1630. else
  1631. return interp.makeFalse();
  1632. }
  1633. DEFPRIMITIVE(MergeStyle, argc, argv, context, interp, loc)
  1634. {
  1635. MergeStyleObj *merged = new (interp) MergeStyleObj;
  1636. for (int i = 0; i < argc; i++) {
  1637. StyleObj *style = argv[i]->asStyle();
  1638. if (!style)
  1639. return argError(interp, loc,
  1640. InterpreterMessages::notAStyle, i, argv[i]);
  1641. merged->append(style);
  1642. }
  1643. return merged;
  1644. }
  1645. DEFPRIMITIVE(IsStyle, argc, argv, context, interp, loc)
  1646. {
  1647. if (argv[0]->asStyle())
  1648. return interp.makeTrue();
  1649. else
  1650. return interp.makeFalse();
  1651. }
  1652. DEFPRIMITIVE(CurrentNodePageNumberSosofo, argc, argv, context, interp, loc)
  1653. {
  1654. if (!context.currentNode)
  1655. return noCurrentNodeError(interp, loc);
  1656. return new (interp) CurrentNodePageNumberSosofoObj(context.currentNode);
  1657. }
  1658. DEFPRIMITIVE(PageNumberSosofo, argc, argv, context, interp, loc)
  1659. {
  1660. return new (interp) PageNumberSosofoObj;
  1661. }
  1662. DEFPRIMITIVE(ProcessElementWithId, argc, argv, context, interp, loc)
  1663. {
  1664. const Char *s;
  1665. size_t n;
  1666. if (!argv[0]->stringData(s, n))
  1667. return argError(interp, loc, InterpreterMessages::notAString, 0, argv[0]);
  1668. if (!context.currentNode)
  1669. return noCurrentNodeError(interp, loc);
  1670. if (!context.processingMode) {
  1671. interp.setNextLocation(loc);
  1672. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1673. return interp.makeError();
  1674. }
  1675. NodePtr root;
  1676. NamedNodeListPtr elements;
  1677. if (context.currentNode->getGroveRoot(root) == accessOK
  1678. && root->getElements(elements) == accessOK) {
  1679. NodePtr node;
  1680. if (elements->namedNode(GroveString(s, n), node) == accessOK)
  1681. return new (interp) ProcessNodeSosofoObj(node, context.processingMode);
  1682. }
  1683. return new (interp) EmptySosofoObj;
  1684. }
  1685. DEFPRIMITIVE(ProcessFirstDescendant, argc, argv, context, interp, loc)
  1686. {
  1687. if (!context.processingMode) {
  1688. interp.setNextLocation(loc);
  1689. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1690. return interp.makeError();
  1691. }
  1692. if (!context.currentNode)
  1693. return noCurrentNodeError(interp, loc);
  1694. NCVector<Pattern> patterns(argc);
  1695. for (size_t i = 0; i < argc; i++) {
  1696. if (!interp.convertToPattern(argv[i], loc, patterns[i]))
  1697. return interp.makeError();
  1698. }
  1699. NodeListObj *nl = new (interp) DescendantsNodeListObj(context.currentNode);
  1700. ELObjDynamicRoot protect(interp, nl);
  1701. nl = new (interp) SelectElementsNodeListObj(nl, patterns);
  1702. protect = nl;
  1703. NodePtr nd(nl->nodeListFirst(context, interp));
  1704. if (!nd)
  1705. return new (interp) EmptySosofoObj;
  1706. return new (interp) ProcessNodeSosofoObj(nd, context.processingMode);
  1707. }
  1708. DEFPRIMITIVE(ProcessMatchingChildren, argc, argv, context, interp, loc)
  1709. {
  1710. if (!context.processingMode) {
  1711. interp.setNextLocation(loc);
  1712. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1713. return interp.makeError();
  1714. }
  1715. if (!context.currentNode)
  1716. return noCurrentNodeError(interp, loc);
  1717. NCVector<Pattern> patterns(argc);
  1718. for (size_t i = 0; i < argc; i++) {
  1719. if (!interp.convertToPattern(argv[i], loc, patterns[i]))
  1720. return interp.makeError();
  1721. }
  1722. NodeListPtr nlPtr;
  1723. // FIXME handle root
  1724. if (patterns.size() == 0 || context.currentNode->children(nlPtr) != accessOK)
  1725. return new (interp) EmptySosofoObj;
  1726. NodeListObj *nl = new (interp) NodeListPtrNodeListObj(nlPtr);
  1727. ELObjDynamicRoot protect(interp, nl);
  1728. nl = new (interp) SelectElementsNodeListObj(nl, patterns);
  1729. protect = nl;
  1730. return new (interp) ProcessNodeListSosofoObj(nl, context.processingMode);
  1731. }
  1732. DEFPRIMITIVE(SelectElements, argc, argv, context, interp, loc)
  1733. {
  1734. NodeListObj *nl = argv[0]->asNodeList();
  1735. if (!nl)
  1736. return argError(interp, loc,
  1737. InterpreterMessages::notANodeList, 0, argv[0]);
  1738. NCVector<Pattern> patterns(1);
  1739. if (!interp.convertToPattern(argv[1], loc, patterns[0]))
  1740. return interp.makeError();
  1741. return new (interp) SelectElementsNodeListObj(nl, patterns);
  1742. }
  1743. DEFPRIMITIVE(IsMatchElement, argc, argv, context, interp, loc)
  1744. {
  1745. Pattern pattern;
  1746. if (!interp.convertToPattern(argv[0], loc, pattern))
  1747. return interp.makeError();
  1748. NodePtr node;
  1749. if (!argv[1]->optSingletonNodeList(context, interp, node) || !node)
  1750. return argError(interp, loc,
  1751. InterpreterMessages::notASingletonNode, 1, argv[1]);
  1752. if (pattern.matches(node, interp))
  1753. return interp.makeTrue();
  1754. return interp.makeFalse();
  1755. }
  1756. DEFPRIMITIVE(ProcessNodeList, argc, argv, context, interp, loc)
  1757. {
  1758. if (!context.processingMode) {
  1759. interp.setNextLocation(loc);
  1760. interp.message(InterpreterMessages::noCurrentProcessingMode);
  1761. return interp.makeError();
  1762. }
  1763. NodeListObj *nl = argv[0]->asNodeList();
  1764. if (!nl)
  1765. return argError(interp, loc,
  1766. InterpreterMessages::notANodeList, 0, argv[0]);
  1767. return new (interp) ProcessNodeListSosofoObj(nl, context.processingMode);
  1768. }
  1769. static
  1770. void reverse(StringC &s)
  1771. {
  1772. size_t i = 0;
  1773. size_t j = s.size() - 1;
  1774. while (i < j) {
  1775. Char tem = s[i];
  1776. s[i] = s[j];
  1777. s[j] = tem;
  1778. i++;
  1779. j--;
  1780. }
  1781. }
  1782. static
  1783. StringC formatNumberLetter(long n, const char *letters)
  1784. {
  1785. StringC result;
  1786. if (n == 0)
  1787. result += '0';
  1788. else {
  1789. bool neg;
  1790. // FIXME possibility of overflow
  1791. if (n < 0) {
  1792. n = -n;
  1793. neg = 1;
  1794. }
  1795. else
  1796. neg = 0;
  1797. do {
  1798. n--;
  1799. int r = n % 26;
  1800. n -= r;
  1801. n /= 26;
  1802. result += letters[r];
  1803. } while (n > 0);
  1804. if (neg)
  1805. result += '-';
  1806. reverse(result);
  1807. }
  1808. return result;
  1809. }
  1810. static
  1811. StringC formatNumberDecimal(long n, size_t minWidth)
  1812. {
  1813. StringC result;
  1814. char buf[32];
  1815. sprintf(buf, "%ld", n);
  1816. const char *p = buf;
  1817. if (*p == '-') {
  1818. p++;
  1819. result += '-';
  1820. }
  1821. size_t len = strlen(p);
  1822. while (len < minWidth) {
  1823. result += '0';
  1824. len++;
  1825. }
  1826. while (*p)
  1827. result += *p++;
  1828. return result;
  1829. }
  1830. static
  1831. StringC formatNumberRoman(long n, const char *letters)
  1832. {
  1833. StringC result;
  1834. if (n > 5000 || n < -5000 || n == 0)
  1835. return formatNumberDecimal(n, 1);
  1836. if (n < 0) {
  1837. n = -n;
  1838. result += '-';
  1839. }
  1840. while (n >= 1000) {
  1841. result += letters[0];
  1842. n -= 1000;
  1843. }
  1844. for (int i = 100; i > 0; i /= 10, letters += 2) {
  1845. long q = n / i;
  1846. n -= q * i;
  1847. switch (q) {
  1848. case 1:
  1849. result += letters[2];
  1850. break;
  1851. case 2:
  1852. result += letters[2];
  1853. result += letters[2];
  1854. break;
  1855. case 3:
  1856. result += letters[2];
  1857. result += letters[2];
  1858. result += letters[2];
  1859. break;
  1860. case 4:
  1861. result += letters[2];
  1862. result += letters[1];
  1863. break;
  1864. case 5:
  1865. result += letters[1];
  1866. break;
  1867. case 6:
  1868. result += letters[1];
  1869. result += letters[2];
  1870. break;
  1871. case 7:
  1872. result += letters[1];
  1873. result += letters[2];
  1874. result += letters[2];
  1875. break;
  1876. case 8:
  1877. result += letters[1];
  1878. result += letters[2];
  1879. result += letters[2];
  1880. result += letters[2];
  1881. break;
  1882. case 9:
  1883. result += letters[2];
  1884. result += letters[0];
  1885. break;
  1886. }
  1887. }
  1888. return result;
  1889. }
  1890. static
  1891. bool formatNumber(long n, const Char *s, size_t len, StringC &result)
  1892. {
  1893. if (len > 0) {
  1894. switch (s[len - 1]) {
  1895. case 'a':

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