1 #!/usr/bin/env python 2 3 from errors import * 4 from os import rename 5 from os.path import abspath, exists, join, split 6 from subprocess import Popen, PIPE 7 from time import time 8 import importer, deducer, optimiser, generator, translator 9 import sys 10 11 libdirs = [ 12 join(split(__file__)[0], "lib"), 13 "/usr/share/lichen/lib" 14 ] 15 16 def load_module(filename, module_name): 17 for libdir in libdirs: 18 path = join(libdir, filename) 19 if exists(path): 20 return i.load_from_file(path, module_name) 21 return None 22 23 def show_missing(missing): 24 missing = list(missing) 25 missing.sort() 26 for module_name, name in missing: 27 print >>sys.stderr, "Module %s references an unknown object: %s" % (module_name, name) 28 29 def stopwatch(activity, now): 30 print >>sys.stderr, "%s took %.2f seconds" % (activity, time() - now) 31 return time() 32 33 def call(tokens, verbose=False): 34 out = not verbose and PIPE or None 35 cmd = Popen(tokens, stdout=out, stderr=out) 36 stdout, stderr = cmd.communicate() 37 return cmd.wait() 38 39 # Main program. 40 41 if __name__ == "__main__": 42 args = sys.argv[1:] 43 path = libdirs + sys.path[:] 44 45 # Determine the options and arguments. 46 47 verbose = False 48 reset = False 49 debug = False 50 make = True 51 make_verbose = True 52 53 filenames = [] 54 outputs = [] 55 56 # Obtain program filenames by default. 57 58 l = filenames 59 60 for arg in args: 61 if arg == "-v": verbose = True 62 elif arg == "-r": reset = True 63 elif arg == "-g": debug = True 64 elif arg == "-c": make = False 65 elif arg == "-q": make_verbose = False 66 elif arg == "-o": l = outputs 67 else: 68 l.append(arg) 69 70 # Revert to collecting program filenames after obtaining the output 71 # executable filename. 72 73 if l is outputs: l = filenames 74 75 # Obtain the program filename. 76 77 if len(filenames) > 1: 78 print >>sys.stderr, "Only one main program file can be specified." 79 sys.exit(1) 80 81 filename = abspath(filenames[0]) 82 path.append(split(filename)[0]) 83 84 # Obtain the output filename. 85 86 output = outputs and outputs[0] or "main" 87 88 # Define the output data directories. 89 90 datadir = "_lplc" 91 cache_dir = join(datadir, "_cache") 92 deduced_dir = join(datadir, "_deduced") 93 output_dir = join(datadir, "_output") 94 generated_dir = join(datadir, "_generated") 95 96 # Load the program. 97 98 try: 99 start = now = time() 100 101 i = importer.Importer(path, cache_dir, verbose) 102 m = i.initialise(filename, reset) 103 success = i.finalise() 104 105 now = stopwatch("Inspection", now) 106 107 # Check for success, indicating missing references otherwise. 108 109 if not success: 110 show_missing(i.missing) 111 sys.exit(1) 112 113 d = deducer.Deducer(i, deduced_dir) 114 d.to_output() 115 116 now = stopwatch("Deduction", now) 117 118 o = optimiser.Optimiser(i, d, output_dir) 119 o.to_output() 120 121 now = stopwatch("Optimisation", now) 122 123 g = generator.Generator(i, o, generated_dir) 124 g.to_output(debug) 125 126 now = stopwatch("Generation", now) 127 128 t = translator.Translator(i, d, o, generated_dir) 129 t.to_output() 130 131 now = stopwatch("Translation", now) 132 133 # Compile the program unless otherwise indicated. 134 135 if make: 136 make_clean_cmd = ["make", "-C", generated_dir, "clean"] 137 make_cmd = make_clean_cmd[:-1] 138 139 retval = call(make_clean_cmd, make_verbose) 140 if not retval: 141 retval = call(make_cmd, make_verbose) 142 143 if not retval: 144 stopwatch("Compilation", now) 145 else: 146 sys.exit(retval) 147 148 # Move the executable into the current directory. 149 150 rename(join(generated_dir, "main"), output) 151 152 # Report any errors. 153 154 except ProcessingError, exc: 155 print exc 156 if "-tb" in args: 157 raise 158 sys.exit(1) 159 160 else: 161 sys.exit(0) 162 163 # vim: tabstop=4 expandtab shiftwidth=4