Example #1
0
 def __init__(self):
     self.library = CodeLibrary()
     self.pipelines = []
Example #2
0
class CodeGenerator:

    def __init__(self):
        self.library = CodeLibrary()
        self.pipelines = []

    def format_pipeline(self, pipeline):
        return " | ".join(self._format_unit(*u) for u in pipeline)

    def init(self, script=False, **namespace):
        self.add_vars(
                script=script, time=time.asctime(), argv=sys.argv[1:],
                version=__version__, **namespace)

    def init(self, arguments, filenames):
        self.arguments = arguments

        self.namespace = attrdict(
                pipelines=self.pipelines,
                filenames=filenames,
                script=self.arguments.dump is not None,
                output=self.arguments.output,
                quiet=self.arguments.quiet,
                stats=self.arguments.stats,
                decode=self.arguments.decode,
                encode=self.arguments.encode,
                time=time.asctime(),
                argv=sys.argv[1:],
                version=__version__)

    def add_pipeline(self, pipeline):
        self.unit_serial = 0
        self.finalized = False

        self.pipelines.append(attrdict(units=[]))

        for unit_number, (name, arguments, handler, handler_arguments) in enumerate(pipeline):
            self.add_unit(name, arguments, handler, handler_arguments, unit_number)

        if not self.finalized:
            self.add_unit("write")

        self.pipelines[-1]["serial"] = len(self.pipelines) - 1
        self.pipelines[-1]["formatted"] = " | ".join(u["formatted"] for u in self.pipelines[-1]["units"])

    def add_unit(self, name, arguments=(), handler=None, handler_arguments=(), unit_number=None):
        unit = self.library.get_unit(name)

        if self.unit_serial == 0:
            if not unit.type == "input":
                self.add_unit("read")

        elif unit.type == "input":
            # FIXME use different exception
            raise ParserError("duplicate use of input unit (%d:%s)" % (unit_number, name))

        if unit.type == "output":
            self.add_unit("output_stats")
            if self.finalized:
                # FIXME use different exception
                raise ParserError("duplicate use of output unit (%d:%s)" % (unit_number, name))
            self.finalized = True

        elif self.finalized:
            raise ParserError("cannot use unit (%d:%s) after output unit" % (unit_number, name))

        # Prepare namespace.
        # FIXME harmonize the variable names.
        self.pipelines[-1]["units"].append(attrdict(
                handler=handler,
                handler_code=handler_arguments[0] if handler_arguments else None,
                ignore_exc=self._format_args(handler_arguments) if handler_arguments else None,
                expr_code=arguments[0] if arguments else None,
                name=unit.name,
                serial=self.unit_serial,
                real_serial=unit_number,
                formatted=self._format_unit(unit.name, arguments, handler, handler_arguments),
                argno=len(arguments), args=arguments,
                args_formatted=self._format_args(arguments)))

        self.unit_serial += 1

        if self.unit_serial == 1:
            self.add_unit("input_stats")

    def _format_unit(self, name, arguments, handler, handler_arguments):
        args = [" ".join(a.split()) for a in arguments]
        hargs = [" ".join(a.split()) for a in handler_arguments]
        if handler is not None:
            return "%s(%s) %s (%s)" % (name, ", ".join(args), handler, ", ".join(hargs))
        else:
            return "%s(%s)" % (name, ", ".join(args))

    def _format_args(self, arguments):
        if len(arguments) == 0:
            return "()"
        elif len(arguments) == 1:
            return "(" + arguments[0] + ",)"
        else:
            return "(" + ", ".join(arguments) + ")"

    def format_epilog(self):
        lines = []
        for name, unit in self.library.get_units():
            lines.append(name)
            lines += _indent(unit.description.splitlines(), 4)
            lines.append("")

        return "\n".join(lines)

    def assemble(self):
        if not self.pipelines:
            self.add_pipeline("")

        # FIXME
        #self.lines.insert(0, "{!set used_units %s}" % self._format_args([repr(u) for u in sorted(self.used_units)]))

        self.namespace["pls_formatted"] = ", ".join("pipeline_%02d()" % i for i in range(len(self.pipelines)))

        yield from Template(self.library, self.namespace, "skeleton").parse()