IfFeature.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. package kawa.standard;
  2. import kawa.lang.*;
  3. import kawa.Version;
  4. import gnu.expr.*;
  5. import gnu.lists.ImmutablePair;
  6. import gnu.lists.LList;
  7. import gnu.lists.Pair;
  8. import gnu.mapping.Symbol;
  9. import gnu.mapping.SimpleSymbol;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. import java.util.Locale;
  13. import java.nio.ByteOrder;
  14. /** Implements the Scheme 'cond-expand' syntax.
  15. * Also provides various static methods relating to "features".
  16. */
  17. public class IfFeature extends Syntax {
  18. public static final IfFeature condExpand = new IfFeature();
  19. static { condExpand.setName("cond-expand"); }
  20. @Override
  21. public void scanForm(Pair st, ScopeExp defs, Translator tr) {
  22. Object forms = evaluate(st.getCdr(), tr);
  23. tr.scanBody(forms, defs, false);
  24. }
  25. public Expression rewriteForm(Pair form, Translator tr) {
  26. Object forms = evaluate(form.getCdr(), tr);
  27. return tr.rewrite_body(forms);
  28. }
  29. public boolean evaluateConditionCar(Pair pair, Translator tr) {
  30. Object save = tr.pushPositionOf(pair);
  31. boolean r = evaluateCondition(pair.getCar(), tr);
  32. tr.popPositionOf(save);
  33. return r;
  34. }
  35. public boolean evaluateCondition(Object form, Translator tr) {
  36. form = tr.namespaceResolve(Translator.stripSyntax(form));
  37. if (form instanceof String || form instanceof SimpleSymbol)
  38. return hasFeature(form.toString());
  39. if (form instanceof Pair) {
  40. Pair pair = (Pair) form;
  41. Object keyword = Translator.stripSyntax(pair.getCar());
  42. if (keyword == orSymbol || keyword == andSymbol) {
  43. Object rest = pair.getCdr();
  44. while (rest instanceof Pair) {
  45. pair = (Pair) rest;
  46. boolean val = evaluateConditionCar(pair, tr);
  47. if (val == (keyword == orSymbol))
  48. return val;
  49. rest = pair.getCdr();
  50. }
  51. tr.errorIfNonEmpty(rest);
  52. return keyword == andSymbol;
  53. }
  54. if (keyword == notSymbol) {
  55. Object rest = pair.getCdr();
  56. if (rest instanceof Pair) {
  57. Pair pair2 = (Pair) rest;
  58. if (pair2.getCdr() == LList.Empty)
  59. return ! evaluateConditionCar(pair2, tr);
  60. }
  61. tr.errorWithPosition("'not' must be followed by a single condition", pair);
  62. return false;
  63. }
  64. if (keyword == librarySymbol) {
  65. Object rest = pair.getCdr();
  66. if (rest instanceof Pair) {
  67. Pair pair2 = (Pair) rest;
  68. if (pair2.getCdr() == LList.Empty)
  69. return ImportFromLibrary.instance
  70. .libraryExists(pair2.getCar(), tr);
  71. }
  72. tr.errorWithPosition("'library' must be followed by <library name>", pair);
  73. return false;
  74. }
  75. }
  76. tr.error('e', "unrecognized cond-expand expression");
  77. return false;
  78. }
  79. public Object evaluate(Object clauses, Translator tr) {
  80. while (clauses instanceof Pair) {
  81. Pair pclauses = (Pair) clauses;
  82. Object clause = pclauses.getCar();
  83. clauses = pclauses.getCdr();
  84. if (! (clause instanceof Pair))
  85. tr.errorWithPosition("cond-expand clauses is not a list",
  86. pclauses);
  87. Pair pclause = (Pair) clause;
  88. Object test = Translator.stripSyntax(pclause.getCar());
  89. if ((test == elseSymbol && clauses == LList.Empty)
  90. || evaluateConditionCar(pclause, tr))
  91. return pclause.getCdr();
  92. }
  93. tr.errorIfNonEmpty(clauses);
  94. return LList.Empty;
  95. }
  96. private static List<String> coreFeatures = new ArrayList<String>();
  97. private static void addCoreFeature(String feature) {
  98. coreFeatures.add(feature.intern());
  99. }
  100. static {
  101. addCoreFeature("kawa");
  102. addCoreFeature("kawa-"+Version.getVersion());
  103. addCoreFeature("complex");
  104. addCoreFeature("exact-complex");
  105. addCoreFeature("exact-closed");
  106. addCoreFeature("ieee-float");
  107. addCoreFeature("ratios");
  108. addCoreFeature("full-unicode");
  109. String javaVersion = System.getProperty("java.version");
  110. if (javaVersion != null && javaVersion.length() >= 1) {
  111. if (javaVersion.length() >= 3
  112. && javaVersion.charAt(0) == '1'
  113. && javaVersion.charAt(1) == '.')
  114. javaVersion = javaVersion.substring(2);
  115. int dot = javaVersion.indexOf('.');
  116. if (dot >= 0)
  117. javaVersion = javaVersion.substring(0, dot);
  118. int version;
  119. int minVersion = 6;
  120. try {
  121. version = Integer.parseInt(javaVersion);
  122. if (version > 20) { // sanity check
  123. addCoreFeature("java-"+version);
  124. version = 11;
  125. }
  126. } catch (Throwable ex) {
  127. version = 0;
  128. }
  129. for (int i = minVersion; i <= version; i++) {
  130. addCoreFeature("java-"+i);
  131. }
  132. }
  133. if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
  134. addCoreFeature("big-endian");
  135. else
  136. addCoreFeature("little-endian");
  137. String osName =
  138. System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
  139. // FIXME check for cygwin, bsd
  140. if (osName.indexOf("linux") >= 0) {
  141. addCoreFeature("posix");
  142. addCoreFeature("unix");
  143. addCoreFeature("linux");
  144. addCoreFeature("gnu-linux");
  145. }
  146. else if (osName.indexOf("win") >= 0) {
  147. addCoreFeature("windows");
  148. } else if (osName.indexOf("sunos") >= 0
  149. || osName.indexOf("solaris") >= 0) {
  150. addCoreFeature("posix");
  151. addCoreFeature("unix");
  152. addCoreFeature("solaris");
  153. } else if (osName.indexOf("mac") >= 0
  154. || osName.indexOf("darwin") >= 0) {
  155. addCoreFeature("posix");
  156. addCoreFeature("unix");
  157. addCoreFeature("darwin");
  158. addCoreFeature("macosx");
  159. } else if (osName.indexOf("bsd") >= 0) {
  160. addCoreFeature("bsd");
  161. addCoreFeature("posix");
  162. addCoreFeature("unix");
  163. } else if (osName.indexOf("nix") >= 0
  164. || osName.indexOf("nux") >= 0
  165. || osName.indexOf("aix") > 0) {
  166. addCoreFeature("posix");
  167. addCoreFeature("unix");
  168. }
  169. String archName =
  170. System.getProperty("os.arch").toLowerCase(Locale.ENGLISH);;
  171. if (archName.indexOf("amd64") >= 0
  172. || archName.indexOf("x86_64") >= 0) {
  173. addCoreFeature("x86-64");
  174. } else if (archName.indexOf("x86") >= 0
  175. || archName.indexOf("i386") >= 0) {
  176. addCoreFeature("i386");
  177. } else if (archName.indexOf("ppc") >= 0
  178. || archName.indexOf("powerpc") >= 0) {
  179. addCoreFeature("ppc");
  180. } else if (archName.indexOf("sparc") >= 0) {
  181. addCoreFeature("sparc");
  182. }
  183. addCoreFeature("jvm");
  184. addCoreFeature("r7rs");
  185. addCoreFeature("srfi-0"); // cond-expand
  186. // addCoreFeature("srfi-1"); // lists - only if require used.
  187. //if (name == "srfi-1") return true; // lists
  188. addCoreFeature("srfi-4"); // Homogeneous numeric vector datatypes
  189. addCoreFeature("srfi-6"); // Basic String Ports
  190. addCoreFeature("srfi-8"); // receive: Binding to multiple values
  191. addCoreFeature("srfi-9"); // Defining Record Types
  192. addCoreFeature("srfi-11"); // let-values, let*-values
  193. addCoreFeature("srfi-16"); // case-lambda
  194. addCoreFeature("srfi-17"); // Generalized set!
  195. addCoreFeature("srfi-23"); // Error reporting mechanism
  196. addCoreFeature("srfi-25"); // Multi-dimensional Array Primitives
  197. addCoreFeature("srfi-26"); // Notation for Specializing Parameters
  198. addCoreFeature("srfi-28"); // Basic Format Strings
  199. addCoreFeature("srfi-30"); // Nested Multi-line Comments.
  200. addCoreFeature("srfi-39"); // Parameter objects
  201. /* #ifdef use:java.text.Normalizer */
  202. /* #ifdef JAVA6COMPAT5 */
  203. // try {
  204. // Class.forName("java.text.Normalizer");
  205. // addCoreFeature("string-normalize-unicode");
  206. // }
  207. // catch (ClassNotFoundException ex) {
  208. // }
  209. /* #else */
  210. addCoreFeature("string-normalize-unicode");
  211. /* #endif */
  212. /* #endif */
  213. addCoreFeature("threads");
  214. }
  215. /** Check if we implement a named feature.
  216. * @param name an interned feature name
  217. */
  218. public static boolean hasFeature (String name) {
  219. for (int i = coreFeatures.size(); --i>= 0; ) {
  220. if (name == coreFeatures.get(i))
  221. return true;
  222. }
  223. if (name == "in-http-server" || name == "in-servlet") {
  224. int mflags = ModuleContext.getContext().getFlags();
  225. if (name == "in-http-server")
  226. return (mflags & ModuleContext.IN_HTTP_SERVER) != 0;
  227. if (name == "in-servlet")
  228. return (mflags & ModuleContext.IN_SERVLET) != 0
  229. || Compilation.getCurrent().generatingServlet();
  230. }
  231. String classExistsPrefix = "class-exists:";
  232. if (name.startsWith(classExistsPrefix)) {
  233. name = name.substring(classExistsPrefix.length());
  234. try {
  235. Class.forName(name, false, IfFeature.class.getClassLoader());
  236. return true;
  237. } catch (ClassNotFoundException ex) {
  238. return false;
  239. }
  240. }
  241. Symbol provide_symbol = Symbol.valueOf(PROVIDE_PREFIX+name);
  242. Declaration decl = Compilation.getCurrent().lookup(provide_symbol, -1);
  243. if (decl!=null && ! decl.getFlag(Declaration.IS_UNKNOWN))
  244. return true;
  245. return false;
  246. }
  247. /** Return a (partial) list of features,
  248. * The result does not include "provide" feature names - though it should.
  249. * Feature names of the form class:CLASSNAME are not returned.
  250. */
  251. public static LList featureList() {
  252. LList result = LList.Empty;
  253. for (int i = coreFeatures.size(); --i>= 0; ) {
  254. String item = coreFeatures.get(i);
  255. result = new ImmutablePair(Symbol.valueOf(item), result);
  256. }
  257. return result;
  258. }
  259. public static final String PROVIDE_PREFIX = "%provide%";
  260. public static boolean isProvide(Declaration decl) {
  261. String name = decl.getName();
  262. return name == null ? false : name.startsWith(PROVIDE_PREFIX);
  263. }
  264. public static final SimpleSymbol andSymbol = Symbol.valueOf("and");
  265. public static final SimpleSymbol elseSymbol = Symbol.valueOf("else");
  266. public static final SimpleSymbol librarySymbol = Symbol.valueOf("library");
  267. public static final SimpleSymbol notSymbol = Symbol.valueOf("not");
  268. public static final SimpleSymbol orSymbol = Symbol.valueOf("or");
  269. }