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