repl.java 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  1. package kawa;
  2. import java.io.*;
  3. import java.net.*;
  4. import gnu.mapping.*;
  5. import gnu.expr.*;
  6. import gnu.text.SourceMessages;
  7. import gnu.text.SyntaxException;
  8. import gnu.lists.*;
  9. import java.awt.Desktop;
  10. import java.util.ArrayList;
  11. import java.util.Collections;
  12. import java.util.List;
  13. import gnu.bytecode.ClassType;
  14. import gnu.kawa.servlet.HttpRequestContext;
  15. import gnu.kawa.io.CharArrayInPort;
  16. import gnu.kawa.io.CheckConsole;
  17. import gnu.kawa.io.InPort;
  18. import gnu.kawa.io.OutPort;
  19. import gnu.kawa.io.Path;
  20. import gnu.kawa.io.TermErrorStream;
  21. import gnu.kawa.io.WriterManager;
  22. import gnu.kawa.util.ExitCalled;
  23. import kawa.lang.SyntaxPattern;
  24. /** Start a "Read-Eval-Print-Loop" for the Kawa Scheme evaluator. */
  25. public class repl extends Procedure0or1 {
  26. public static String compilationTopname = null;
  27. Language language;
  28. static Language previousLanguage;
  29. static int defaultParseOptions = Language.PARSE_PROLOG|Language.PARSE_EXPLICIT;
  30. public repl() {
  31. }
  32. public repl(Language language) {
  33. this.language = language;
  34. }
  35. public Object apply0() {
  36. Shell.run(language, Environment.getCurrent());
  37. return Values.empty;
  38. }
  39. public Object apply1(Object env) {
  40. Shell.run(language, (Environment) env);
  41. return Values.empty;
  42. }
  43. public static String messagePrefix = "kawa: ";
  44. protected void error(String message) {
  45. if (messagePrefix != null)
  46. message = messagePrefix + message;
  47. System.err.println(message);
  48. System.exit(-1);
  49. }
  50. void bad_option (String str) {
  51. str = "bad option '" + str + "'";
  52. if (messagePrefix != null)
  53. str = messagePrefix + str;
  54. System.err.println(str);
  55. printOptions(System.err);
  56. System.exit(-1);
  57. }
  58. public static void printOption(PrintStream out,
  59. String option, String doc) {
  60. StringBuilder buf = new StringBuilder(" ");
  61. buf.append(option);
  62. buf.append(' ');
  63. for (int i = 30 - option.length(); --i >= 0; )
  64. buf.append(' ');
  65. buf.append(' ');
  66. buf.append(doc);
  67. out.println(buf);
  68. }
  69. public static void printOptions(PrintStream out) {
  70. out.println("Usage: [java kawa.repl | kawa] [options ...]");
  71. out.println();
  72. out.println(" Generic options:");
  73. printOption(out, "--help", "Show help about options");
  74. printOption(out, "--author", "Show author information");
  75. printOption(out, "--version", "Show version information");
  76. out.println();
  77. out.println(" Options");
  78. printOption(out, "-e <expr>", "Evaluate expression <expr>");
  79. printOption(out, "-c <expr>", "Same as -e, but make sure ~/.kawarc.scm is run first");
  80. printOption(out, "-f <filename>", "File to interpret");
  81. printOption(out, "-s| --", "Start reading commands interactively from console");
  82. printOption(out, "-w", "Launch the interpreter in a GUI window");
  83. printOption(out, "--server <port>", "Start a server accepting telnet connections on <port>");
  84. printOption(out, "--debug-dump-zip", "Compiled interactive expressions to a zip archive");
  85. printOption(out, "--debug-print-expr", "Print generated internal expressions");
  86. printOption(out, "--debug-print-final-expr", "Print expression after any optimizations");
  87. printOption(out, "--debug-error-prints-stack-trace", "Print stack trace with errors");
  88. printOption(out, "--debug-warning-prints-stack-trace", "Print stack trace with warnings");
  89. printOption(out,"--[no-]full-tailcalls", "(Don't) use full tail-calls");
  90. printOption(out, "-C <filename> ...", "Compile named files to Java class files");
  91. printOption(out, "--output-format <format>", "Use <format> when printing top-level output");
  92. printOption(out,"--<language>", "Select source language, one of:");
  93. String[][] languages = Language.getLanguages();
  94. for (int i = 0; i < languages.length; i++)
  95. {
  96. out.print(" ");
  97. String[] lang = languages[i];
  98. // skip last entry, which is class name
  99. int nwords = lang.length - 1;
  100. for (int j = 0; j < nwords; j++)
  101. out.print(lang[j] + " ");
  102. if (i == 0)
  103. out.print("[default]");
  104. out.println();
  105. }
  106. out.println(" Compilation options, must be specified before -C");
  107. printOption(out, "-d <dirname>", "Directory to place .class files in");
  108. printOption(out, "-P <prefix>", "Prefix to prepand to class names");
  109. printOption(out, "-T <topname>", "name to give to top-level class");
  110. printOption(out, "--applet", "Generate an applet");
  111. printOption(out, "--servlet", "Generate a servlet");
  112. printOption(out, "--module-static", "Top-level definitions are by default static");
  113. List<String> keys = Compilation.options.keys();
  114. Collections.sort(keys);
  115. for (int i = 0; i < keys.size(); ++i) {
  116. String name = keys.get(i);
  117. printOption(out, "--" + name, Compilation.options.getDoc(name));
  118. }
  119. out.println();
  120. out.println("For more information go to: http://www.gnu.org/software/kawa/");
  121. }
  122. public static String homeDirectory;
  123. static void checkInitFile()
  124. {
  125. /* Set homeDirectory; if first time called, run ~/.kawarc.scm. */
  126. if (homeDirectory == null) {
  127. File initFile = getInitFile();
  128. if (initFile != null && initFile.exists())
  129. if (! Shell.runFileOrClass(initFile.getPath(), true, 0))
  130. System.exit(-1);
  131. }
  132. }
  133. static File getInitFile() {
  134. File initFile = null;
  135. homeDirectory = System.getProperty ("user.home");
  136. Object scmHomeDirectory;
  137. if (homeDirectory != null) {
  138. scmHomeDirectory = new FString (homeDirectory);
  139. String file_separator = System.getProperty("file.separator");
  140. String kawarc_name = new String();
  141. if (Language.getDefaultLanguage().getName().equals("Emacs-Lisp"))
  142. kawarc_name = ".jemacs";
  143. else
  144. kawarc_name =
  145. "/".equals(file_separator) ? ".kawarc.scm"
  146. : "kawarc.scm";
  147. initFile = new File(homeDirectory, kawarc_name);
  148. }
  149. else
  150. scmHomeDirectory = Boolean.FALSE;
  151. Environment.getCurrent().put("home-directory", scmHomeDirectory);
  152. return initFile;
  153. }
  154. /** Evaluate init file, if any, returning error message on failure. */
  155. public static String evalInitFileWithErrorMessage() {
  156. File initFile = getInitFile();
  157. if (initFile != null && initFile.exists()) {
  158. try {
  159. Path path = Path.valueOf(initFile.getPath());
  160. InputStream fs = path.openInputStream();
  161. Environment env = Environment.getCurrent();
  162. Shell.runFile(fs, path, env, true, 0);
  163. } catch (Error e) {
  164. throw e;
  165. } catch (Throwable e) {
  166. return "An error occurred while loading '" + initFile +"' : " + e;
  167. }
  168. }
  169. return null;
  170. }
  171. int getArgs(String[] args, int iArg) {
  172. int avail = args.length - iArg;
  173. if (nextActionArgCount >= 0) {
  174. if (nextActionArgCount > avail)
  175. error("there are only "+avail+" arguments remaining");
  176. ApplicationMainSupport.setArgs(args, iArg, nextActionArgCount);
  177. iArg += nextActionArgCount;
  178. nextActionArgCount = -1;
  179. usedActionArgCount = true;
  180. } else {
  181. ApplicationMainSupport.setArgs(args, iArg, avail);
  182. usedActionArgCount = false;
  183. }
  184. return iArg;
  185. }
  186. public static void setArgs(String[] args, int arg_start) {
  187. ApplicationMainSupport.setArgs(args, arg_start,
  188. args.length - arg_start);
  189. }
  190. public static void getLanguageFromFilenameExtension(String name) {
  191. if (previousLanguage == null) {
  192. previousLanguage = Language.getInstanceFromFilenameExtension(name);
  193. if (previousLanguage != null) {
  194. Language.setDefaults(previousLanguage);
  195. return;
  196. }
  197. }
  198. getLanguage();
  199. }
  200. public static void getLanguage() {
  201. if (previousLanguage == null) {
  202. previousLanguage = Language.getInstance(null);
  203. Language.setDefaults(previousLanguage);
  204. }
  205. }
  206. public static Language setLanguage(String name) {
  207. Language lang = Language.getInstance(name);
  208. if (lang != null) {
  209. if (previousLanguage == null)
  210. Language.setDefaults(lang);
  211. else
  212. Language.setCurrentLanguage(lang);
  213. previousLanguage = lang;
  214. }
  215. return lang;
  216. }
  217. static boolean shutdownRegistered
  218. = WriterManager.instance.registerShutdownHook();
  219. public static int processArgs(String[] args, int iArg, int maxArg) {
  220. return new repl().processArgs(args, iArg, maxArg, true);
  221. }
  222. int nextActionArgCount = -1;
  223. boolean usedActionArgCount = false;
  224. public int processArgs(String[] args, int iArg, int maxArg,
  225. boolean argsOnly) {
  226. boolean something_done = false;
  227. boolean checkedDomTerm = false;
  228. int returnDelta = 0;
  229. if (iArg == maxArg || ! "--connect".equals(args[iArg]))
  230. checkDomTerm();
  231. for ( ; iArg < maxArg; ) {
  232. String arg = args[iArg++];
  233. if (arg.equals("--langserver")) {
  234. try {
  235. Class.forName("kawa.langserver.KawaLanguageServer")
  236. .getMethod("main", String[].class)
  237. .invoke(null, (Object) args);
  238. } catch (Throwable ex) {
  239. WrappedException.rethrow(ex);
  240. }
  241. return -1;
  242. }
  243. if (arg.equals ("-c") || arg.equals ("-e")) {
  244. if (iArg == maxArg)
  245. bad_option(arg);
  246. String expr = args[iArg++];
  247. getLanguage();
  248. iArg = getArgs(args, iArg);
  249. if (arg.equals ("-c"))
  250. checkInitFile();
  251. Language language = Language.getDefaultLanguage();
  252. SourceMessages messages = new SourceMessages();
  253. Throwable ex = Shell.run(language, Environment.getCurrent(),
  254. new CharArrayInPort(expr),
  255. OutPort.outDefault(),
  256. OutPort.errDefault(), messages);
  257. if (ex != null) {
  258. Shell.printError(ex, messages, OutPort.errDefault());
  259. System.exit(-1);
  260. }
  261. something_done = true;
  262. } else if (arg.equals ("-f")) {
  263. if (iArg == maxArg)
  264. bad_option (arg);
  265. String filename = args[iArg++];
  266. getLanguageFromFilenameExtension(filename);
  267. iArg = getArgs(args, iArg);
  268. checkInitFile();
  269. if (! Shell.runFileOrClass(filename, true, 0))
  270. System.exit(-1);
  271. something_done = true;
  272. } else if (arg.startsWith("--script")) {
  273. String count = arg.substring(8);
  274. int skipLines = 0;
  275. if (count.length() > 0) {
  276. try {
  277. skipLines = Integer.parseInt(count);
  278. } catch (Exception ex) {
  279. iArg = maxArg; // force bad_option.
  280. }
  281. }
  282. if (iArg == maxArg)
  283. bad_option (arg);
  284. String filename = args[iArg++];
  285. getLanguageFromFilenameExtension(filename);
  286. iArg = getArgs(args, iArg);
  287. checkInitFile();
  288. if (! Shell.runFileOrClass(filename, true, skipLines))
  289. System.exit(-1);
  290. return -1;
  291. } else if (arg.equals("\\")) {
  292. // Scsh-like "meta-arg". See Kawa manual.
  293. if (iArg == maxArg)
  294. bad_option(arg);
  295. String filename = args[iArg];
  296. ApplicationMainSupport.commandName.set(filename);
  297. InPort freader;
  298. SourceMessages messages = new SourceMessages();
  299. try {
  300. InputStream fstream = new BufferedInputStream(new FileInputStream(filename));
  301. int ch = fstream.read();
  302. if (ch == '#') {
  303. StringBuffer sbuf = new StringBuffer(100);
  304. ArrayList<String> xargs = new ArrayList<String>(10);
  305. int state = 0;
  306. while (ch != '\n' && ch != '\r' && ch >= 0)
  307. ch = fstream.read();
  308. for (;;) {
  309. ch = fstream.read();
  310. if (ch < 0) {
  311. System.err.println("unexpected end-of-file processing argument line for: '" + filename + '\'');
  312. System.exit(-1);
  313. }
  314. if (state == 0) {
  315. if (ch == '\\' || ch == '\'' || ch == '\"') {
  316. state = ch;
  317. continue;
  318. } else if (ch == '\n' || ch == '\r')
  319. break;
  320. else if (ch == ' ' || ch == '\t') {
  321. if (sbuf.length() > 0) {
  322. xargs.add(sbuf.toString());
  323. sbuf.setLength(0);
  324. }
  325. continue;
  326. }
  327. } else if (state == '\\')
  328. state = 0;
  329. else if (ch == state) {
  330. state = 0;
  331. continue;
  332. }
  333. sbuf.append((char) ch);
  334. }
  335. if (sbuf.length() > 0)
  336. xargs.add(sbuf.toString());
  337. int nxargs = xargs.size();
  338. String[] nargs = new String[maxArg+nxargs-1];
  339. iArg--; // back up to just before '\'
  340. System.arraycopy(args, 0, nargs, 0, iArg);
  341. for (int i = 0; i < nxargs; i++)
  342. nargs[iArg+i] = xargs.get(i);
  343. System.arraycopy(args, iArg+1, nargs, iArg+nxargs,
  344. maxArg-iArg-1);
  345. maxArg = nargs.length;
  346. returnDelta += maxArg-args.length;
  347. args = nargs;
  348. continue;
  349. }
  350. } catch (Throwable ex) {
  351. Shell.printError(ex, messages, OutPort.errDefault());
  352. System.exit(1);
  353. }
  354. return -1;
  355. } else if (arg.equals ("-s") || arg.equals ("--")) {
  356. getLanguage();
  357. iArg = getArgs(args, iArg);
  358. checkInitFile();
  359. Shell.run(Language.getDefaultLanguage(), Environment.getCurrent());
  360. something_done = true;
  361. if (! usedActionArgCount)
  362. return -1;
  363. } else if (arg.startsWith("-w")) {
  364. getLanguage();
  365. iArg = getArgs(args, iArg);
  366. checkInitFile();
  367. String msg = startGuiConsole(arg.substring(2));
  368. if (msg != null)
  369. error(arg+" failed: "+msg);
  370. something_done = true;
  371. } else if (arg.equals ("-d")) {
  372. if (iArg == maxArg)
  373. bad_option (arg);
  374. ModuleManager manager = ModuleManager.getInstance();
  375. manager.setCompilationDirectory(args[iArg++]);
  376. } else if (arg.equals("--target") || arg.equals("-target")) {
  377. if (iArg == maxArg)
  378. bad_option(arg);
  379. arg = args[iArg++];
  380. int version = -1;
  381. if (arg.equals("8") || arg.equals("1.8"))
  382. version = ClassType.JDK_1_8_VERSION;
  383. else if (arg.equals("7") || arg.equals("1.7"))
  384. version = ClassType.JDK_1_7_VERSION;
  385. else if (arg.equals("6") || arg.equals("1.6"))
  386. version = ClassType.JDK_1_6_VERSION;
  387. else if (arg.equals("5") || arg.equals("1.5"))
  388. version = ClassType.JDK_1_5_VERSION;
  389. else if (arg.equals("1.4"))
  390. version = ClassType.JDK_1_4_VERSION;
  391. else if (arg.equals("1.3"))
  392. version = ClassType.JDK_1_3_VERSION;
  393. else if (arg.equals("1.2"))
  394. version = ClassType.JDK_1_2_VERSION;
  395. else if (arg.equals("1.1"))
  396. version = ClassType.JDK_1_1_VERSION;
  397. else
  398. bad_option(arg);
  399. Compilation.defaultClassFileVersion = version;
  400. } else if (arg.equals ("-P")) {
  401. if (iArg == maxArg)
  402. bad_option (arg);
  403. Compilation.classPrefixDefault = args[iArg++];
  404. } else if (arg.equals ("-T")) {
  405. if (iArg == maxArg)
  406. bad_option (arg);
  407. compilationTopname = args[iArg++];
  408. } else if (arg.equals ("--main")) {
  409. defaultParseOptions |= Language.PARSE_EMIT_MAIN;
  410. } else if (arg.startsWith("--with-arg-count=")) {
  411. String count = arg.substring(17);
  412. if (count.length() > 0) {
  413. try {
  414. nextActionArgCount = Integer.parseInt(count);
  415. } catch (Exception ex) {
  416. error("non-integer value to --with-arg-count");
  417. }
  418. }
  419. } else if (arg.equals ("-C")) {
  420. if (iArg == maxArg)
  421. bad_option (arg);
  422. compileFiles(args, iArg, maxArg);
  423. return -1;
  424. } else if (arg.equals("--output-format")
  425. || arg.equals("--format")) {
  426. if (iArg == maxArg)
  427. bad_option (arg);
  428. Shell.setDefaultFormat(args[iArg++]);
  429. } else if (arg.equals("--connect")) {
  430. if (iArg == maxArg)
  431. bad_option (arg);
  432. int port;
  433. String portArg = args[iArg++];
  434. if (portArg.equals("-"))
  435. port = 0;
  436. else {
  437. try {
  438. port = Integer.parseInt(portArg);
  439. } catch (NumberFormatException ex) {
  440. bad_option("--connect port#");
  441. port = -1; // never seen.
  442. }
  443. }
  444. try {
  445. Socket socket = new Socket(InetAddress.getByName(null), port);
  446. Telnet conn = new Telnet(socket, true);
  447. java.io.InputStream sin = conn.getInputStream();
  448. java.io.OutputStream sout = conn.getOutputStream();
  449. java.io.PrintStream pout = new PrintStream (sout, true);
  450. System.setIn(sin);
  451. System.setOut(pout);
  452. System.setErr(pout);
  453. checkDomTerm();
  454. } catch (java.io.IOException ex) {
  455. ex.printStackTrace(System.err);
  456. throw new Error(ex.toString());
  457. }
  458. } else if (arg.equals("--server")) {
  459. getLanguage();
  460. if (iArg == maxArg)
  461. bad_option (arg);
  462. int port;
  463. String portArg = args[iArg++];
  464. if (portArg.equals("-"))
  465. port = 0;
  466. else {
  467. try {
  468. port = Integer.parseInt(portArg);
  469. } catch (NumberFormatException ex) {
  470. bad_option ("--server port#");
  471. port = -1; // never seen.
  472. }
  473. }
  474. try {
  475. java.net.ServerSocket ssocket
  476. = new java.net.ServerSocket(port);
  477. port = ssocket.getLocalPort();
  478. System.err.println("Listening on port "+port);
  479. for (;;) {
  480. System.err.print("waiting ... "); System.err.flush();
  481. java.net.Socket client = ssocket.accept();
  482. System.err.println("got connection from "
  483. +client.getInetAddress()
  484. +" port:"+client.getPort());
  485. TelnetRepl.serve(Language.getDefaultLanguage(), client);
  486. }
  487. } catch (java.io.IOException ex) {
  488. throw new Error(ex.toString());
  489. }
  490. } else if (arg.equals("--http-auto-handler")) {
  491. if (iArg + 1 >= maxArg)
  492. bad_option (arg);
  493. /* #ifdef use:com.sun.net.httpserver */
  494. String uriRoot = args[iArg++];
  495. String resourceRoot = args[iArg++];
  496. try {
  497. gnu.kawa.servlet.KawaHttpHandler.addAutoHandler(uriRoot, resourceRoot);
  498. } catch (java.io.IOException ex) {
  499. throw new RuntimeException(ex);
  500. } catch (NoClassDefFoundError ex) {
  501. System.err.println("kawa: HttpServer classes not found");
  502. System.exit(-1);
  503. }
  504. /* #else */
  505. // System.err.println("kawa: HttpServer classes not found");
  506. // System.exit(-1);
  507. /* #endif */
  508. } else if (arg.equals("--http-start")) {
  509. if (iArg >= maxArg)
  510. bad_option("missing httpd port argument");
  511. /* #ifdef use:com.sun.net.httpserver */
  512. String portArg = args[iArg++];
  513. int port;
  514. try {
  515. port = Integer.parseInt(portArg);
  516. } catch (NumberFormatException ex) {
  517. bad_option("malformed server port#");
  518. port = -1; // never seen.
  519. }
  520. try {
  521. gnu.kawa.servlet.KawaHttpHandler
  522. .startServer(port, System.err);
  523. /* #ifdef JAVA6 */
  524. Console console;
  525. if (CheckConsole.haveConsole()
  526. && (console = System.console()) != null) {
  527. if (console.readLine() != null) {
  528. System.err.println("kawa: HttpServer shutting down");
  529. System.exit(0);
  530. }
  531. }
  532. /* #endif */
  533. } catch (NoClassDefFoundError ex) {
  534. System.err.println("kawa: HttpServer classes not found");
  535. System.exit(-1);
  536. } catch (IOException ex) {
  537. throw new RuntimeException(ex);
  538. }
  539. something_done = true;
  540. /* #else */
  541. // System.err.println("kawa: HttpServer classes not found");
  542. // System.exit(-1);
  543. /* #endif */
  544. } else if (arg.equals("--applet")) {
  545. defaultParseOptions |= Language.PARSE_FOR_APPLET;
  546. } else if (arg.equals("--servlet")) {
  547. defaultParseOptions |= Language.PARSE_FOR_SERVLET;
  548. HttpRequestContext.importServletDefinitions = 2;
  549. } else if (arg.startsWith("--browse-manual")) {
  550. String rest = arg.substring(15);
  551. if (rest.length() > 0 && rest.charAt(0) == '=')
  552. rest = rest.substring(1);
  553. String msg = browseManual(null, rest);
  554. if (msg != null)
  555. error(arg+" failed: "+msg);
  556. something_done = true;
  557. } else if (arg.equals("--debug-dump-zip")) {
  558. gnu.expr.ModuleExp.dumpZipPrefix = "kawa-zip-dump-";
  559. } else if (arg.equals("--enable-anf")) {
  560. Compilation.enableANF = true;
  561. } else if (arg.equals("--debug-print-anf")
  562. && Compilation.enableANF) {
  563. Compilation.debugPrintANF = true;
  564. } else if (arg.equals("--debug-print-expr")) {
  565. Compilation.debugPrintExpr = true;
  566. } else if (arg.equals("--debug-print-final-expr")) {
  567. Compilation.debugPrintFinalExpr = true;
  568. } else if (arg.equals("--debug-syntax-pattern-match")) {
  569. SyntaxPattern.printSyntaxPatternMatch = true;
  570. } else if (arg.equals("--debug-error-prints-stack-trace")) {
  571. SourceMessages.debugStackTraceOnError = true;
  572. } else if (arg.equals("--debug-warning-prints-stack-trace")) {
  573. SourceMessages.debugStackTraceOnWarning = true;
  574. } else if (arg.equals("--diagnostic-strip-directories"))
  575. SourceMessages.stripDirectoriesDefault = true;
  576. else if (arg.equals("--module-nonstatic")
  577. || arg.equals("--no-module-static")) {
  578. Compilation.moduleStatic = Compilation.MODULE_NONSTATIC;
  579. } else if (arg.equals("--module-static")) {
  580. Compilation.moduleStatic = Compilation.MODULE_STATIC;
  581. } else if (arg.equals("--module-static-run")) {
  582. Compilation.moduleStatic = Compilation.MODULE_STATIC_RUN;
  583. } else if (arg.equals("--no-inline")
  584. || arg.equals("--inline=none")) {
  585. Compilation.inlineOk = false;
  586. } else if (arg.equals("--no-console"))
  587. CheckConsole.setHaveConsole(false);
  588. else if (arg.equals("--console"))
  589. CheckConsole.setHaveConsole(true);
  590. else if (arg.equals("--inline")) {
  591. Compilation.inlineOk = true;
  592. } else if (arg.equals("--cps")) {
  593. Compilation.defaultCallConvention
  594. = Compilation.CALL_WITH_CONTINUATIONS;
  595. } else if (arg.equals("--full-tailcalls")) {
  596. Compilation.defaultCallConvention
  597. = Compilation.CALL_WITH_TAILCALLS;
  598. } else if (arg.equals("--no-full-tailcalls")) {
  599. Compilation.defaultCallConvention
  600. = Compilation.CALL_WITH_RETURN;
  601. } else if (arg.equals("--pedantic")) {
  602. Language.requirePedantic = true;
  603. } else if (arg.equals("--help")) {
  604. printOptions(System.out);
  605. System.exit(0);
  606. } else if (arg.equals("--author")) {
  607. System.out.println("Per Bothner <per@bothner.com>");
  608. System.exit(0);
  609. } else if (arg.equals("--version")) {
  610. System.out.print("Kawa ");
  611. System.out.print(Version.getVersion());
  612. System.out.println();
  613. System.out.println("Copyright (C) 2019 Per Bothner");
  614. something_done = true;
  615. } else if (arg.startsWith("-D")) {
  616. int eq = arg.indexOf('=');
  617. if (eq == 2)
  618. error("bad option '"+arg+"' - empty key before '='");
  619. String key, val;
  620. if (eq < 0) {
  621. key = arg.substring(2);
  622. val = "";
  623. }
  624. else {
  625. key = arg.substring(2, eq);
  626. val = arg.substring(eq+1);
  627. }
  628. System.setProperty(key, val);
  629. } else if (arg.length () > 0 && arg.charAt(0) == '-') {
  630. // Check if arg is a known language name.
  631. boolean doubleDash = arg.length() > 2 && arg.charAt(1) == '-';
  632. String name = arg.substring(doubleDash ? 2 : 1);
  633. Language lang = setLanguage(name);
  634. if (lang == null) {
  635. // See if arg is a valid Compilation option, and if so set it.
  636. int eq = name.indexOf('=');
  637. String opt_value;
  638. if (eq < 0)
  639. opt_value = null;
  640. else {
  641. opt_value = name.substring(eq+1);
  642. name = name.substring(0, eq);
  643. }
  644. // Convert "--no-xxx" to "--xxx=no":
  645. boolean startsWithNo
  646. = name.startsWith("no-") && name.length() > 3;
  647. boolean addedNo = false;
  648. if (opt_value == null && startsWithNo) {
  649. opt_value = "no";
  650. name = name.substring(3);
  651. addedNo = true;
  652. }
  653. String msg = Compilation.options.set(name, opt_value);
  654. if (msg != null) {
  655. if (msg == gnu.text.Options.UNKNOWN) {
  656. if (addedNo)
  657. msg = "unknown option '"+name+"'";
  658. // It wasn't a valid Compilation option.
  659. else if (startsWithNo)
  660. msg = "both '--no-' prefix and '="+
  661. opt_value+"' specified";
  662. }
  663. if (msg == gnu.text.Options.UNKNOWN) {
  664. bad_option(arg);
  665. } else {
  666. error("bad option '" + arg + "': " + msg);
  667. }
  668. }
  669. }
  670. } else if (ApplicationMainSupport.processSetProperty(arg))
  671. ;
  672. else if (argsOnly || (something_done && !usedActionArgCount))
  673. break;
  674. else {
  675. String filename = arg;
  676. getLanguageFromFilenameExtension(filename);
  677. iArg = getArgs(args, iArg);
  678. checkInitFile();
  679. if (! Shell.runFileOrClass(filename, false, 0))
  680. System.exit(-1);
  681. something_done = true;
  682. if (! usedActionArgCount)
  683. break;
  684. }
  685. }
  686. if (! something_done) {
  687. getLanguage();
  688. iArg = getArgs(args, iArg);
  689. checkInitFile();
  690. if (! CheckConsole.haveConsole())
  691. startGuiConsole("");
  692. else {
  693. boolean ok = Shell.run(Language.getDefaultLanguage(),
  694. Environment.getCurrent());
  695. if (! ok)
  696. System.exit(-1);
  697. }
  698. }
  699. // Adjust return value to index in *incoming* array.
  700. // This is a hack to compensate for meta-arg handling.
  701. return something_done ? -1 : iArg-returnDelta;
  702. }
  703. public static void compileFiles (String[] args, int iArg, int maxArg)
  704. {
  705. ModuleManager manager = ModuleManager.getInstance();
  706. Compilation[] comps = new Compilation[maxArg-iArg];
  707. ModuleInfo[] infos = new ModuleInfo[maxArg-iArg];
  708. SourceMessages messages = new SourceMessages();
  709. for (int i = iArg; i < maxArg; i++) {
  710. String arg = args[i];
  711. getLanguageFromFilenameExtension(arg);
  712. Language language = Language.getDefaultLanguage();
  713. Compilation comp = null;
  714. try {
  715. InPort fstream;
  716. try {
  717. Path path = Path.valueOf(arg);
  718. fstream = Shell.openFile(path.openInputStream(), path);
  719. } catch (java.io.FileNotFoundException ex) {
  720. System.err.println(ex);
  721. System.exit(-1);
  722. break; // Kludge to shut up compiler.
  723. }
  724. ModuleInfo minfo = manager.findWithSourcePath(arg);
  725. if (compilationTopname != null) {
  726. String cname
  727. = Mangling.mangleNameIfNeeded(compilationTopname);
  728. if (Compilation.classPrefixDefault != null)
  729. cname = Compilation.classPrefixDefault + cname;
  730. minfo.setClassName(cname);
  731. }
  732. comp = language.parse(fstream, messages,
  733. defaultParseOptions, minfo);
  734. infos[i-iArg] = minfo;
  735. comps[i-iArg] = comp;
  736. } catch (Exception ex) {
  737. if (! (ex instanceof SyntaxException)
  738. || ((SyntaxException) ex).getMessages() != messages)
  739. internalError(ex, comp, arg);
  740. }
  741. if (messages.seenErrorsOrWarnings()) {
  742. System.err.println("(compiling "+arg+')');
  743. if (messages.checkErrors(System.err, 20))
  744. System.exit(1);
  745. }
  746. }
  747. for (int i = iArg; i < maxArg; i++) {
  748. String arg = args[i];
  749. Compilation comp = comps[i-iArg];
  750. try {
  751. System.err.println("(compiling "+arg+" to "+comp.mainClass.getName()+')');
  752. infos[i-iArg].loadByStages(Compilation.CLASS_WRITTEN);
  753. boolean sawErrors = messages.seenErrors();
  754. messages.checkErrors(System.err, 50);
  755. if (sawErrors)
  756. System.exit(-1);
  757. comps[i-iArg] = comp;
  758. sawErrors = messages.seenErrors();
  759. messages.checkErrors(System.err, 50);
  760. if (sawErrors)
  761. System.exit(-1);
  762. } catch (Exception ex) {
  763. internalError(ex, comp, arg);
  764. }
  765. }
  766. }
  767. static void internalError(Throwable ex, Compilation comp, Object arg) {
  768. try { comp.getMessages().checkErrors(System.err, 50); }
  769. catch (Exception e) { }
  770. StringBuffer sbuf = new StringBuffer();
  771. if (comp != null) {
  772. String file = comp.getFileName();
  773. int line = comp.getLineNumber();
  774. if (file != null && line > 0) {
  775. sbuf.append(file);
  776. sbuf.append(':');
  777. sbuf.append(line);
  778. sbuf.append(": ");
  779. }
  780. }
  781. sbuf.append("internal error while compiling ");
  782. sbuf.append(arg);
  783. System.err.println(sbuf.toString());
  784. ex.printStackTrace(System.err);
  785. System.exit(-1);
  786. }
  787. public static void main(String args[]) {
  788. try {
  789. ExitCalled.push();
  790. new repl().processArgs(args, 0, args.length, false);
  791. } finally {
  792. if (! shutdownRegistered) {
  793. // Redundant if registerShutdownHook succeeded (e.g on JDK 1.3).
  794. OutPort.runCleanups();
  795. }
  796. ModuleBody.exitDecrement();
  797. ExitCalled.pop();
  798. }
  799. }
  800. private static boolean checkedDomTerm;
  801. public static void checkDomTerm() {
  802. if (checkedDomTerm)
  803. return;
  804. checkedDomTerm = true;
  805. String dversion = CheckConsole.getDomTermVersionInfo();
  806. if (dversion != null) {
  807. if (dversion.indexOf("err-handled;") < 0)
  808. TermErrorStream.setSystemErr(false);
  809. OutPort.getSystemOut().setDomTerm(true);
  810. OutPort.getSystemErr().setDomTerm(true);
  811. }
  812. /*else if (isAnsiTerminal())
  813. TermErrorStream.setSystemErr(true);
  814. */
  815. }
  816. private static boolean isAnsiTerminal() {
  817. return CheckConsole.haveConsole(); // FIXME
  818. }
  819. private static Throwable startJfxConsole() {
  820. try {
  821. Object replBackend =
  822. Class.forName("kawa.DomTermBackend").newInstance();
  823. Class.forName("org.domterm.javafx.WebTerminalApp")
  824. .getMethod("startApp",
  825. Class.forName("org.domterm.Backend"),
  826. String.class, String[].class)
  827. .invoke(null, replBackend, "Kawa (DomTerm)", null);
  828. return null;
  829. } catch (Throwable ex) {
  830. return ex;
  831. }
  832. }
  833. public static String startGuiConsole(String command) {
  834. try {
  835. if ("".equals(command)) {
  836. String defaults = CheckConsole.consoleType();
  837. String rest = ";"+defaults+";";
  838. for (;;) {
  839. int semi = rest.indexOf(';', 1);
  840. if (semi < 0)
  841. break;
  842. String cur = rest.substring(1, semi).trim();
  843. rest = rest.substring(semi);
  844. if (cur.length() > 0
  845. && startGuiConsole(cur) == null)
  846. return null;
  847. }
  848. return "no window type ("+defaults+") worked";
  849. }
  850. if ("javafx".equals(command)) {
  851. Throwable ex = startJfxConsole();
  852. return ex == null ? null : ex.toString();
  853. }
  854. if ("swing".equals(command)) {
  855. Class.forName("kawa.GuiConsole").newInstance();
  856. return null;
  857. }
  858. if ("console".equals(command)) {
  859. Shell.run(Language.getDefaultLanguage(), Environment.getCurrent());
  860. return null;
  861. }
  862. if ("qtdomterm".equals(command))
  863. command = "browser=qtdomterm --connect localhost:%W";
  864. Object result = Class.forName("kawa.DomTermBackend")
  865. .getMethod("startDomTermConsole", String.class)
  866. .invoke(null, command);
  867. return result == null ? null : result.toString();
  868. } catch (Throwable ex) {
  869. return "caught exception "+ex.toString();
  870. }
  871. }
  872. public static String browseManual(String path, String browserCommand) {
  873. try {
  874. String kawaHome = System.getProperty("kawa.home");
  875. if (kawaHome == null)
  876. return "kawa.home not set";
  877. File manualFile = new File(kawaHome+"/doc/kawa-manual.epub");
  878. if (! manualFile.exists())
  879. return manualFile+" does not exist";
  880. if (browserCommand == null || browserCommand.length() == 0) {
  881. try {
  882. Class.forName("gnu.kawa.servlet.KawaHttpHandler");
  883. browserCommand = "browser";
  884. } catch (Throwable ex1) {
  885. try {
  886. Class.forName("gnu.kawa.javafx.KawaJavafxApplication");
  887. browserCommand = "javafx";
  888. } catch (Throwable ex2) {
  889. return "don't know how to display manual (neither JavaFX or HttpServer classes found)";
  890. }
  891. }
  892. }
  893. if (browserCommand.equals("javafx")) {
  894. // FIXME ignores 'path' argument
  895. String filename = kawaHome+"/doc/browse-kawa-manual";
  896. setLanguage("scheme");
  897. Shell.runFileOrClass(filename, false, 0);
  898. return null;
  899. }
  900. /* #ifdef use:com.sun.net.httpserver */
  901. String defaultUrl = "index.html";
  902. String pathPrefix = "jar:file:" + manualFile + "!/OEBPS";
  903. gnu.kawa.servlet.KawaHttpHandler.addStaticFileHandler("/kawa-manual/",
  904. pathPrefix, defaultUrl, true);
  905. int htport = 0;
  906. com.sun.net.httpserver.HttpServer httpHandler =
  907. gnu.kawa.servlet.KawaHttpHandler.startServer(htport, System.err);
  908. htport = httpHandler.getAddress().getPort();
  909. if (path == null || path.length() == 0)
  910. path = defaultUrl;
  911. String webUrl = "http://127.0.0.1:"+htport+"/kawa-manual/" + path;
  912. if (browserCommand.equals("google-chrome"))
  913. browserCommand = "google-chrome --app=%U";
  914. if (browserCommand.equals("browser")) {
  915. if (! Desktop.isDesktopSupported())
  916. return "using default desktop browser not supported";
  917. Desktop.getDesktop().browse(new URI(webUrl));
  918. return null;
  919. } else {
  920. if (browserCommand.indexOf('%') < 0)
  921. browserCommand = browserCommand + " %U";
  922. try {
  923. Runtime.getRuntime().exec(browserCommand.replace("%U", webUrl));
  924. } catch (Throwable ex) {
  925. return "cannot read manual (using command: "+browserCommand+")";
  926. }
  927. return null;
  928. }
  929. /* #else */
  930. // return "cannot read manual using builin http server";
  931. /* #endif */
  932. } catch (Throwable ex) {
  933. return "caught exception "+ex.toString();
  934. }
  935. }
  936. }