package sisc.util;
import java.util.*;
import java.security.AccessControlException;
import java.text.*;
import java.net.*;
import sisc.compiler.*;
import sisc.data.*;
import sisc.env.SymbolicEnvironment;
import sisc.exprs.*;
import sisc.io.*;
import sisc.interpreter.*;
import sisc.nativefun.NativeLibrary;
import java.io.IOException;
import java.io.EOFException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import sisc.reader.Lexer;
import sisc.reader.Parser;
public abstract class Util implements Version {
static String safeGetProperty(String key, String def) {
try {
return System.getProperty(key, def);
} catch (AccessControlException ex) {
return def;
}
}
public static final boolean caseSensitive =
safeGetProperty("sisc.caseSensitive",
new Boolean(Defaults.CASE_SENSITIVE).toString()).equals("true");
public static final boolean permitInterrupts =
safeGetProperty("sisc.permitInterrupts",
new Boolean(Defaults.PERMIT_INTERRUPTS).toString()).equals("true");
public static final int minFloatPrecision =
Integer.parseInt(safeGetProperty("sisc.minFloatPrecision",
Integer.toString(Defaults.MIN_FLOAT_PRECISION)));
public static final int maxFloatPrecision =
Integer.parseInt(safeGetProperty("sisc.maxFloatPrecision",
Integer.toString(Defaults.MAX_FLOAT_PRECISION)));
public static final Value[] ZV = new Value[0];
public static final Quantity FIVE = Quantity.valueOf(5);
public static EOFObject EOF = EOFObject.EOF;
public static Syntax QUOTE =
new Syntax(sisc.compiler.Compiler.QUOTE);
public static EmptyList EMPTYLIST = EmptyList.EMPTYLIST;
public static SchemeVoid VOID = SchemeVoid.VOID;
public static SchemeBoolean TRUE = SchemeBoolean.TRUE,
FALSE = SchemeBoolean.FALSE;
public static SchemeVector EMPTYVEC =
new SchemeVector(new Value[]{});
public static Symbol BEGIN = Symbol.get("begin"),
ERRORK = Symbol.get("error-continuation"),
EXPSC = Symbol.get("*sc-expander*"),
EXPTOP = Symbol.get("*top*"),
FCONT = Symbol.get("failure-continuation"),
JEXCEPTION = Symbol.get("java-exception"),
LAMBDA = Symbol.get("lambda"),
LOCATION = Symbol.get("location"),
MESSAGE = Symbol.get("message"),
NAME = Symbol.get("name"),
OTHER = Symbol.get("other"),
PARENT = Symbol.get("parent"),
QUOTESYM = Symbol.get("quote"),
REPORT = Symbol.get("*report*"),
SETBANG = Symbol.get("set!"),
SISC = Symbol.get("*sisc*"),
SISC_SPECIFIC = Symbol.get("*sisc-specific*"),
SYMENV = Symbol.get("*symenv*"),
THIS = Symbol.get("this"),
TOPLEVEL = Symbol.get("*toplevel*"),
BACKQUOTE = Symbol.get("quasiquote"),
UNQUOTE = Symbol.get("unquote"),
UNQUOTE_SPLICING = Symbol.get("unquote-splicing"),
SOURCE_LINE = Symbol.get("line-number"),
SOURCE_COLUMN = Symbol.get("column-number"),
SOURCE_FILE = Symbol.get("source-file"),
EVAL = Symbol.get("eval");
public static String warn(String messageClass) {
StringBuffer b = new StringBuffer("{");
b.append(liMessage(SISCB, "warning"));
b.append(": ");
b.append(liMessage(SISCB, messageClass));
b.append(')');
return b.toString();
}
public static String warn(String messageClass, String sourceFile,
int lineNumber, int columnNumber) {
StringBuffer b = new StringBuffer("{");
b.append(liMessage(SISCB, "warning"));
b.append(": ");
b.append(liMessage(SISCB, messageClass));
b.append("\n ");
b.append(sourceFile).append(':').append(lineNumber);
b.append(':').append(columnNumber).append(": }");
return b.toString();
}
public static String warn(String messageClass, String arg) {
StringBuffer b = new StringBuffer("{");
b.append(liMessage(SISCB, "warning"));
b.append(": ");
b.append(liMessage(SISCB, messageClass, arg));
b.append(')');
return b.toString();
}
static Class JOBJ = null;
static Class[] OBJARRY = new Class[] { Object.class };
static Constructor JOBJCONST = null;
static {
try {
JOBJ = Class.forName("sisc.modules.s2j.JavaObject");
JOBJCONST = JOBJ.getConstructor(OBJARRY);
} catch (Exception cnf) {
}
}
public static Value javaWrap(Object o) {
if (JOBJ != null)
try {
return (Value) JOBJCONST.newInstance(new Object[] { o });
} catch (Exception ie) {
}
return FALSE;
}
public static void error(Interpreter r,
Value where,
String errormessage,
Pair moreData)
throws ContinuationException {
error(r, append(moreData, list(new Pair(MESSAGE, new SchemeString(errormessage)),
new Pair(LOCATION, where))));
}
public static void error(
Interpreter r,
Value where,
String errormessage,
Exception e)
throws ContinuationException {
error(r, list(new Pair(MESSAGE, new SchemeString(errormessage)),
new Pair(LOCATION, where),
new Pair(JEXCEPTION, javaWrap(e))));
}
public static void error(Interpreter r, Value where, String errormessage)
throws ContinuationException {
error(r, list(new Pair(MESSAGE, new SchemeString(errormessage)),
new Pair(LOCATION, where)));
}
public static void error(Interpreter r, String errormessage, Pair moreData)
throws ContinuationException {
error(r, new Pair(new Pair(MESSAGE, new SchemeString(errormessage)),
moreData));
}
public static void error(Interpreter r, String errormessage)
throws ContinuationException {
error(r, list(new Pair(MESSAGE, new SchemeString(errormessage))));
}
public static void error(Interpreter r, Value errormessage)
throws ContinuationException {
error(r, list(new Pair(MESSAGE, errormessage)));
}
public static String simpleErrorToString(Pair p) {
StringBuffer b=new StringBuffer();
String location=null;
String message=null;
Pair parent = null;
while (p!=EMPTYLIST && (location==null || message==null)) {
Pair cp=(Pair)p.car();
if (cp.car().equals(MESSAGE))
message=cp.cdr().toString();
else if (cp.car().equals(LOCATION))
location=cp.cdr().toString();
else if (cp.car().equals(PARENT))
parent=(Pair)cp.cdr();
p=(Pair)p.cdr();
}
if (location==null)
b.append(liMessage(SISCB, "error"));
else
b.append(liMessage(SISCB, "errorinwhere", location));
if (message!=null)
b.append(": ").append(message);
else
b.append('.');
if (parent!=null)
b.append("\n ").append(simpleErrorToString(parent));
return b.toString();
}
public static ClassLoader currentClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (java.security.AccessControlException e) {
}
if (cl == null) {
try {
cl = Util.class.getClassLoader();
} catch (java.security.AccessControlException e) {
}
}
if (cl == null) {
try {
cl = ClassLoader.getSystemClassLoader();
} catch (java.security.AccessControlException e) {
}
}
if (cl == null) {
throw new RuntimeException(liMessage(SISCB, "notclassloader"));
}
return cl;
}
public static Value read(String expr) throws IOException {
PushbackReader ip = new PushbackReader(new StringReader(expr));
Parser p = new Parser(new Lexer());
Value res = p.nextExpression(ip);
try {
Value v=p.nextExpression(ip);
} catch (EOFException eof) {
return res;
}
throw new IOException(liMessage(SISCB, "stringreaderror", expr));
}
public static void error(Interpreter r, Pair error)
throws ContinuationException {
r.error(error);
}
public static String justify(String v, int p, char c) {
StringBuffer b = new StringBuffer();
while (b.length() < (p - v.length())) {
b.append(c);
}
return b.append(v).toString();
}
public static final void argCheck(Pair argl, int arity) throws Exception {
int x = length(argl);
if (x != arity && arity != -1) {
throw new RuntimeException(liMessage(SISCB,
"notenoughargs",
new Object[] { new Integer(arity), new Integer(x)}));
}
}
public static void updateName(Value v, Symbol s) {
if (v instanceof NamedValue) {
NamedValue nv = (NamedValue) v;
if (nv.getName() == null) {
nv.setName(s);
}
}
}
public static int length(Pair p) {
Pair s = p;
try {
int i = 0;
for (; p != EMPTYLIST; i++) {
p = (Pair) p.cdr();
}
return i;
} catch (ClassCastException ce) {
throw new RuntimeException(liMessage(SISCB, "notaproperlist", s.synopsis()));
}
}
/**
* @param p the head of a list
* @return a Vector containing the same elements as the list
*
* @deprecated Obsoleted by pairToExpressions and pairToValues.
*/
public static Vector pairToExpVect(Pair p) {
Vector v = new Vector();
for (; p != EMPTYLIST; p = (Pair) p.cdr()) {
v.addElement(p.car());
}
return v;
}
public static Expression[] pairToExpressions(Pair p) {
int len = length(p);
Expression[] es = new Expression[len];
for (int i = 0; i < len; ++i) {
es[i] = p.car();
p = (Pair)p.cdr();
}
return es;
}
public static Value[] pairToValues(Pair p) {
int len = length(p);
if (len == 0) return ZV;
Value[] vs = new Value[len];
for (int i = 0; i < len; ++i) {
vs[i] = p.car();
p = (Pair)p.cdr();
}
return vs;
}
public static Symbol[] argsToSymbols(Pair p) {
if (p == EMPTYLIST) {
return new Symbol[0];
}
// Count the proper elements ignoring the tail:
int l = 1;
Value q = p.cdr();
while ((q instanceof Pair) && (q != EMPTYLIST)) {
++l;
q = ((Pair)q).cdr();
}
// Allocate result array:
Symbol[] result;
if (q == EMPTYLIST) {
result = new Symbol[l];
} else {
// improper list: the tail is expected to contain a symbol
result = new Symbol[l+1];
result[l] = (Symbol)q;
}
// Copy the proper elements into the result
int i = 0;
for (;;) {
result[i++] = (Symbol)p.car();
if (i == l) {
// An update of p as done below would throw a
// ClassCastException for improper lists.
break;
}
p = (Pair)p.cdr();
}
return result;
}
/* Casting checks */
public static void typeError(String type, Value o) {
typeError(SISCB, type, o);
}
public static void typeError(Symbol bundleName, String type, Value o) {
if (o instanceof Values)
throw new RuntimeException(liMessage(SISCB, "multiplevalues"));
throw new RuntimeException(liMessage(SISCB,
"unexpectedarg",
liMessage(bundleName, type),
o.synopsis()));
}
// Synonym for Symbol.get(s) (i.e. a lowercased sym)
public static final Symbol sym(String s) {
return Symbol.get(s);
}
public static final String symval(Value o) {
if (o instanceof Symbol) {
return ((Symbol) o).symval;
} else {
typeError("symbol", o);
return null;
}
}
public static final Quantity num(Value o) {
if (o instanceof Quantity) {
return (Quantity) o;
} else {
typeError("number", o);
return null;
}
}
public static final Pair pair(Value o) {
if (o instanceof Pair) {
return (Pair) o;
} else {
typeError("pair", o);
return null;
}
}
public static final Procedure proc(Value o) {
if (o instanceof Procedure) {
return (Procedure) o;
} else {
typeError("procedure", o);
return null;
}
}
public static final Pair truePair(Value o) {
if (o == EMPTYLIST)
typeError("pair", o);
return pair(o);
}
public static final char character(Value c) {
return chr(c).c;
}
public static final SchemeCharacter chr(Value o) {
if (o instanceof SchemeCharacter) {
return (SchemeCharacter) o;
} else {
typeError("character", o);
return null;
}
}
public static final String string(Value o) {
return str(o).asString();
}
public static final SchemeString str(Value o) {
if (o instanceof SchemeString) {
return (SchemeString) o;
} else {
typeError("string", o);
return null;
}
}
public static final Symbol symbol(Value o) {
if (o instanceof Symbol) {
return (Symbol) o;
} else {
typeError("symbol", o);
return null;
}
}
public static final SchemeVector vec(Value o) {
if (o instanceof SchemeVector) {
return (SchemeVector) o;
} else {
typeError("vector", o);
return null;
}
}
/* IO Type casts */
public static final OutputPort outport(Value o) {
if (o instanceof OutputPort) {
return (OutputPort) o;
} else {
typeError("output-port", o);
return null;
}
}
public static final SchemeBinaryOutputPort binoutport(Value o) {
if (o instanceof SchemeBinaryOutputPort) {
return (SchemeBinaryOutputPort) o;
} else {
typeError("binary-output-port", o);
return null;
}
}
public static final OutputStream binoutstream(Value o) {
return binoutport(o).getOutputStream();
}
public static final SchemeCharacterOutputPort charoutport(Value o) {
if (o instanceof SchemeCharacterOutputPort) {
return (SchemeCharacterOutputPort) o;
} else {
typeError("character-output-port", o);
return null;
}
}
public static final Writer charoutwriter(Value o) {
return charoutport(o).getWriter();
}
public static final InputPort inport(Value o) {
if (o instanceof InputPort) {
return (InputPort) o;
} else {
typeError("input-port", o);
return null;
}
}
public static final SchemeBinaryInputPort bininport(Value o) {
if (o instanceof SchemeBinaryInputPort) {
return (SchemeBinaryInputPort) o;
} else {
typeError("binary-input-port", o);
return null;
}
}
public static final InputStream bininstream(Value o) {
return bininport(o).getInputStream();
}
public static final SchemeCharacterInputPort charinport(Value o) {
if (o instanceof SchemeCharacterInputPort) {
return (SchemeCharacterInputPort) o;
} else {
typeError("character-input-port", o);
return null;
}
}
public static final Reader charinreader(Value o) {
return charinport(o).getReader();
}
public static final SymbolicEnvironment env(Value o) {
if (o instanceof SymbolicEnvironment) {
return (sisc.env.SymbolicEnvironment) o;
} else {
typeError("environment", o);
return null;
}
}
public static final Box box(Value o) {
if (o instanceof Box) {
return (Box) o;
} else {
typeError("box", o);
return null;
}
}
public static final CallFrame cont(Value o) {
if (o instanceof CallFrame) {
return (CallFrame) o;
} else {
typeError("continuation", o);
return null;
}
}
public static final Expression expr(Value o) {
if (o instanceof ExpressionValue) {
return ((ExpressionValue)o).e;
} else {
typeError("expression", o);
return null;
}
}
public static final AnnotatedExpr annotated(Value o) {
if (o instanceof AnnotatedExpr) {
return (AnnotatedExpr) o;
} else {
typeError("annotatedexpression", o);
return null;
}
}
public static URL makeURL(String url) {
URL res = null;
if (url == null) return res;
try {
res = new URL(url);
} catch (MalformedURLException e) {
try {
res = new URL("file", null, url);
} catch (MalformedURLException ee) {
}
}
return res;
}
public static URL url(Value v) {
try {
return url(string(v));
} catch (MalformedURLException e) {
typeError("url", v);
}
return null;
}
public static URL url(String s) throws MalformedURLException {
try {
return new URL(s);
} catch (MalformedURLException e) {
return new URL("file", null, s);
}
}
public static URL url(Value current, Value v) {
URL c = url(current);
String s = string(v);
try {
return new URL(c, s);
} catch (MalformedURLException e) {
try {
return new URL(c, "file:" + s);
} catch (MalformedURLException ee) {
typeError("url", v);
}
return null;
}
}
public static final NativeLibrary nlib(Value o) {
if (o instanceof NativeLibrary) {
return (NativeLibrary) o;
} else {
typeError("nativelibrary", o);
return null;
}
}
public static final ImmutablePair immutablePair(Value o) {
if (o instanceof ImmutablePair) {
return (ImmutablePair) o;
} else {
typeError("immutable-pair", o);
return null;
}
}
public static final ImmutableVector immutableVector(Value o) {
if (o instanceof ImmutableVector) {
return (ImmutableVector) o;
} else {
typeError("immutable-vector", o);
return null;
}
}
public static final SchemeBoolean truth(boolean b) {
return b ? TRUE : FALSE;
}
public static final boolean truth(Value v) {
return v != FALSE;
}
/* List functions */
public static Value assq(Value v, Pair p) {
while (p!=EMPTYLIST) {
Pair assc=pair(p.car());
if (assc.car() == v) {
return assc;
}
p=pair(p.cdr());
}
return FALSE;
}
public static Pair mapcar(Pair list) {
Pair c=EMPTYLIST;
while (list != EMPTYLIST) {
c=new Pair(truePair(list.car()).car(), c);
list=pair(list.cdr());
}
return reverseInPlace(c);
}
public static Pair reverse(Pair p) {
Pair n=EMPTYLIST;
while (p!=EMPTYLIST) {
n=new Pair(p.car(), n);
p=(Pair)p.cdr();
}
return n;
}
public static Pair reverseInPlace(Pair s) {
if (s==EMPTYLIST) {
return EMPTYLIST;
}
Pair r=EMPTYLIST;
Value d;
for (;;) {
d=s.cdr();
s.setCdr(r);
r=s;
if (d==EMPTYLIST) {
break;
}
s=(Pair)d;
}
return r;
}
public static Pair append(Pair p1, Pair p2) {
if (p1 == EMPTYLIST)
return p2;
return new Pair(p1.car(), append((Pair) p1.cdr(), p2));
}
public static final Pair list(Value o1) {
return new Pair(o1, EMPTYLIST);
}
public static final Pair list(Value o1, Value o2) {
return new Pair(o1, list(o2));
}
public static final Pair list(Value o1, Value o2, Value o3) {
return new Pair(o1, list(o2, o3));
}
public static final Pair list(Value o1, Value o2, Value o3, Value o4) {
return new Pair(o1, list(o2, o3, o4));
}
public static final Pair list(Value o1, Value o2, Value o3, Value o4, Value o5) {
return new Pair(o1, list(o2, o3, o4, o5));
}
public static final Pair valArrayToList(Value[] r, int offset, int len) {
Pair p = EMPTYLIST;
for (int i = (offset + len) - 1; i >= offset; i--) {
p = new Pair(r[i], p);
}
return p;
}
public static final Pair valArrayToList(Value[] r) {
return (r == null ? EMPTYLIST : valArrayToList(r, 0, r.length));
}
public static final SchemeVector valArrayToVec(Value[] r) {
if (r == null) return EMPTYVEC;
//replace nulls with VOID - this mutation is always safe
for (int i = 0; i < r.length; i++) {
if (r[i] == null) r[i] = VOID;
}
return new SchemeVector(r);
}
public static Value memq(Value v, Pair p) {
while (p!=EMPTYLIST) {
if (p.car() == v) {
return p;
}
p=pair(p.cdr());
}
return FALSE;
}
/* Localization and Internationalization */
public static Symbol SISCB = Symbol.intern("sisc.Messages");
public static WeakHashMap bundles = new WeakHashMap();
static Locale myLocale = Locale.getDefault();
static MessageFormat formatter = new MessageFormat("");
static {
formatter.setLocale(myLocale);
}
public static void registerBundle(Symbol bundleName)
throws MissingResourceException {
ResourceBundle b = ResourceBundle.getBundle(bundleName.symval);
bundles.put(bundleName, b);
}
public static String liMessage(Symbol bundleName, String messageName) {
ResourceBundle bundle = (ResourceBundle) bundles.get(bundleName);
try {
if (bundle == null) {
registerBundle(bundleName);
bundle = (ResourceBundle) bundles.get(bundleName);
}
return bundle.getString(messageName);
} catch (MissingResourceException mr) {
if (!bundleName.equals(SISCB))
return liMessage(SISCB, messageName);
else
return "<localized message not found: " + messageName + ">";
}
}
public static String liMessage(Symbol bundle,
String messageName,
String arg1) {
return MessageFormat.format(liMessage(bundle, messageName),
new Object[] { arg1 });
}
public static String liMessage(Symbol bundle,
String messageName,
String arg1,
String arg2) {
return MessageFormat.format(liMessage(bundle, messageName),
new Object[] { arg1, arg2 });
}
public static String liMessage(Symbol bundle,
String messageName,
String arg1,
String arg2,
String arg3) {
return MessageFormat.format(liMessage(bundle, messageName),
new Object[] { arg1, arg2, arg3 });
}
public static String liMessage(Symbol bundle,
String messageName,
String arg1,
String arg2,
String arg3,
String arg4) {
return MessageFormat.format(liMessage(bundle, messageName),
new Object[] { arg1, arg2, arg3, arg4 });
}
public static String liMessage(Symbol bundle,
String messageName,
String arg1,
int arg2,
int arg3) {
return MessageFormat.format(liMessage(bundle, messageName),
new Object[] { arg1, new Integer(arg2), new Integer(arg3)});
}
public static String liMessage(Symbol bundle,
String messageName,
Object[] args) {
return MessageFormat.format(liMessage(bundle, messageName), args);
}
protected static String javaExceptionToString(Exception e) {
return "<" + e.getClass().getName() + ">: "+ e.getMessage();
}
public static Pair sourceAnnotations(String file,
int line,
int column,
Pair anns) {
return
new Pair(new Pair(SOURCE_FILE, new SchemeString(file)),
new Pair(new Pair(SOURCE_LINE, Quantity.valueOf(line)),
new Pair(new Pair(SOURCE_COLUMN, Quantity.valueOf(column)),
anns)));
}
public static Expression annotatedAppEval(Class clazz, String fn) {
Expression e = new AppEval();
e.setAnnotation(SOURCE_FILE,
new SchemeString(clazz.getName() + "/" + fn));
return e;
}
private static Charset defaultCharset = null;
static {
try {
defaultCharset = Charset.forName("UTF-8");
} catch (UnsupportedEncodingException e) {
// I think this is a "can't happen" error,
// since Java natively supports UTF-8
throw new ExceptionInInitializerError(e);
} catch (java.nio.charset.UnsupportedCharsetException e) {
// this one, too
throw new ExceptionInInitializerError(e);
}
}
/**
* Return the default character set, which is UTF-8, but could in
* principle change.
*
* @return a static Charset object
*/
public static Charset getDefaultCharacterSet() {
return defaultCharset;
}
/**
* Converts a character set name to a Charset. If the input name
* is null, then return the default Charset. If the input name
* does not correspond to a legal or supported
* character set, then return the default Charset and give a warning.
*
* @param charsetName the name of a putative character set, or null
* @return the Charset corresponding to the argument, or the
* default character set (see {@link #getDefaultCharacterSet}) if
* that is not possible
*/
public static Charset charsetFromString(String charsetName) {
Charset c;
if (charsetName == null) {
c = getDefaultCharacterSet();
} else {
try {
c = Charset.forName(charsetName);
} catch (Exception e) {
// This is either IllegalCharsetNameException or
// UnsupportedCharsetException -- handle both in the same way
System.err.println(Util.warn("unsupencoding", charsetName));
c = getDefaultCharacterSet();
}
}
//assert c != null;
return c;
}
}
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Second Interpreter of Scheme Code (SISC).
*
* The Initial Developer of the Original Code is Scott G. Miller.
* Portions created by Scott G. Miller are Copyright (C) 2000-2007
* Scott G. Miller. All Rights Reserved.
*
* Contributor(s):
* Matthias Radestock
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
|