PageRenderTime 435ms CodeModel.GetById 120ms app.highlight 175ms RepoModel.GetById 127ms app.codeStats 1ms

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