git @ Cat's Eye Technologies Eightebed / master src / eightebed / drivers.py
master

Tree @master (Download .tar.gz)

drivers.py @masterraw · history · blame

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
drivers.py: Drive the Eightebed compiling/C compiling/running/etc processes.
"""

import logging
import os
import sys

from pprint import pprint
from subprocess import Popen, PIPE

from eightebed.parser import parse
from eightebed.context import Context


logger = logging.getLogger("main")


def parse_and_check(program_text, options=None):
    ast = parse(program_text)
    if options is not None and options.dump_ast:
        pprint(ast)
    ast.typecheck(Context(), Context())
    ast.vanalyze(Context())
    return ast


def parse_and_gen(options, infilename, outfilename, tests=None):
    if infilename.startswith('@') and tests is not None:
        program_text = getattr(tests, infilename[1:])
    else:
        infile = open(infilename, "r")
        program_text = infile.read()
        infile.close()
    logger.info("Parsing...")
    ast = parse_and_check(program_text, options=options)
    if outfilename == '-':
        outfile = sys.stdout
    else:
        outfile = open(outfilename, "w")
    logger.info("Generating...")
    ast.emit(outfile, options)
    outfile.close()


def compile_and_run(filename, options):
    # a bit of a hack
    a_out = './a.out'
    if sys.platform == 'cygwin':
        a_out = './a.exe'

    logger.info("Compiling...")
    output = Popen([options.compiler, filename], stdout=PIPE).communicate()[0]
    if options.verbose:
        sys.stdout.write(output)
    if output not in ('', b''):
        raise RuntimeError("Compilation failed!")
    if options.run:
        logger.info("Running...")
        output = Popen([a_out], stdout=PIPE).communicate()[0]
        try:
            # Python 2
            output = unicode(output).encode('ascii')
        except NameError:
            # Python 3
            output = output.decode('ascii')
    if options.clean:
        os.remove(filename)
        os.remove(a_out)
    return output


def load_and_go(ast, options=None):
    class LoadAndGoOptions(object):
        verbose = False
        run = True
        clean = True
        compiler = "gcc"
        pedigree = __file__ + ":load_and_go"
        trace_marking = False
        pointer_format = "$%08lx"
    options = options or LoadAndGoOptions()
    file = open("tmp.c", "w")
    ast.emit(file, options)
    file.close()
    return compile_and_run("tmp.c", options)


def cmdline(options):
    cmd = ""
    print("Eightebed interactive!  Type 'quit' to quit.")
    options.run = True
    options.clean = True
    while True:
        sys.stdout.write("> ")
        cmd = sys.stdin.readline().strip()
        if cmd == "quit":
            break
        try:
            ast = parse_and_check(cmd, options=options)
            result = load_and_go(ast, options=options)
            sys.stdout.write(result)
        except Exception as e:
            print("Exception!", repr(e))