diff python/zcc.py @ 331:a78b41ff6ad2

Added better recipe files
author Windel Bouwman
date Fri, 07 Feb 2014 12:39:59 +0100
parents 8f6f3ace4e78
children 87feb8a23b4d
line wrap: on
line diff
--- a/python/zcc.py	Fri Feb 07 12:08:40 2014 +0100
+++ b/python/zcc.py	Fri Feb 07 12:39:59 2014 +0100
@@ -1,21 +1,17 @@
 #!/usr/bin/env python
 
 import sys
+import os
 import argparse
 import logging
+import yaml
 
-from ppci.c3 import AstPrinter
 from ppci.buildtasks import Compile
 from ppci.tasks import TaskRunner
+from ppci.report import RstFormatter
 import outstream
-from utils import HexFile
-import target
 from target.target_list import target_list
-from ppci import irutils
-import io
-
-
-logformat='%(asctime)s|%(levelname)s|%(name)s|%(message)s'
+import ppci
 
 
 def logLevel(s):
@@ -26,149 +22,97 @@
     return numeric_level
 
 
-class RstFormatter(logging.Formatter):
-    """ Formatter that tries to create an rst document """
-    def __init__(self):
-        super().__init__(fmt=logformat)
-
-    def format(self, record):
-        s = super().format(record)
-        s += '\n'
-        if hasattr(record, 'c3_ast'):
-            f = io.StringIO()
-            print('', file=f)
-            print('', file=f)
-            print('.. code::', file=f)
-            print('', file=f)
-            AstPrinter().printAst(record.c3_ast, f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        if hasattr(record, 'ircode'):
-            f = io.StringIO()
-            print('', file=f)
-            print('', file=f)
-            print('.. code::', file=f)
-            print('', file=f)
-            Writer('  ').write(record.ircode, f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        if hasattr(record, 'irfunc'):
-            f = io.StringIO()
-            print('', file=f)
-            print('', file=f)
-            print('.. code::', file=f)
-            print('', file=f)
-            Writer('  ').write_function(record.irfunc, f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        if hasattr(record, 'ppci_frame'):
-            f = io.StringIO()
-            frame = record.ppci_frame
-            print('', file=f)
-            print('.. code::', file=f)
-            print('', file=f)
-            print('  {}'.format(frame.name), file=f)
-            for i in frame.instructions:
-                print('   {}'.format(i),file=f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        if hasattr(record, 'ra_cfg'):
-            f = io.StringIO()
-            print('', file=f)
-            print('', file=f)
-            print('.. graphviz::', file=f)
-            print('', file=f)
-            print('  digraph G {', file=f)
-            print('    size="8,80";', file=f)
-            cfg = record.ra_cfg
-            cfg.to_dot(f)
-            print('  }', file=f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        if hasattr(record, 'ra_ig'):
-            f = io.StringIO()
-            print('', file=f)
-            print('', file=f)
-            print('.. graphviz::', file=f)
-            print('', file=f)
-            print('  digraph G {', file=f)
-            print('    ratio="compress";', file=f)
-            print('    size="8,80";', file=f)
-            ig = record.ra_ig
-            ig.to_dot(f)
-            print('  }', file=f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        if hasattr(record, 'zcc_outs'):
-            f = io.StringIO()
-            print('', file=f)
-            print('', file=f)
-            print('.. code::', file=f)
-            print('', file=f)
-            outstream.OutputStreamWriter('  ').dump(record.zcc_outs, f)
-            print('', file=f)
-            s += '\n' + f.getvalue()
-        return s
-
-
 targets = {t.name: t for t in target_list}
 targetnames = list(targets.keys())
 
-# Parse arguments:
-parser = argparse.ArgumentParser(description='lcfos Compiler')
-parser.add_argument('source', type=argparse.FileType('r'), \
-  help='the source file to build', nargs="+")
-parser.add_argument('-i', '--imp', type=argparse.FileType('r'), \
-  help='Possible import module', action='append', default=[])
+def make_parser():
+    parser = argparse.ArgumentParser(description='lcfos Compiler')
+
+    parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])',
+                        type=logLevel, default='WARN')
+    sub_parsers = parser.add_subparsers(title='commands',
+         description='possible commands', dest='command')
+    recipe_parser = sub_parsers.add_parser('recipe', help="Bake recipe")
+    recipe_parser.add_argument('recipe_file', help='recipe file')
+
+    compile_parser = sub_parsers.add_parser('compile', help="compile source")
+    compile_parser.add_argument('source', type=argparse.FileType('r'),
+      help='the source file to build', nargs="+")
+    compile_parser.add_argument('-i', '--imp', type=argparse.FileType('r'),
+      help='Possible import module', action='append', default=[])
+    compile_parser.add_argument('--target', help="Backend selection",
+        choices=targetnames, required=True)
+    compile_parser.add_argument('-o', '--output', help='Output file',
+        metavar='filename')
+    compile_parser.add_argument('--report',
+                help='Specify a file to write the compile report to',
+                type=argparse.FileType('w'))
+    return parser
+
 
-#sub_parsers = parser.add_subparsers()
-#recipe = sub_parsers.add_parser('recipe')
-parser.add_argument('--optimize', action='store_true', help="Optimize")
-parser.add_argument('--target', help="Backend selection",
-    choices=targetnames, required=True)
-parser.add_argument('-o', '--output', help='Output file', metavar='filename')
-parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])',
-                    type=logLevel, default='WARN')
-parser.add_argument('--report', 
-            help='Specify a file to write the compile report to',
-            type=argparse.FileType('w'))
+class RecipeLoader:
+    def load_file(self, recipe_file, runner):
+        """ Loads a recipe dictionary into a task runner """
+        self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file))
+        with open(recipe_file, 'r') as f:
+            recipe = yaml.load(f)
+        self.load_dict(recipe, runner)
+
+    def relpath(self, filename):
+        return os.path.join(self.recipe_dir, filename)
+
+    def openfile(self, filename):
+        return open(self.relpath(filename), 'r')
+
+    def load_dict(self, recipe, runner):
+        for command, value in recipe.items():
+            if command == 'compile':
+                sources = [self.openfile(s) for s in value['sources']]
+                includes = [self.openfile(i) for i in value['includes']]
+                target = targets[value['machine']]
+                output = outstream.TextOutputStream()
+                runner.add_task(Compile(sources, includes, target, output))
+            elif command == 'link':
+                self.load_dict(value['inputs'], runner)
+                #runner.add_task(Link())
+            elif command == 'assemble':
+                pass
+            elif command == 'apps':
+                for a in value:
+                    self.load_dict(a, runner)
+            else:
+                raise NotImplementedError(command)
 
 
 def main(args):
     # Configure some logging:
     logging.getLogger().setLevel(logging.DEBUG)
     ch = logging.StreamHandler()
