PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/jasi/semantics/procedure/PrimitiveProcedure.java

http://jasi-himanshu.googlecode.com/
Java | 1024 lines | 787 code | 153 blank | 84 comment | 169 complexity | a212a4c8cf24f4d82a95153a1fdb834f MD5 | raw file
  1. package jasi.semantics.procedure;
  2. import java.util.ArrayList;
  3. import jasi.Main;
  4. import jasi.datatype.SBoolean;
  5. import jasi.datatype.SChar;
  6. import jasi.datatype.SEmptyList;
  7. import jasi.datatype.SNumber;
  8. import jasi.datatype.SPair;
  9. import jasi.datatype.SString;
  10. import jasi.datatype.SUndefined;
  11. import jasi.datatype.SVariable;
  12. import jasi.parser.Reader;
  13. import jasi.semantics.Environment;
  14. import jasi.semantics.Scheme;
  15. import jasi.semantics.Utils;
  16. public class PrimitiveProcedure extends Procedure {
  17. //procecure Ids
  18. public final static int PLUS = 0;
  19. public final static int MINUS = PLUS + 1;
  20. public final static int MULTIPLICATION = MINUS + 1;
  21. public final static int DIVISION = MULTIPLICATION + 1;
  22. public final static int NOT = DIVISION + 1;
  23. public final static int GT = NOT + 1;
  24. public final static int LT = GT + 1;
  25. public final static int GT_EQ = LT + 1;
  26. public final static int LT_EQ = GT_EQ + 1;
  27. public final static int MAKE_STRING = LT_EQ + 1;
  28. public final static int SYMBOL_TO_STRING = MAKE_STRING + 1;
  29. public final static int STRING_TO_SYMBOL = SYMBOL_TO_STRING + 1;
  30. public final static int STRING_LENGTH = STRING_TO_SYMBOL + 1;
  31. public final static int STRING_REF = STRING_LENGTH + 1;
  32. public final static int STRING_SET = STRING_REF + 1;
  33. public final static int NUMBER_TO_STRING = STRING_SET + 1;
  34. public final static int STRING_TO_NUMBER = NUMBER_TO_STRING + 1;
  35. public final static int CHAR_UPCASE = STRING_TO_NUMBER + 1;
  36. public final static int CHAR_DOWNCASE = CHAR_UPCASE + 1;
  37. public final static int CHAR_LT = CHAR_DOWNCASE + 1;
  38. public final static int CHAR_PRED_ALPHABETIC = CHAR_LT + 1;
  39. public final static int CHAR_PRED_NUMERIC = CHAR_PRED_ALPHABETIC + 1;
  40. public final static int CHAR_PRED_WHITESPACE = CHAR_PRED_NUMERIC + 1;
  41. public final static int CHAR_PRED_LOWERCASE = CHAR_PRED_WHITESPACE + 1;
  42. public final static int CHAR_PRED_UPPERCASE = CHAR_PRED_LOWERCASE + 1;
  43. public final static int READ = 100;
  44. public final static int EVAL = READ + 1;
  45. public final static int APPLY = EVAL + 1;
  46. public final static int ERROR = APPLY + 1;
  47. public final static int INTERACTION_ENVIRONMENT = ERROR + 1;
  48. public final static int DISPLAY = INTERACTION_ENVIRONMENT + 1;
  49. public final static int WRITE = DISPLAY + 1;
  50. public final static int NEWLINE = WRITE + 1;
  51. public final static int CONS = NEWLINE + 1;
  52. public final static int LIST = CONS + 1;
  53. public final static int PRED_EQ = LIST + 1;
  54. public final static int PRED_EQV = PRED_EQ + 1;
  55. public final static int PRED_EQUAL = PRED_EQV + 1;
  56. public final static int CAR = PRED_EQUAL + 1;
  57. public final static int CDR = CAR + 1;
  58. public final static int SET_CAR = CDR + 1;
  59. public final static int SET_CDR = SET_CAR + 1;
  60. public final static int PRED_PAIR = SET_CDR + 1;
  61. public final static int PRED_LIST = PRED_PAIR + 1;
  62. public final static int PRED_BOOLEAN = PRED_LIST + 1;
  63. public final static int PRED_CHAR = PRED_BOOLEAN + 1;
  64. public final static int PRED_STRING = PRED_CHAR + 1;
  65. public final static int PRED_SYMBOL = PRED_STRING + 1;
  66. public final static int PRED_NUMBER = PRED_SYMBOL + 1;
  67. public final static int PRED_PROCEDURE = PRED_NUMBER + 1;
  68. public final static int PRED_NULL = PRED_PROCEDURE + 1;
  69. //procedure id of this PrimitiveProcedure
  70. private int id;
  71. public PrimitiveProcedure(int id) {
  72. this.id = id;
  73. }
  74. public Object apply(Object o, Environment env) {
  75. ArrayList<Object> args = null;
  76. if(o != null) {
  77. if(o instanceof ArrayList)
  78. args = (ArrayList)o;
  79. else
  80. throw new RuntimeException("arguments not ArrayList:" + o);
  81. }
  82. //for all the procedures that take a limited number of arguments, we pass
  83. //min, max integers specifying the number of minimum and maximum arguments
  84. //they can take. For a procedure that can take any arguments we pass a -ve
  85. //value for max.
  86. final int n = -1;
  87. switch(id) {
  88. case PLUS:
  89. return applyPlus(args, 0, n);
  90. case MINUS:
  91. return applyMinus(args, 1, n);
  92. case MULTIPLICATION:
  93. return applyMultiplication(args, 0 ,n);
  94. case DIVISION:
  95. return applyDivision(args, 1, n);
  96. case NOT:
  97. return applyNot(args, 1 ,1);
  98. case GT:
  99. return applyGreaterThan(args, 0, n);
  100. case LT:
  101. return applyLessThan(args, 0 ,n);
  102. case GT_EQ:
  103. return applyGreaterThanEqual(args, 0 , n);
  104. case LT_EQ:
  105. return applyLessThanEqual(args, 0 , n);
  106. case MAKE_STRING:
  107. return applyMakeString(args, 1, 2);
  108. case SYMBOL_TO_STRING:
  109. return applySymbolToString(args, 1, 1);
  110. case STRING_TO_SYMBOL:
  111. return applyStringToSymbol(args, 1, 1);
  112. case STRING_LENGTH:
  113. return applyStringLength(args, 1, 1);
  114. case STRING_REF:
  115. return applyStringRef(args, 2, 2);
  116. case STRING_SET:
  117. return applyStringSet(args, 3, 3);
  118. case NUMBER_TO_STRING:
  119. return applyNumberToString(args, 1, 1);
  120. case STRING_TO_NUMBER:
  121. return applyStringToNumber(args, 1, 1);
  122. case CHAR_UPCASE:
  123. return applyCharUpCase(args, 1, 1);
  124. case CHAR_DOWNCASE:
  125. return applyCharDownCase(args, 1, 1);
  126. case CHAR_LT:
  127. return applyCharLess(args, 2, 2);
  128. case CHAR_PRED_ALPHABETIC:
  129. return applyCharPredAlphabetic(args, 1, 1);
  130. case CHAR_PRED_NUMERIC:
  131. return applyCharPredNumeric(args, 1, 1);
  132. case CHAR_PRED_WHITESPACE:
  133. return applyCharPredWhitespace(args, 1, 1);
  134. case CHAR_PRED_LOWERCASE:
  135. return applyCharPredLowerCase(args, 1, 1);
  136. case CHAR_PRED_UPPERCASE:
  137. return applyCharPredUpperCase(args, 1, 1);
  138. case READ:
  139. return applyRead();
  140. case EVAL:
  141. return applyEval(args, 1 ,2, env);
  142. case ERROR:
  143. return applyError(args, 1, 1);
  144. case APPLY:
  145. return applyApply(args, 2 ,2, env);
  146. case INTERACTION_ENVIRONMENT:
  147. return applyInteractionEnvironment(args, 0 ,0);
  148. case PRED_EQ:
  149. return applyPredEq(args , 2, 2);
  150. case PRED_EQV:
  151. return applyPredEqv(args, 2, 2);
  152. case PRED_EQUAL:
  153. return applyPredEqual(args, 2, 2);
  154. case DISPLAY:
  155. return applyDisplay(args, 1, 2);
  156. case WRITE:
  157. return applyWrite(args, 1, 2);
  158. case NEWLINE:
  159. return applyNewline();
  160. case CONS:
  161. return applyCons(args, 2 , 2);
  162. case CAR:
  163. return applyCar(args, 1, 1);
  164. case CDR:
  165. return applyCdr(args, 1, 1);
  166. case SET_CAR:
  167. return applySetCar(args, 2, 2);
  168. case SET_CDR:
  169. return applySetCdr(args, 2, 2);
  170. case PRED_PAIR:
  171. return applyPredPair(args, 1, 1);
  172. case PRED_LIST:
  173. return applyPredList(args, 1, 1);
  174. case LIST:
  175. return applyList(args, 0 , n);
  176. case PRED_BOOLEAN:
  177. return applyPredBoolean(args, 1 ,1);
  178. case PRED_CHAR:
  179. return applyPredChar(args, 1 ,1);
  180. case PRED_NULL:
  181. return applyPredNull(args, 1 ,1);
  182. case PRED_NUMBER:
  183. return applyPredNumber(args, 1 ,1);
  184. case PRED_PROCEDURE:
  185. return applyPredProcedure(args, 1 ,1);
  186. case PRED_STRING:
  187. return applyPredString(args, 1 ,1);
  188. case PRED_SYMBOL:
  189. return applyPredSymbol(args, 1 ,1);
  190. default:
  191. throw new RuntimeException("not a valid primitive procedure id:" + id);
  192. }
  193. }
  194. //min-max is the number of minimum and maximum arguments this procedure
  195. //can take.
  196. private Object applyPlus(ArrayList args, int min, int max) {
  197. int result = 0;
  198. if(args == null)
  199. return new SNumber(result);
  200. //validate number of arguments
  201. validateArgsSize(args.size(), min, max);
  202. for(int i=0; i < args.size(); i++) {
  203. Object o = args.get(i);
  204. if(o instanceof SNumber) {
  205. double d = ((SNumber)o).getValue();
  206. result += Double.valueOf(d).intValue();
  207. }
  208. else {
  209. throw new RuntimeException("invalid argument, not a number:" + o);
  210. }
  211. }
  212. return new SNumber(result);
  213. }
  214. private Object applyMinus(ArrayList args, int min, int max) {
  215. if (args == null) {
  216. throw new RuntimeException("must provide arguments");
  217. }
  218. //validate number of arguments
  219. validateArgsSize(args.size(), min, max);
  220. int result = 0;
  221. for(int i=0; i < args.size(); i++) {
  222. Object o = args.get(i);
  223. Utils.validateType(o, SNumber.class);
  224. double d = ((SNumber)o).getValue();
  225. if(i == 0 && args.size() > 1) {
  226. result = Double.valueOf(d).intValue();
  227. }
  228. else result -= Double.valueOf(d).intValue();
  229. }
  230. return new SNumber(result);
  231. }
  232. private Object applyMultiplication(ArrayList args, int min, int max) {
  233. int result = 1;
  234. if(args == null)
  235. return new SNumber(result);
  236. //validate number of arguments
  237. validateArgsSize(args.size(), min, max);
  238. for(int i=0; i < args.size(); i++) {
  239. Object o = args.get(i);
  240. if(o instanceof SNumber) {
  241. double d = ((SNumber)o).getValue();
  242. result *= Double.valueOf(d).intValue();
  243. }
  244. else {
  245. throw new RuntimeException("invalid argument, not a number:" + o);
  246. }
  247. }
  248. return new SNumber(result);
  249. }
  250. private Object applyDivision(ArrayList args, int min, int max) {
  251. int result = 1;
  252. if(args == null)
  253. throw new RuntimeException("must provide arguments");
  254. //validate number of arguments
  255. validateArgsSize(args.size(), min, max);
  256. for(int i=0; i < args.size(); i++) {
  257. Object o = args.get(i);
  258. if(o instanceof SNumber) {
  259. double d = ((SNumber)o).getValue();
  260. if(i == 0 && args.size() > 1)
  261. result = Double.valueOf(d).intValue();
  262. else
  263. result /= Double.valueOf(d).intValue();
  264. }
  265. else {
  266. throw new RuntimeException("invalid argument, not a number:" + o);
  267. }
  268. }
  269. return new SNumber(result);
  270. }
  271. private Object applyNot(ArrayList args, int min, int max) {
  272. if (args == null) {
  273. throw new RuntimeException("must provide arguments");
  274. }
  275. // validate number of arguments
  276. validateArgsSize(args.size(), min, max);
  277. return SBoolean.getInstance(!Utils.isTrue(args.get(0)));
  278. }
  279. private Object applyGreaterThan(ArrayList args, int min, int max) {
  280. if (args == null || args.size() == 1) {
  281. return SBoolean.getInstance(true);
  282. }
  283. // validate number of arguments
  284. validateArgsSize(args.size(), min, max);
  285. Object o = args.get(0);
  286. Utils.validateType(o, SNumber.class);
  287. double d = ((SNumber)o).getValue();
  288. for(int i = 1; i < args.size(); i++) {
  289. Object o2 = args.get(i);
  290. Utils.validateType(o2, SNumber.class);
  291. double d2 = ((SNumber)o2).getValue();
  292. if(d2 < d)
  293. d = d2;
  294. else
  295. return SBoolean.getInstance(false);
  296. }
  297. return SBoolean.getInstance(true);
  298. }
  299. private Object applyGreaterThanEqual(ArrayList args, int min, int max) {
  300. if (args == null || args.size() == 1) {
  301. return SBoolean.getInstance(true);
  302. }
  303. // validate number of arguments
  304. validateArgsSize(args.size(), min, max);
  305. Object o = args.get(0);
  306. Utils.validateType(o, SNumber.class);
  307. double d = ((SNumber)o).getValue();
  308. for(int i = 1; i < args.size(); i++) {
  309. Object o2 = args.get(i);
  310. Utils.validateType(o2, SNumber.class);
  311. double d2 = ((SNumber)o2).getValue();
  312. if(d2 <= d)
  313. d = d2;
  314. else
  315. return SBoolean.getInstance(false);
  316. }
  317. return SBoolean.getInstance(true);
  318. }
  319. private Object applyLessThan(ArrayList args, int min, int max) {
  320. if (args == null || args.size() == 1) {
  321. return SBoolean.getInstance(true);
  322. }
  323. // validate number of arguments
  324. validateArgsSize(args.size(), min, max);
  325. Object o = args.get(0);
  326. Utils.validateType(o, SNumber.class);
  327. double d = ((SNumber)o).getValue();
  328. for(int i = 1; i < args.size(); i++) {
  329. Object o2 = args.get(i);
  330. Utils.validateType(o2, SNumber.class);
  331. double d2 = ((SNumber)o2).getValue();
  332. if(d2 > d)
  333. d = d2;
  334. else
  335. return SBoolean.getInstance(false);
  336. }
  337. return SBoolean.getInstance(true);
  338. }
  339. private Object applyLessThanEqual(ArrayList args, int min, int max) {
  340. if (args == null || args.size() == 1) {
  341. return SBoolean.getInstance(true);
  342. }
  343. // validate number of arguments
  344. validateArgsSize(args.size(), min, max);
  345. Object o = args.get(0);
  346. Utils.validateType(o, SNumber.class);
  347. double d = ((SNumber)o).getValue();
  348. for(int i = 1; i < args.size(); i++) {
  349. Object o2 = args.get(i);
  350. Utils.validateType(o2, SNumber.class);
  351. double d2 = ((SNumber)o2).getValue();
  352. if(d2 >= d)
  353. d = d2;
  354. else
  355. return SBoolean.getInstance(false);
  356. }
  357. return SBoolean.getInstance(true);
  358. }
  359. private Object applyMakeString(ArrayList args, int min, int max) {
  360. if (args == null) {
  361. throw new RuntimeException("must provide arguments");
  362. }
  363. // validate number of arguments
  364. validateArgsSize(args.size(), min, max);
  365. Object o = args.get(0);
  366. Utils.validateType(o, SNumber.class);
  367. int len = (int)((SNumber)o).getValue();
  368. StringBuffer sb = new StringBuffer(len);
  369. char ch = ' ';
  370. if(args.size() > 1) {
  371. o = args.get(1);
  372. Utils.validateType(o, SChar.class);
  373. ch = ((SChar)o).getValue();
  374. }
  375. while(len-- > 0) {
  376. sb.append(ch);
  377. }
  378. return new SString(sb);
  379. }
  380. public Object applySymbolToString(ArrayList args, int min, int max) {
  381. if (args == null) {
  382. throw new RuntimeException("must provide arguments");
  383. }
  384. // validate number of arguments
  385. validateArgsSize(args.size(), min, max);
  386. Object o = args.get(0);
  387. Utils.validateType(o, SVariable.class);
  388. return new SString(((SVariable)o).getName());
  389. }
  390. public Object applyStringToSymbol(ArrayList args, int min, int max) {
  391. if (args == null) {
  392. throw new RuntimeException("must provide arguments");
  393. }
  394. // validate number of arguments
  395. validateArgsSize(args.size(), min, max);
  396. Object o = args.get(0);
  397. Utils.validateType(o, SString.class);
  398. return SVariable.getInstance(((SString)o).getValue().toString());
  399. }
  400. public Object applyStringLength(ArrayList args, int min, int max) {
  401. if (args == null) {
  402. throw new RuntimeException("must provide arguments");
  403. }
  404. // validate number of arguments
  405. validateArgsSize(args.size(), min, max);
  406. Object o = args.get(0);
  407. Utils.validateType(o, SString.class);
  408. return new SNumber(((SString)o).getValue().length());
  409. }
  410. public Object applyStringRef(ArrayList args, int min, int max) {
  411. if (args == null) {
  412. throw new RuntimeException("must provide arguments");
  413. }
  414. // validate number of arguments
  415. validateArgsSize(args.size(), min, max);
  416. Object o1 = args.get(0);
  417. Object o2 = args.get(1);
  418. Utils.validateType(o1, SString.class);
  419. Utils.validateType(o2, SNumber.class);
  420. return new SChar(((SString)o1).getValue().
  421. charAt(Double.valueOf(((SNumber)o2).getValue()).intValue()));
  422. }
  423. public Object applyStringSet(ArrayList args, int min, int max) {
  424. if (args == null) {
  425. throw new RuntimeException("must provide arguments");
  426. }
  427. // validate number of arguments
  428. validateArgsSize(args.size(), min, max);
  429. Object o1 = args.get(0);
  430. Object o2 = args.get(1);
  431. Object o3 = args.get(2);
  432. Utils.validateType(o1, SString.class);
  433. Utils.validateType(o2, SNumber.class);
  434. Utils.validateType(o3, SChar.class);
  435. StringBuffer sb = ((SString)o1).getValue();
  436. int i = Double.valueOf(((SNumber)o2).getValue()).intValue();
  437. char c = ((SChar)o3).getValue();
  438. //set c at i in sb
  439. sb.setCharAt(i, c);
  440. return SUndefined.getInstance();
  441. }
  442. public Object applyNumberToString(ArrayList args, int min, int max) {
  443. if (args == null) {
  444. throw new RuntimeException("must provide arguments");
  445. }
  446. // validate number of arguments
  447. validateArgsSize(args.size(), min, max);
  448. Object o = args.get(0);
  449. Utils.validateType(o, SNumber.class);
  450. double d = ((SNumber)o).getValue();
  451. return new SString(Integer.toString(Double.valueOf(d).intValue()));
  452. }
  453. public Object applyStringToNumber(ArrayList args, int min, int max) {
  454. if (args == null) {
  455. throw new RuntimeException("must provide arguments");
  456. }
  457. // validate number of arguments
  458. validateArgsSize(args.size(), min, max);
  459. Object o = args.get(0);
  460. Utils.validateType(o, SString.class);
  461. String s = ((SString)o).getValue().toString();
  462. try {
  463. return new SNumber(Integer.parseInt(s));
  464. }
  465. catch(NumberFormatException ex) {
  466. return SBoolean.getInstance(false);
  467. }
  468. }
  469. public Object applyCharUpCase(ArrayList args, int min, int max) {
  470. if (args == null) {
  471. throw new RuntimeException("must provide arguments");
  472. }
  473. // validate number of arguments
  474. validateArgsSize(args.size(), min, max);
  475. Object o = args.get(0);
  476. Utils.validateType(o, SChar.class);
  477. char c = ((SChar)o).getValue();
  478. if(Character.isLowerCase(c))
  479. return new SChar(Character.toUpperCase(c));
  480. else return o;
  481. }
  482. public Object applyCharDownCase(ArrayList args, int min, int max) {
  483. if (args == null) {
  484. throw new RuntimeException("must provide arguments");
  485. }
  486. // validate number of arguments
  487. validateArgsSize(args.size(), min, max);
  488. Object o = args.get(0);
  489. Utils.validateType(o, SChar.class);
  490. char c = ((SChar)o).getValue();
  491. if(Character.isUpperCase(c))
  492. return new SChar(Character.toLowerCase(c));
  493. else return o;
  494. }
  495. public Object applyCharLess(ArrayList args, int min, int max) {
  496. if (args == null) {
  497. throw new RuntimeException("must provide arguments");
  498. }
  499. // validate number of arguments
  500. validateArgsSize(args.size(), min, max);
  501. Object o1 = args.get(0);
  502. Object o2 = args.get(1);
  503. Utils.validateType(o1, SChar.class);
  504. Utils.validateType(o2, SChar.class);
  505. Character c1 = Character.valueOf(((SChar)o1).getValue());
  506. Character c2 = Character.valueOf(((SChar)o2).getValue());
  507. return SBoolean.getInstance(c1.compareTo(c2) < 0);
  508. }
  509. public Object applyCharPredAlphabetic(ArrayList args, int min, int max) {
  510. if (args == null) {
  511. throw new RuntimeException("must provide arguments");
  512. }
  513. // validate number of arguments
  514. validateArgsSize(args.size(), min, max);
  515. Object o = args.get(0);
  516. Utils.validateType(o, SChar.class);
  517. char c = ((SChar)o).getValue();
  518. return SBoolean.getInstance(Character.isLetter(c));
  519. }
  520. public Object applyCharPredNumeric(ArrayList args, int min, int max) {
  521. if (args == null) {
  522. throw new RuntimeException("must provide arguments");
  523. }
  524. // validate number of arguments
  525. validateArgsSize(args.size(), min, max);
  526. Object o = args.get(0);
  527. Utils.validateType(o, SChar.class);
  528. char c = ((SChar)o).getValue();
  529. return SBoolean.getInstance(Character.isDigit(c));
  530. }
  531. public Object applyCharPredWhitespace(ArrayList args, int min, int max) {
  532. if (args == null) {
  533. throw new RuntimeException("must provide arguments");
  534. }
  535. // validate number of arguments
  536. validateArgsSize(args.size(), min, max);
  537. Object o = args.get(0);
  538. Utils.validateType(o, SChar.class);
  539. char c = ((SChar)o).getValue();
  540. return SBoolean.getInstance(Character.isWhitespace(c));
  541. }
  542. public Object applyCharPredLowerCase(ArrayList args, int min, int max) {
  543. if (args == null) {
  544. throw new RuntimeException("must provide arguments");
  545. }
  546. // validate number of arguments
  547. validateArgsSize(args.size(), min, max);
  548. Object o = args.get(0);
  549. Utils.validateType(o, SChar.class);
  550. char c = ((SChar)o).getValue();
  551. return SBoolean.getInstance(Character.isLowerCase(c));
  552. }
  553. public Object applyCharPredUpperCase(ArrayList args, int min, int max) {
  554. if (args == null) {
  555. throw new RuntimeException("must provide arguments");
  556. }
  557. // validate number of arguments
  558. validateArgsSize(args.size(), min, max);
  559. Object o = args.get(0);
  560. Utils.validateType(o, SChar.class);
  561. char c = ((SChar)o).getValue();
  562. return SBoolean.getInstance(Character.isUpperCase(c));
  563. }
  564. private Object applyPredEq(ArrayList args, int min, int max) {
  565. if (args == null) {
  566. throw new RuntimeException("must provide arguments");
  567. }
  568. // validate number of arguments
  569. validateArgsSize(args.size(), min, max);
  570. return SBoolean.getInstance(args.get(0) == args.get(1));
  571. }
  572. private Object applyPredEqv(ArrayList args, int min, int max) {
  573. if (args == null) {
  574. throw new RuntimeException("must provide arguments");
  575. }
  576. // validate number of arguments
  577. validateArgsSize(args.size(), min, max);
  578. Object o1 = args.get(0);
  579. Object o2 = args.get(1);
  580. return SBoolean.getInstance(checkEqv(o1,o2));
  581. }
  582. private Object applyPredEqual(ArrayList args, int min, int max) {
  583. if (args == null) {
  584. throw new RuntimeException("must provide arguments");
  585. }
  586. // validate number of arguments
  587. validateArgsSize(args.size(), min, max);
  588. Object o1 = args.get(0);
  589. Object o2 = args.get(1);
  590. return SBoolean.getInstance(checkEqual(o1, o2));
  591. }
  592. //checks if two objects should return #t for eqv?
  593. //on o1 and o2
  594. private boolean checkEqv(Object o1, Object o2) {
  595. //this takes care of both being #t or #f or same symbol
  596. //or both being empty list
  597. if(o1 == o2) return true;
  598. //false if they're not of same type
  599. if(o1.getClass() != o2.getClass()) return false;
  600. //true if they're chars with same value
  601. if(o1 instanceof SChar)
  602. return ((SChar)o1).getValue() == ((SChar)o2).getValue();
  603. //true if they're numbers with same numeric value
  604. if(o1 instanceof SNumber)
  605. return ((SNumber)o1).getValue() == ((SNumber)o2).getValue();
  606. //true if they're both strings with same string value
  607. if(o1 instanceof SString)
  608. return ((SString)o1).getValue().toString().equals(((SString)o2).getValue().toString());
  609. //todo:
  610. //true if they're procedures or pairs having same location
  611. //if nothing then false
  612. return false;
  613. }
  614. //checks if two objects should return #t for equal?
  615. //on o1 and o2
  616. private boolean checkEqual(Object o1, Object o2) {
  617. if(o1.getClass() == o2.getClass() && o1 instanceof SPair) {
  618. SPair sp1 = (SPair)o1;
  619. SPair sp2 = (SPair)o2;
  620. while(true) {
  621. o1 = sp1.getCar();
  622. o2 = sp2.getCar();
  623. if(!checkEqual(o1,o2)) return false;
  624. o1 = sp1.getCdr();
  625. o2 = sp1.getCdr();
  626. if(!(o1 instanceof SPair && o2 instanceof SPair))
  627. return checkEqv(o1,o2);
  628. else {
  629. sp1 = (SPair)o1;
  630. sp2 = (SPair)o2;
  631. }
  632. }
  633. }
  634. else return checkEqv(o1, o2);
  635. }
  636. private Object applyRead() {
  637. //todo: may be we should get reader set for this class
  638. return Main.reader.read();
  639. }
  640. private Object applyEval(ArrayList args, int min, int max, Environment env) {
  641. if (args == null) {
  642. throw new RuntimeException("must provide arguments");
  643. }
  644. // validate number of arguments
  645. validateArgsSize(args.size(), min, max);
  646. if(args.size() > 1)
  647. env = (Environment)args.get(1);
  648. return Scheme.eval(args.get(0), env);
  649. }
  650. private Object applyApply(ArrayList args, int min, int max, Environment env) {
  651. if (args == null) {
  652. throw new RuntimeException("must provide arguments");
  653. }
  654. // validate number of arguments
  655. validateArgsSize(args.size(), min, max);
  656. Object proc = args.get(0);
  657. Utils.validateType(proc, Procedure.class);
  658. if(args.size() > 0) {
  659. Object argsList = args.get(1);
  660. if(argsList instanceof SPair) {
  661. ArrayList arr = new ArrayList();
  662. while(argsList instanceof SPair) {
  663. arr.add(Utils.car(argsList));
  664. argsList = Utils.cdr(argsList);
  665. }
  666. return ((Procedure)proc).apply(arr, env);
  667. }
  668. }
  669. return ((Procedure)proc).apply(null, env);
  670. }
  671. private Object applyError(ArrayList args, int min, int max) {
  672. if (args == null) {
  673. throw new RuntimeException("must provide arguments");
  674. }
  675. // validate number of arguments
  676. validateArgsSize(args.size(), min, max);
  677. throw new RuntimeException(args.get(0).toString());
  678. }
  679. private Object applyInteractionEnvironment(ArrayList args, int min, int max) {
  680. if(args != null) {
  681. // validate number of arguments
  682. validateArgsSize(args.size(), min, max);
  683. }
  684. return Environment.getGlobalEnvironment();
  685. }
  686. //args should be array-list containing two elements, first is the object
  687. //to be printed and second is the port.
  688. //NOTE: port functionality is not supported, output goes automatically to
  689. //standard output
  690. private Object applyDisplay(ArrayList args, int min, int max) {
  691. if (args == null) {
  692. throw new RuntimeException("must provide arguments");
  693. }
  694. // validate number of arguments
  695. validateArgsSize(args.size(), min, max);
  696. System.out.print(args.get(0));
  697. return SUndefined.getInstance();
  698. }
  699. //args should be array-list containing two elements, first is the object
  700. //to be printed and second is the port.
  701. //NOTE: port functionality is not supported, output goes automatically to
  702. //standard output
  703. private Object applyWrite(ArrayList args, int min, int max) {
  704. if (args == null) {
  705. throw new RuntimeException("must provide arguments");
  706. }
  707. // validate number of arguments
  708. validateArgsSize(args.size(), min, max);
  709. String s = args.get(0).toString();
  710. //s = s.replaceAll("\\", "\\\\");
  711. //s = s.replaceAll("#\\", "#");
  712. //s = s.replaceAll("\"", "\\\"");
  713. System.out.print(s);
  714. return SUndefined.getInstance();
  715. }
  716. private Object applyNewline() {
  717. System.out.println("");
  718. return SUndefined.getInstance();
  719. }
  720. private Object applyCons(ArrayList args, int min, int max) {
  721. if (args == null) {
  722. throw new RuntimeException("must provide arguments");
  723. }
  724. // validate number of arguments
  725. validateArgsSize(args.size(), min, max);
  726. return Utils.cons(args.get(0), args.get(1));
  727. }
  728. private Object applyCar(ArrayList args, int min, int max) {
  729. if (args == null) {
  730. throw new RuntimeException("must provide arguments");
  731. }
  732. // validate number of arguments
  733. validateArgsSize(args.size(), min, max);
  734. return Utils.car(args.get(0));
  735. }
  736. private Object applyCdr(ArrayList args, int min, int max) {
  737. if (args == null) {
  738. throw new RuntimeException("must provide arguments");
  739. }
  740. // validate number of arguments
  741. validateArgsSize(args.size(), min, max);
  742. return Utils.cdr(args.get(0));
  743. }
  744. private Object applySetCar(ArrayList args, int min, int max) {
  745. if (args == null) {
  746. throw new RuntimeException("must provide arguments");
  747. }
  748. // validate number of arguments
  749. validateArgsSize(args.size(), min, max);
  750. Object oPair = args.get(0);
  751. Object oItem = args.get(1);
  752. Utils.validateType(oPair, SPair.class);
  753. SPair p = (SPair)oPair;
  754. p.setCar(oItem);
  755. return SUndefined.getInstance();
  756. }
  757. private Object applySetCdr(ArrayList args, int min, int max) {
  758. if (args == null) {
  759. throw new RuntimeException("must provide arguments");
  760. }
  761. // validate number of arguments
  762. validateArgsSize(args.size(), min, max);
  763. Object oPair = args.get(0);
  764. Object oItem = args.get(1);
  765. Utils.validateType(oPair, SPair.class);
  766. SPair p = (SPair)oPair;
  767. p.setCdr(oItem);
  768. return SUndefined.getInstance();
  769. }
  770. private Object applyList(ArrayList args, int min, int max) {
  771. if(args != null && args.size() > 0) {
  772. int len = args.size();
  773. SPair result = new SPair();
  774. SPair tmp = result;
  775. for(int i=0; i<len; i++) {
  776. tmp.setCar(args.get(i));
  777. if(i == len-1) {
  778. tmp.setCdr(SEmptyList.getInstance());
  779. }
  780. else {
  781. SPair sp = new SPair();
  782. tmp.setCdr(sp);
  783. tmp = sp;
  784. }
  785. }
  786. return result;
  787. }
  788. else return SEmptyList.getInstance();
  789. }
  790. private Object applyPredPair(ArrayList args, int min, int max) {
  791. if (args == null) {
  792. throw new RuntimeException("must provide arguments");
  793. }
  794. // validate number of arguments
  795. validateArgsSize(args.size(), min, max);
  796. return SBoolean.getInstance((args.get(0) instanceof SPair));
  797. }
  798. private Object applyPredBoolean(ArrayList args, int min, int max) {
  799. if (args == null) {
  800. throw new RuntimeException("must provide arguments");
  801. }
  802. // validate number of arguments
  803. validateArgsSize(args.size(), min, max);
  804. return SBoolean.getInstance((args.get(0) instanceof SBoolean));
  805. }
  806. private Object applyPredChar(ArrayList args, int min, int max) {
  807. if (args == null) {
  808. throw new RuntimeException("must provide arguments");
  809. }
  810. // validate number of arguments
  811. validateArgsSize(args.size(), min, max);
  812. return SBoolean.getInstance((args.get(0) instanceof SChar));
  813. }
  814. private Object applyPredString(ArrayList args, int min, int max) {
  815. if (args == null) {
  816. throw new RuntimeException("must provide arguments");
  817. }
  818. // validate number of arguments
  819. validateArgsSize(args.size(), min, max);
  820. return SBoolean.getInstance((args.get(0) instanceof SString));
  821. }
  822. private Object applyPredSymbol(ArrayList args, int min, int max) {
  823. if (args == null) {
  824. throw new RuntimeException("must provide arguments");
  825. }
  826. // validate number of arguments
  827. validateArgsSize(args.size(), min, max);
  828. return SBoolean.getInstance((args.get(0) instanceof SVariable));
  829. }
  830. private Object applyPredNumber(ArrayList args, int min, int max) {
  831. if (args == null) {
  832. throw new RuntimeException("must provide arguments");
  833. }
  834. // validate number of arguments
  835. validateArgsSize(args.size(), min, max);
  836. return SBoolean.getInstance((args.get(0) instanceof SNumber));
  837. }
  838. private Object applyPredProcedure(ArrayList args, int min, int max) {
  839. if (args == null) {
  840. throw new RuntimeException("must provide arguments");
  841. }
  842. // validate number of arguments
  843. validateArgsSize(args.size(), min, max);
  844. return SBoolean.getInstance((args.get(0) instanceof Procedure));
  845. }
  846. private Object applyPredList(ArrayList args, int min, int max) {
  847. if (args == null) {
  848. throw new RuntimeException("must provide arguments");
  849. }
  850. // validate number of arguments
  851. validateArgsSize(args.size(), min, max);
  852. return SBoolean.getInstance(Utils.isSchemeList(args.get(0)));
  853. }
  854. private Object applyPredNull(ArrayList args, int min, int max) {
  855. if (args == null) {
  856. throw new RuntimeException("must provide arguments");
  857. }
  858. // validate number of arguments
  859. validateArgsSize(args.size(), min, max);
  860. return SBoolean.getInstance((args.get(0) instanceof SEmptyList));
  861. }
  862. //validates if min <= size <= max.
  863. //max < 0 is treated as infinity.
  864. private void validateArgsSize(int size, int min, int max) {
  865. if(size < min || (size > max && max >= 0))
  866. throw new RuntimeException("argument list size is not valid.");
  867. }
  868. public String toString() {
  869. return "#<Primitive-Procedure>#";
  870. }
  871. }