PageRenderTime 69ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/jade_0_1/jade/style/primitive.cxx

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