Scheme.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package kawa.standard;
  2. import kawa.lang.*;
  3. import gnu.bytecode.Type;
  4. import gnu.bytecode.ClassType;
  5. import gnu.mapping.*;
  6. import gnu.expr.*;
  7. import java.util.*;
  8. import gnu.text.SourceMessages;
  9. import gnu.kawa.lispexpr.*;
  10. import gnu.kawa.format.AbstractFormat;
  11. import gnu.kawa.functions.*;
  12. import gnu.kawa.io.CharArrayInPort;
  13. import gnu.kawa.io.InPort;
  14. import gnu.kawa.reflect.LazyType;
  15. import gnu.kawa.reflect.MultValuesType;
  16. import gnu.kawa.servlet.HttpRequestContext;
  17. public class Scheme extends LispLanguage {
  18. public static final int FOLLOW_R5RS = 5;
  19. public static final int FOLLOW_R6RS = 6;
  20. public static final int FOLLOW_R7RS = 7;
  21. int standardToFollow;
  22. public int getStandardToFollow() { return standardToFollow; }
  23. private static Environment r5Environment;
  24. protected static final SimpleEnvironment kawaEnvironment =
  25. Environment.make("kawa-environment");
  26. public static final Scheme instance = new Scheme(kawaEnvironment);
  27. private static Scheme r5rsInstance;
  28. private static Scheme r6rsInstance;
  29. private static Scheme r7rsInstance;
  30. public static final LangPrimType booleanType =
  31. new LangPrimType(Type.booleanType, instance);
  32. public static final ApplyToArgs applyToArgs =
  33. new ApplyToArgs("apply-to-args", instance);
  34. public static final Apply apply =
  35. new Apply("apply", applyToArgs);
  36. public static final gnu.kawa.reflect.InstanceOf instanceOf =
  37. new gnu.kawa.reflect.InstanceOf(instance, "instance?");
  38. public static final Not not =
  39. new Not(instance, "not");
  40. public static final gnu.kawa.functions.IsEq isEq =
  41. new gnu.kawa.functions.IsEq(instance, "eq?");
  42. public static final gnu.kawa.functions.IsEqv isEqv =
  43. new gnu.kawa.functions.IsEqv(instance, "eqv?", isEq);
  44. public static final gnu.kawa.functions.IsEqual isEqual =
  45. new gnu.kawa.functions.IsEqual(instance, "equal?");
  46. public static final gnu.kawa.functions.Map map =
  47. new gnu.kawa.functions.Map(true, applyToArgs, isEq);
  48. public static final gnu.kawa.functions.Map forEach =
  49. new gnu.kawa.functions.Map(false, applyToArgs, isEq);
  50. public static final NumberCompare numEqu =
  51. NumberCompare.make(instance, "=", NumberCompare.TRUE_IF_EQU);
  52. public static final NumberCompare numGrt =
  53. NumberCompare.make(instance, ">", NumberCompare.TRUE_IF_GRT);
  54. public static final NumberCompare numGEq =
  55. NumberCompare.make(instance, ">=",
  56. NumberCompare.TRUE_IF_GRT|NumberCompare.TRUE_IF_EQU);
  57. public static final NumberCompare numLss =
  58. NumberCompare.make(instance, "<", NumberCompare.TRUE_IF_LSS);
  59. public static final NumberCompare numLEq =
  60. NumberCompare.make(instance, "<=",
  61. NumberCompare.TRUE_IF_LSS|NumberCompare.TRUE_IF_EQU);
  62. public static final NumberPredicate isOdd =
  63. new NumberPredicate(instance, "odd?", NumberPredicate.ODD);
  64. public static final NumberPredicate isEven =
  65. new NumberPredicate(instance, "even?", NumberPredicate.EVEN);
  66. private static final String[] uniformVectorTags =
  67. {"s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64", "f32", "f64" };
  68. public static final String emptyStringLeft = new String();
  69. public static final String emptyStringRight = new String();
  70. static {
  71. instance.initScheme();
  72. }
  73. public static Scheme getInstance()
  74. {
  75. return instance;
  76. }
  77. private static Scheme newStandardInstance (int standardToFollow)
  78. {
  79. Scheme instance = new Scheme(getStdEnvironment());
  80. instance.standardToFollow = standardToFollow;
  81. return instance;
  82. }
  83. public static Exception loadClass(String path, Environment env) {
  84. Environment saveEnv = Environment.setSaveCurrent(env);
  85. try {
  86. instance.loadClass(path);
  87. } catch (java.lang.ClassNotFoundException ex) {
  88. return ex;
  89. } finally {
  90. Environment.restoreCurrent(saveEnv);
  91. }
  92. return null;
  93. }
  94. public static synchronized Environment getR5rsEnvironment() {
  95. if (r5Environment == null) {
  96. r5Environment = Environment.make("r5rs-environment");
  97. Exception ex = loadClass("kawa.lib.scheme.r5rs", r5Environment);
  98. if (ex != null)
  99. throw new RuntimeException(ex);
  100. }
  101. return r5Environment;
  102. }
  103. static Environment stdEnvironment;
  104. public static synchronized Environment getStdEnvironment() {
  105. if (stdEnvironment == null) {
  106. stdEnvironment = Environment.make("standard-environment");
  107. Exception ex = loadClass("kawa.lib.kawa.base", stdEnvironment);
  108. if (ex == null)
  109. ex = loadClass("kawa.lib.kawa.mstrings", stdEnvironment);
  110. if (ex != null )
  111. throw new RuntimeException(ex);
  112. stdEnvironment.setLocked();
  113. }
  114. return stdEnvironment;
  115. }
  116. public static synchronized Scheme getR5rsInstance() {
  117. if (r5rsInstance == null)
  118. r5rsInstance = newStandardInstance(FOLLOW_R5RS);
  119. return r5rsInstance;
  120. }
  121. public static synchronized Scheme getR6rsInstance() {
  122. if (r6rsInstance == null)
  123. r6rsInstance = newStandardInstance(FOLLOW_R6RS);
  124. return r6rsInstance;
  125. }
  126. public static synchronized Scheme getR7rsInstance() {
  127. if (r7rsInstance == null)
  128. r7rsInstance = newStandardInstance(FOLLOW_R7RS);
  129. return r7rsInstance;
  130. }
  131. public static Environment builtin ()
  132. {
  133. return kawaEnvironment;
  134. }
  135. private void initScheme() {
  136. environ = kawaEnvironment;
  137. Environment saveEnv = Environment.setSaveCurrent(kawaEnvironment);
  138. try {
  139. loadClass("kawa.lib.kawa.base");
  140. } catch (java.lang.ClassNotFoundException ex) {
  141. // Ignore exception - happens while building kawa/lib.
  142. defAliasStFld("$construct$", "gnu.kawa.lispexpr.LispLanguage", "constructNamespace");
  143. defSntxStFld("object", "kawa.standard.object", "objectSyntax");
  144. defSntxStFld("module-export", "kawa.standard.export", "module_export");
  145. defSntxStFld("module-name", "kawa.standard.module_name",
  146. "module_name");
  147. defSntxStFld("export", "kawa.standard.export", "export");
  148. defSntxStFld("import", "kawa.standard.ImportFromLibrary", "instance");
  149. defSntxStFld("require", "kawa.standard.require", "require");
  150. defSntxStFld("include", "kawa.standard.Include", "include");
  151. }
  152. finally {
  153. Environment.restoreCurrent(saveEnv);
  154. }
  155. kawaEnvironment.setLocked();
  156. int withServlets = HttpRequestContext.importServletDefinitions;
  157. if (withServlets > 0) {
  158. try {
  159. loadClass(withServlets > 1 ? "gnu.kawa.servlet.servlets"
  160. : "gnu.kawa.servlet.HTTP");
  161. } catch (Exception ex) {
  162. }
  163. }
  164. }
  165. public Scheme ()
  166. {
  167. environ = kawaEnvironment;
  168. userEnv = getNewEnvironment();
  169. }
  170. protected Scheme (Environment env)
  171. {
  172. environ = env;
  173. }
  174. public String getName()
  175. {
  176. switch (standardToFollow)
  177. {
  178. case FOLLOW_R5RS:
  179. return "Scheme-r5rs";
  180. case FOLLOW_R6RS:
  181. return "Scheme-r6rs";
  182. case FOLLOW_R7RS:
  183. return "Scheme-r7rs";
  184. default:
  185. return "Scheme";
  186. }
  187. }
  188. public String getCompilationClass () { return "kawa.standard.SchemeCompilation"; }
  189. /** Evaluate Scheme expressions from string.
  190. * @param string the string containing Scheme expressions
  191. * @param env the Environment to evaluate the string in
  192. * @return result of last expression, or Language.voidObject if none. */
  193. public static Object eval (String string, Environment env)
  194. {
  195. return eval (new CharArrayInPort(string), env);
  196. }
  197. /** Evaluate Scheme expressions from stream.
  198. * @param port the port to read Scheme expressions from
  199. * @param env the Environment to evaluate the string in
  200. * @return result of last expression, or Language.voidObject if none. */
  201. public static Object eval (InPort port, Environment env)
  202. {
  203. SourceMessages messages = new SourceMessages();
  204. try
  205. {
  206. LispReader lexer = (LispReader)
  207. Language.getDefaultLanguage().getLexer(port, messages);
  208. Object body = ReaderParens.readList(lexer, null, 0, 1, -1, -1);
  209. if (messages.seenErrors())
  210. throw new gnu.text.SyntaxException(messages);
  211. return Eval.evalBody(body, env, messages);
  212. }
  213. catch (gnu.text.SyntaxException e)
  214. {
  215. // The '\n' is because a SyntaxException includes a line number,
  216. // and it is better if that starts the line. FIXME OBSOLETE
  217. throw new RuntimeException("eval: errors while compiling:\n"
  218. +e.getMessages().toString(20));
  219. }
  220. catch (java.io.IOException e)
  221. {
  222. throw new RuntimeException("eval: I/O exception: "
  223. + e.toString ());
  224. }
  225. catch (Throwable ex)
  226. {
  227. throw WrappedException.rethrow(ex);
  228. }
  229. }
  230. /** Evaluate Scheme expressions from an "S expression."
  231. * @param sexpr the S expression to evaluate
  232. * @param env the Environment to evaluate the string in
  233. * @return result of the expression. */
  234. public static Object eval (Object sexpr, Environment env)
  235. {
  236. try
  237. {
  238. return Eval.eval (sexpr, env);
  239. }
  240. catch (Throwable ex)
  241. {
  242. throw WrappedException.rethrow(ex);
  243. }
  244. }
  245. @Override
  246. public AbstractFormat getFormat(boolean readable)
  247. {
  248. return readable ? DisplayFormat.schemeWriteFormat
  249. : DisplayFormat.schemeDisplayFormat;
  250. }
  251. @Override
  252. public LispReader getLexer(InPort inp, SourceMessages messages)
  253. {
  254. LispReader reader = super.getLexer(inp, messages);
  255. if (reader.getReadCase() == '\0'
  256. && standardToFollow == FOLLOW_R5RS)
  257. reader.setReadCase('D');
  258. return reader;
  259. }
  260. @Override
  261. public int getNamespaceOf (Declaration decl)
  262. {
  263. return FUNCTION_NAMESPACE+VALUE_NAMESPACE;
  264. }
  265. /** If exp is a "constant" Type, return that type, otherwise return null. */
  266. public static Type getTypeValue (Expression exp)
  267. {
  268. return getInstance().getTypeFor(exp);
  269. }
  270. private HashMap<String,Type> types;
  271. private HashMap<Type,String> typeToStringMap;
  272. @Override
  273. protected synchronized HashMap<String, Type> getTypeMap() {
  274. if (types == null) {
  275. types = new HashMap<String, Type>(128); // Bit more wiggle room
  276. types.put("boolean", booleanType);
  277. types.put("parameter", Compilation.typeLocationProc);
  278. types.putAll(super.getTypeMap());
  279. for (int i = uniformVectorTags.length; --i >= 0;) {
  280. String tag = uniformVectorTags[i];
  281. String cname = "gnu.lists." + tag.toUpperCase() + "Vector";
  282. types.put(tag + "vector", ClassType.make(cname));
  283. }
  284. }
  285. return types;
  286. }
  287. public String formatType(Type type) {
  288. // FIXME synchronize
  289. if (type instanceof LazyType) {
  290. LazyType ltype = (LazyType) type;
  291. return formatType(ltype.getRawType())
  292. +'['+formatType(ltype.getValueType())+']';
  293. }
  294. if (type instanceof MultValuesType) {
  295. MultValuesType mtype = (MultValuesType) type;
  296. StringBuilder sbuf = new StringBuilder();
  297. sbuf.append("values[");
  298. int n = mtype.getValueCount();
  299. for (int i = 0; i < n; i++) {
  300. if (i > 0)
  301. sbuf.append(' ');
  302. Type etype = mtype.getValueType(i);
  303. sbuf.append(etype == null ? "unspecified" : formatType(etype));
  304. }
  305. sbuf.append(']');
  306. return sbuf.toString();
  307. }
  308. if (type instanceof GenArrayType) {
  309. GenArrayType atype = (GenArrayType) type;
  310. StringBuilder sbuf = new StringBuilder("array");
  311. int rank = atype.rank();
  312. if (rank >= 0)
  313. sbuf.append(rank);
  314. Type elementType = atype.getComponentType();
  315. if (elementType != null && elementType != Type.objectType) {
  316. sbuf.append('[');
  317. sbuf.append(formatType(elementType));
  318. sbuf.append(']');
  319. }
  320. return sbuf.toString();
  321. }
  322. if (typeToStringMap == null) {
  323. typeToStringMap = new HashMap<Type,String>();
  324. // Invert the map returned by getTypeMap.
  325. for (java.util.Map.Entry<String,Type> e : getTypeMap().entrySet())
  326. typeToStringMap.put(e.getValue(), e.getKey());
  327. }
  328. String str = typeToStringMap.get(type);
  329. if (str != null)
  330. return str;
  331. return super.formatType(type);
  332. }
  333. /** Convert expression to a Type.
  334. * Allow {@code "TYPE"} or {@code 'TYPE} or {@code <TYPE>}.
  335. */
  336. public static Type exp2Type (Expression exp)
  337. {
  338. return getInstance().getTypeFor(exp);
  339. }
  340. public Symbol asSymbol (String ident)
  341. {
  342. return Namespace.EmptyNamespace.getSymbol(ident);
  343. }
  344. /** Should the values of body/block be appended as multiple values?
  345. * Otherwise, just return the result of the final expression.
  346. */
  347. public boolean appendBodyValues () { return false; }
  348. @Override
  349. public boolean keywordsAreSelfEvaluating() { return false; }
  350. public ReadTable createReadTable ()
  351. {
  352. ReadTable tab = ReadTable.createInitial();
  353. int std = standardToFollow;
  354. ReaderDispatch dispatchTable = (ReaderDispatch) tab.lookup('#');
  355. ReaderDispatchSyntaxQuote sentry = new ReaderDispatchSyntaxQuote();
  356. dispatchTable.set('\'', sentry);
  357. dispatchTable.set('`', sentry);
  358. dispatchTable.set(',', sentry);
  359. tab.putReaderCtorFld("path", "gnu.kawa.lispexpr.LangObjType", "pathType");
  360. tab.putReaderCtorFld("filepath", "gnu.kawa.lispexpr.LangObjType", "filepathType");
  361. tab.putReaderCtorFld("URI", "gnu.kawa.lispexpr.LangObjType", "URIType");
  362. tab.putReaderCtor("symbol", ClassType.make("gnu.mapping.Symbol"));
  363. tab.putReaderCtor("namespace", ClassType.make("gnu.mapping.Namespace"));
  364. tab.putReaderCtorFld("duration", "kawa.lib.numbers", "duration");
  365. if (std == FOLLOW_R5RS || std == FOLLOW_R6RS || std == FOLLOW_R7RS)
  366. {
  367. }
  368. else
  369. {
  370. tab.postfixLookupOperator = ':';
  371. tab.setFinalColonIsKeyword(true);
  372. tab.extraFlags = LispReader.SCM_LEXPONENT_IS_BIGDECIMAL;
  373. tab.set('@', new ReaderQuote(LispLanguage.splice_sym,
  374. ':', LispLanguage.splice_colon_sym,
  375. ReadTable.NON_TERMINATING_MACRO));
  376. }
  377. return tab;
  378. }
  379. /** The compiler insert calls to this method for applications and applets. */
  380. public static void registerEnvironment()
  381. {
  382. Language.setDefaults(getInstance());
  383. }
  384. }