-    ch.setFormatter(logging.Formatter(logformat))
+    ch.setFormatter(logging.Formatter(ppci.logformat))
     ch.setLevel(args.log)
     logging.getLogger().addHandler(ch)
-    if args.report:
-        fh = logging.StreamHandler(stream=args.report)
-        fh.setFormatter(RstFormatter())
-        logging.getLogger().addHandler(fh)
-
-    tg = targets[args.target]
-    outs = outstream.TextOutputStream()
-
-    tr = TaskRunner()
-    tr.add_task(Compile(args.source, args.imp, tg, outs))
 
-    res = tr.run_tasks()
-    if res > 0:
-        return 1
-    logging.info('Assembly created', extra={'zcc_outs':outs})
+    runner = TaskRunner()
+    if args.command == 'compile':
+        tg = targets[args.target]
+        outs = outstream.TextOutputStream()
+        runner.add_task(Compile(args.source, args.imp, tg, outs))
+    elif args.command == 'recipe':
+        recipe_loader = RecipeLoader()
+        recipe_loader.load_file(args.recipe_file, runner)
+    else:
+        raise NotImplementedError('Invalid option')
 
-    code_bytes = outs.sections['code'].to_bytes()
-    if args.output:
-        output_filename = args.output
-        with open(output_filename, 'wb') as f:
-            f.write(code_bytes)
+    res = runner.run_tasks()
 
-    if args.report:
-        logging.getLogger().removeHandler(fh)
     logging.getLogger().removeHandler(ch)
-    return 0
+    return res
 
 
 if __name__ == '__main__':
+    parser = make_parser()
     arguments = parser.parse_args()
+    if not arguments.command:
+        parser.print_usage()
+        sys.exit(1)
     sys.exit(main(arguments))