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