/src/org/ooc/frontend/CommandLine.java

http://github.com/nddrylliog/ooc · Java · 522 lines · 400 code · 121 blank · 1 comment · 196 complexity · 1fcbbfa7ac6acf0577d07267bcbee40f MD5 · raw file

  1. package org.ooc.frontend;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.io.InputStreamReader;
  6. import java.util.ArrayList;
  7. import java.util.HashSet;
  8. import java.util.List;
  9. import java.util.Set;
  10. import java.util.StringTokenizer;
  11. import org.ooc.backend.cdirty.CGenerator;
  12. import org.ooc.backend.json.JSONGenerator;
  13. import org.ooc.frontend.compilers.Clang;
  14. import org.ooc.frontend.compilers.Gcc;
  15. import org.ooc.frontend.compilers.Icc;
  16. import org.ooc.frontend.compilers.Tcc;
  17. import org.ooc.frontend.drivers.CombineDriver;
  18. import org.ooc.frontend.drivers.Driver;
  19. import org.ooc.frontend.drivers.SequenceDriver;
  20. import org.ooc.frontend.model.Import;
  21. import org.ooc.frontend.model.Module;
  22. import org.ooc.frontend.parser.ModuleParser;
  23. import org.ooc.frontend.parser.Parser;
  24. import org.ooc.middle.Tinkerer;
  25. import org.ooc.utils.FileUtils;
  26. import org.ooc.utils.ProcessUtils;
  27. import org.ubi.CompilationFailedError;
  28. import org.ubi.FileLocation;
  29. public class CommandLine {
  30. public static void main(String[] argv) throws InterruptedException, IOException {
  31. new CommandLine(argv);
  32. }
  33. private BuildParams params = new BuildParams();
  34. private Driver driver = new CombineDriver(params);
  35. class Pair {
  36. String in;
  37. String out;
  38. public Pair(String in) {
  39. this.in = in;
  40. this.out = null;
  41. }
  42. }
  43. public CommandLine(String[] args) throws InterruptedException, IOException {
  44. List<Pair> modulePaths = new ArrayList<Pair>();
  45. List<String> nasms = new ArrayList<String>();
  46. for(String arg: args) {
  47. if(arg.startsWith("-")) {
  48. String option = arg.substring(1);
  49. if(option.startsWith("sourcepath=")) {
  50. String sourcePathOption = arg.substring(arg.indexOf('=') + 1);
  51. StringTokenizer tokenizer = new StringTokenizer(sourcePathOption, File.pathSeparator);
  52. while(tokenizer.hasMoreTokens()) {
  53. params.sourcePath.add(tokenizer.nextToken());
  54. }
  55. } else if(option.startsWith("outpath=")) {
  56. params.outPath = new File(arg.substring(arg.indexOf('=') + 1));
  57. params.clean = false;
  58. } else if(option.startsWith("outlib=")) {
  59. params.outlib = arg.substring(arg.indexOf('=') + 1);
  60. } else if(option.startsWith("incpath=")) {
  61. params.incPath.add(arg.substring(arg.indexOf('=') + 1));
  62. } else if(option.startsWith("entrypoint")) {
  63. params.entryPoint = arg.substring(arg.indexOf('=') + 1);
  64. } else if(option.startsWith("j")) {
  65. params.sequenceThreads = Integer.parseInt(arg.substring(2));
  66. } else if(option.startsWith("I")) {
  67. params.incPath.add(arg.substring(2));
  68. } else if(option.startsWith("libpath=")) {
  69. params.libPath.add(arg.substring(arg.indexOf('=') + 1));
  70. } else if(option.startsWith("linker=")) {
  71. params.linker = arg.substring(arg.indexOf('=') + 1);
  72. } else if(option.startsWith("editor=")) {
  73. params.editor = arg.substring(arg.indexOf('=') + 1);
  74. } else if(option.equals("c")) {
  75. params.link = false;
  76. } else if(option.startsWith("L")) {
  77. params.libPath.add(arg.substring(2));
  78. } else if(option.startsWith("D")) {
  79. params.defines.add(arg.substring(2));
  80. } else if(option.startsWith("U")) {
  81. params.defines.remove(arg.substring(2));
  82. } else if(option.startsWith("l")) {
  83. params.dynamicLibs.add(arg.substring(2));
  84. } else if(option.equals("dyngc")) {
  85. System.out.println("Deprecated option -dyngc, you should use -gc=dynamic instead.");
  86. params.dynGC = true;
  87. params.defineSymbol(BuildParams.GC_DEFINE);
  88. } else if(option.equals("nogc")) {
  89. System.out.println("Deprecated option -nogc, you should use -gc=off instead.");
  90. params.enableGC = false;
  91. params.undefineSymbol(BuildParams.GC_DEFINE);
  92. } else if(option.startsWith("gc=")) {
  93. String subOption = option.substring(3);
  94. if(subOption.equals("off")) {
  95. params.enableGC = false;
  96. params.undefineSymbol(BuildParams.GC_DEFINE);
  97. } else if(subOption.equals("dynamic")) {
  98. params.enableGC = true;
  99. params.defineSymbol(BuildParams.GC_DEFINE);
  100. params.dynGC = true;
  101. } else if(subOption.equals("static")) {
  102. params.enableGC = true;
  103. params.defineSymbol(BuildParams.GC_DEFINE);
  104. params.dynGC = false;
  105. } else {
  106. System.out.println("Unrecognized option "+option
  107. +", valid values are gc=off, gc=dynamic, gc=static");
  108. }
  109. } else if(option.equals("noclean")) {
  110. params.clean = false;
  111. } else if(option.equals("nomain")) {
  112. params.defaultMain = false;
  113. } else if(option.equals("nolines")) {
  114. params.lineDirectives = false;
  115. } else if(option.equals("shout")) {
  116. params.shout = true;
  117. } else if(option.equals("timing") || option.equals("t")) {
  118. params.timing = true;
  119. } else if(option.equals("debug") || option.equals("g")) {
  120. params.debug = true;
  121. params.clean = false;
  122. } else if(option.equals("verbose") || option.equals("v")) {
  123. params.verbose = true;
  124. } else if(option.equals("veryVerbose") || option.equals("vv")) {
  125. params.veryVerbose = true;
  126. } else if(option.equals("run") || option.equals("r")) {
  127. params.run = true;
  128. } else if(option.startsWith("o=")) {
  129. if(modulePaths.isEmpty()) {
  130. System.out.println("Using '-o' option before any .ooc file, ignoring..." +
  131. "\n(you should do something like ooc file.ooc -o=myexecutable");
  132. } else {
  133. modulePaths.get(modulePaths.size() - 1).out = option.substring(2);
  134. }
  135. } else if(option.startsWith("driver=")) {
  136. String driverName = option.substring("driver=".length());
  137. if(driverName.equals("combine")) {
  138. driver = new CombineDriver(params);
  139. } else if(driverName.equals("sequence")) {
  140. driver = new SequenceDriver(params);
  141. } else {
  142. System.out.println("Unknown driver '"+driverName+"'");
  143. }
  144. } else if(option.startsWith("blowup=")) {
  145. params.blowup = Integer.parseInt(option.substring("blowup=".length()));
  146. } else if(option.equals("V") || option.equals("-version") || option.equals("version")) {
  147. CompilerVersion.printVersion();
  148. System.exit(0);
  149. } else if(option.equals("h") || option.equals("-help") || option.equals("help")) {
  150. Help.printHelp();
  151. System.exit(0);
  152. } else if(option.startsWith("gcc")) {
  153. if(option.startsWith("gcc=")) {
  154. params.compiler = new Gcc(option.substring(4));
  155. } else {
  156. params.compiler = new Gcc();
  157. }
  158. } else if(option.startsWith("icc")) {
  159. if(option.startsWith("icc=")) {
  160. params.compiler = new Icc(option.substring(4));
  161. } else {
  162. params.compiler = new Icc();
  163. }
  164. } else if(option.startsWith("tcc")) {
  165. if(option.startsWith("tcc=")) {
  166. params.compiler = new Tcc(option.substring(4));
  167. } else {
  168. params.compiler = new Tcc();
  169. }
  170. params.dynGC = true;
  171. } else if(option.startsWith("clang")) {
  172. if(option.startsWith("clang=")) {
  173. params.compiler = new Clang(option.substring(6));
  174. } else {
  175. params.compiler = new Clang();
  176. }
  177. } else if(option.equals("onlygen")) {
  178. params.compiler = null;
  179. params.gccByDefault = false;
  180. params.clean = false;
  181. } else if(option.startsWith("backend=")) {
  182. params.backend = option.substring("backend=".length());
  183. if(!params.backend.equals("c") && !params.backend.equals("json")) {
  184. System.out.println("Unrecognized backend: " + params.backend);
  185. params.backend = "c";
  186. }
  187. } else if(option.equals("help-backends") || option.equals("-help-backends")) {
  188. Help.printHelpBackends();
  189. System.exit(0);
  190. } else if(option.equals("help-gcc") || option.equals("-help-gcc")) {
  191. Help.printHelpGcc();
  192. System.exit(0);
  193. } else if(option.equals("help-make") || option.equals("-help-make")) {
  194. Help.printHelpMake();
  195. System.exit(0);
  196. } else if(option.equals("help-none") || option.equals("-help-none")) {
  197. Help.printHelpNone();
  198. System.exit(0);
  199. } else if(option.equals("slave")) {
  200. params.slave = true;
  201. } else if(option.startsWith("m")) {
  202. String arch = arg.substring(2);
  203. if (arch.equals("32") || arch.equals("64"))
  204. params.arch = arg.substring(2);
  205. else
  206. System.out.println("Unrecognized architecture: " + arch);
  207. } else if(option.startsWith("archs=")) {
  208. params.fatArchitectures = arg.substring("archs=".length() + 1).split(",");
  209. } else if(option.startsWith("osxtarget=")) {
  210. params.osxSDKAndDeploymentTarget = arg.substring("osxtarget=".length() + 1);
  211. } else {
  212. System.err.println("Unrecognized option: '"+arg+"'");
  213. }
  214. } else if(arg.startsWith("+")) {
  215. params.compilerArgs.add(arg.substring(1));
  216. } else {
  217. String lowerArg = arg.toLowerCase();
  218. if(lowerArg.endsWith(".s")) {
  219. nasms.add(arg);
  220. } else if(lowerArg.endsWith(".ooc")) {
  221. modulePaths.add(new Pair(arg));
  222. } else {
  223. if(lowerArg.contains(".")) {
  224. params.additionals.add(arg);
  225. } else {
  226. modulePaths.add(new Pair(arg+".ooc"));
  227. }
  228. }
  229. }
  230. }
  231. if(modulePaths.isEmpty()) {
  232. System.err.println("ooc: no files.");
  233. return;
  234. }
  235. if (params.compiler == null && params.gccByDefault) {
  236. if (params.verbose)
  237. System.out.println("No compiler given ... using GCC");
  238. params.compiler = new Gcc();
  239. }
  240. if(!nasms.isEmpty()) {
  241. driver.compileNasms(nasms, params.additionals);
  242. }
  243. if(params.sourcePath.isEmpty()) params.sourcePath.add(".");
  244. params.sourcePath.add(params.sdkLocation.getPath());
  245. int errorCode = 0;
  246. BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
  247. do {
  248. ModuleParser.clearCache();
  249. int successCount = 0;
  250. for(Pair modulePath: modulePaths) {
  251. try {
  252. int code = parse(modulePath);
  253. if(code == 0) {
  254. successCount++;
  255. } else {
  256. errorCode = 2; // C compiler failure.
  257. }
  258. } catch(CompilationFailedError err) {
  259. if(errorCode == 0) errorCode = 1; // ooc failure
  260. System.err.println(err);
  261. fail();
  262. if(params.editor.length() > 0) {
  263. System.out.println("Press [Enter] to launch "+params.editor);
  264. reader.readLine();
  265. launchEditor(params.editor, err);
  266. }
  267. }
  268. if(params.clean && params.backend.equals("c")) FileUtils.deleteRecursive(params.outPath);
  269. }
  270. if(modulePaths.size() > 1) {
  271. System.out.println(modulePaths.size()+" compiled ("+successCount
  272. +" success, "+(modulePaths.size() - successCount)+" failed)");
  273. }
  274. if(params.slave) {
  275. System.out.println(".-------------( ready )-------------.\n");
  276. reader.readLine();
  277. } else {
  278. if(successCount < modulePaths.size()) {
  279. System.exit(errorCode);
  280. }
  281. }
  282. } while(params.slave);
  283. }
  284. private void ok() {
  285. if(params.shout) {
  286. if(Target.guessHost() == Target.LINUX) {
  287. System.out.println("\033[1;32m[ OK ]\033[m");
  288. } else {
  289. System.out.println("[ OK ]");
  290. }
  291. }
  292. }
  293. private void fail() {
  294. if(params.shout) {
  295. if(Target.guessHost() == Target.LINUX) {
  296. System.out.println("\033[1;31m[FAIL]\033[m");
  297. } else {
  298. System.out.println("[FAIL]");
  299. }
  300. }
  301. }
  302. private void launchEditor(final String editor, final CompilationFailedError err) {
  303. if(err.getLocation() == null) return;
  304. Thread thread = new Thread() {
  305. @Override
  306. public void run() {
  307. try {
  308. ProcessBuilder builder = new ProcessBuilder();
  309. FileLocation location = err.getLocation();
  310. String absolutePath = new File(location.getFileName()).getAbsolutePath();
  311. if(editor.endsWith("geany")) {
  312. builder.command(editor, absolutePath+":"+location.getLineNumber()+":"+(location.getLinePos() - 1));
  313. } else if(editor.endsWith("mate")) {
  314. builder.command(editor, absolutePath, "-l", String.valueOf(location.getLineNumber()));
  315. } else if(editor.endsWith("gedit")) {
  316. builder.command(editor, absolutePath, "+" + String.valueOf(location.getLineNumber()));
  317. } else {
  318. builder.command(editor, absolutePath);
  319. }
  320. ProcessUtils.redirectIO(builder.start());
  321. } catch (IOException e) {
  322. e.printStackTrace();
  323. }
  324. }
  325. };
  326. thread.setDaemon(true);
  327. thread.start();
  328. try {
  329. // allow time for the program startup
  330. Thread.sleep(3);
  331. } catch (InterruptedException e) {
  332. e.printStackTrace();
  333. }
  334. }
  335. protected int parse(Pair modulePath) throws InterruptedException, IOException {
  336. params.outPath.mkdirs();
  337. long tt1 = System.nanoTime();
  338. Module module = new Parser(params).parse(modulePath.in);
  339. module.setMain(true);
  340. long tt2 = System.nanoTime();
  341. if(params.verbose) System.out.println("Finished parsing, now tinkering...");
  342. ArrayList<Module> list = new ArrayList<Module>();
  343. collectModules(module, list);
  344. tinker(list);
  345. long tt3 = System.nanoTime();
  346. output(module, new HashSet<Module>());
  347. long tt4 = System.nanoTime();
  348. int code = 0;
  349. if(params.compiler != null && params.backend.equals("c")) {
  350. code = driver.compile(module, modulePath.out == null ? module.getSimpleName() : modulePath.out);
  351. }
  352. long tt5 = System.nanoTime();
  353. if(params.timing) {
  354. System.out.printf("parse: %.2f ms\ttinker: %.2f ms\toutput: %.2f ms\tcc: %.2f ms\tTOTAL %.2f ms\n",
  355. Float.valueOf((tt2 - tt1) / 1000000.0f),
  356. Float.valueOf((tt3 - tt2) / 1000000.0f),
  357. Float.valueOf((tt4 - tt3) / 1000000.0f),
  358. Float.valueOf((tt5 - tt4) / 1000000.0f),
  359. Float.valueOf((tt5 - tt1) / 1000000.0f));
  360. }
  361. if(code == 0) {
  362. if(params.shout) ok();
  363. if(params.run) {
  364. ProcessBuilder builder = new ProcessBuilder();
  365. builder.command("./"+module.getSimpleName());
  366. Process process = builder.start();
  367. ProcessUtils.redirectIO(process);
  368. int exitCode = process.waitFor();
  369. if(exitCode != 0) {
  370. System.out.println("Unerwarteter Programmabbruch. Return code: "+exitCode+". Please don't cry :(");
  371. }
  372. }
  373. } else if(params.shout) fail();
  374. return code;
  375. }
  376. protected void output(Module module, Set<Module> done) throws IOException {
  377. done.add(module);
  378. for(Import imp: module.getAllImports()) {
  379. if(!done.contains(imp.getModule())) {
  380. output(imp.getModule(), done);
  381. }
  382. }
  383. if(params.backend.equals("c")) {
  384. new CGenerator(params.outPath, module).generate(params);
  385. } else {
  386. new JSONGenerator(params.outPath, module).generate(params);
  387. }
  388. }
  389. protected void collectModules(Module module, List<Module> list) throws IOException {
  390. list.add(module);
  391. for(Import imp: module.getAllImports()) {
  392. if(!list.contains(imp.getModule())) {
  393. collectModules(imp.getModule(), list);
  394. }
  395. }
  396. }
  397. protected void tinker(List<Module> list) throws IOException {
  398. Tinkerer tink = new Tinkerer();
  399. tink.process(list, params);
  400. }
  401. }