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