LispElement.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package migl.lisp;
  2. import java.math.BigInteger;
  3. import java.util.Map;
  4. import migl.util.Cons;
  5. import java.util.HashMap;
  6. /**
  7. * Class pour gérer les élément des expressions Lisp
  8. *
  9. * @author Arthur Brandao
  10. */
  11. public class LispElement {
  12. /**
  13. * Garde en cache les elements deja créer pour eviter de recreer plusieurs fois les meme elements
  14. */
  15. private static Map<Object, LispElement> cache = new HashMap<>();
  16. /**
  17. * La valeur de l'element
  18. */
  19. private final Object value;
  20. /**
  21. * Constructeur privée pour construire un element à partir de valueOf
  22. *
  23. * @param val
  24. */
  25. private LispElement(Object val) {
  26. this.value = val;
  27. cache.put(val, this);
  28. }
  29. /**
  30. * Retourne la valeur de l'element lisp
  31. * @return
  32. */
  33. public Object getValue() {
  34. return this.value;
  35. }
  36. /**
  37. * Retourne la valeur d'un element sous forme d'entier
  38. *
  39. * @throws IllegalStateException Si l'element ne peut pas être converti en BigInteger
  40. * @return
  41. */
  42. public BigInteger toInt() {
  43. if(this.isInt()) {
  44. return (BigInteger) this.value;
  45. }
  46. throw new IllegalStateException("Not an integer");
  47. }
  48. /**
  49. * Retourne la valeur d'un element sous forme de nombre
  50. *
  51. * @throws IllegalStateException Si l'element ne peut pas être converti en Double
  52. * @return
  53. */
  54. public double toNumber() {
  55. if(this.value.getClass() == BigInteger.class) {
  56. BigInteger bi = (BigInteger) this.value;
  57. return bi.doubleValue();
  58. } else if(this.value.getClass() == Double.class) {
  59. return (Double) this.value;
  60. }
  61. throw new IllegalStateException("Not a number");
  62. }
  63. /**
  64. * Retourne la valeur d'un element sous forme de boolean
  65. *
  66. * @throws IllegalStateException Si l'element ne peut pas être converti en boolean
  67. * @return
  68. */
  69. public boolean toBoolean() {
  70. if(this.isBoolean()) {
  71. LispBoolean lb = (LispBoolean) this.value;
  72. return lb.value();
  73. }
  74. throw new IllegalStateException("Not a Boolean");
  75. }
  76. /**
  77. * Retourne la valeur d'un element sous forme de string
  78. *
  79. * @throws IllegalStateException Si l'element ne peut pas être converti en String
  80. * @return
  81. */
  82. public String toStr() {
  83. if(this.isStr()) {
  84. return (String) this.value;
  85. }
  86. throw new IllegalStateException("Not a String");
  87. }
  88. /**
  89. * Retourne la valeur d'un element sous forme d'une liste
  90. *
  91. * @throws IllegalStateException
  92. * @return
  93. */
  94. public LispList toList() {
  95. if(this.isList()) {
  96. return (LispList) this.value;
  97. }
  98. throw new IllegalStateException("Not a List");
  99. }
  100. /**
  101. * Retourne la valeur d'un element sous forme d'une cons
  102. *
  103. * @throws IllegalStateException
  104. * @return
  105. */
  106. public Cons<?, ?> toCons() {
  107. if(this.isCons()) {
  108. return (Cons<?, ?>) this.value;
  109. }
  110. throw new IllegalStateException("Not a Cons");
  111. }
  112. /**
  113. * Indique si l'element est un entier
  114. * @return
  115. */
  116. public boolean isInt() {
  117. return this.value.getClass() == BigInteger.class;
  118. }
  119. /**
  120. * Indique si l'element est nombre (BigInteger ou Double)
  121. * @return
  122. */
  123. public boolean isNumber() {
  124. return this.isInt() || (this.value.getClass() == Double.class);
  125. }
  126. /**
  127. * Indique si l'element est boolean
  128. * @return
  129. */
  130. public boolean isBoolean() {
  131. return this.value.getClass() == LispBoolean.class;
  132. }
  133. /**
  134. * Indique si l'element est un String
  135. * @return
  136. */
  137. public boolean isStr() {
  138. return this.value.getClass() == String.class;
  139. }
  140. /**
  141. * Indique si l'element est une liste
  142. * @return
  143. */
  144. public boolean isList() {
  145. return this.value.getClass() == LispList.class;
  146. }
  147. /**
  148. * Indique si l'element est une Cons
  149. * @return
  150. */
  151. public boolean isCons() {
  152. return this.value.getClass() == Cons.class;
  153. }
  154. @Override
  155. public int hashCode() {
  156. return this.value.hashCode();
  157. }
  158. @Override
  159. public boolean equals(Object obj) {
  160. if(obj == null) {
  161. return false;
  162. } else if(this == obj) {
  163. return true;
  164. } else if(obj instanceof LispElement) {
  165. LispElement other = (LispElement) obj;
  166. return this.value.equals(other.value);
  167. }
  168. return false;
  169. }
  170. @Override
  171. public String toString() {
  172. return this.value.toString();
  173. }
  174. /**
  175. * Indique le nombre actuel d'element en cache
  176. * @return
  177. */
  178. public static int getCacheSize() {
  179. return cache.size();
  180. }
  181. /**
  182. * Supprime le cache
  183. */
  184. public static void clear() {
  185. cache.clear();
  186. }
  187. /**
  188. * Parse un element
  189. *
  190. * @param elt L'element à parser
  191. * @return Un LispElement contenant la valeur extraite
  192. */
  193. public static LispElement valueOf(String elt) {
  194. try {
  195. return generate(new BigInteger(elt));
  196. } catch(NumberFormatException ex) {
  197. //Rien
  198. }
  199. try {
  200. return generate(Double.valueOf(elt));
  201. } catch(NumberFormatException ex) {
  202. //Rien
  203. }
  204. try {
  205. return generate(LispBoolean.valueOf(elt));
  206. } catch(IllegalArgumentException ex) {
  207. //Rien
  208. }
  209. return generate(elt);
  210. }
  211. /**
  212. * Genere un LispElement correspondant à l'objet
  213. *
  214. * @param elt
  215. * @return
  216. */
  217. public static LispElement generate(Object elt) {
  218. if(elt == null) {
  219. return new LispElement(null);
  220. }
  221. else if(elt.getClass() == LispElement.class) {
  222. return (LispElement) elt;
  223. }
  224. else if(elt.getClass() == Integer.class) {
  225. elt = BigInteger.valueOf((Integer) elt);
  226. }
  227. else if(elt.getClass() == Boolean.class) {
  228. elt = LispBoolean.valueOf((boolean) elt);
  229. }
  230. else if(elt.getClass() == Long.class) {
  231. elt = BigInteger.valueOf((long) elt);
  232. }
  233. else if(
  234. elt.getClass() != BigInteger.class
  235. && elt.getClass() != Double.class
  236. && elt.getClass() != LispBoolean.class
  237. && elt.getClass() != String.class
  238. && elt.getClass() != LispList.class
  239. && elt.getClass() != Cons.class
  240. ) {
  241. throw new IllegalArgumentException("Object class is not a Lisp element");
  242. }
  243. if(cache.containsKey(elt)) {
  244. return cache.get(elt);
  245. }
  246. return new LispElement(elt);
  247. }
  248. }