예제 #1
0
    def prepare(self):
        """
    Prepares the definition of the node type.
    """
        # this is a generator for the Nodes domain, let's get it ;-)
        self.domain = SemanticNodes()

        # we need a translator
        self.translator = Translator()

        node_type = code.StructuredType("nodes").tag("node_type_def")
        node_type.append(code.Comment("domain properties"),
                         code.Property("id", code.ByteType()),
                         code.Property("address", code.LongType()))

        # the node type
        module = self.generator.unit.append(structure.Module("node_t"))
        module.select("def").append(code.Import("moose/bool"))

        module.select("def").append(code.Comment("THE node type"),
                                    node_type).tag("node_t-start")

        # provide init_node to initialise module-specific properties
        module.select("dec").append(
            code.Import("node_t"),
            code.Function("init_node",
                          params=[
                              code.Parameter("node",
                                             type=code.ObjectType("node"))
                          ]).tag("init_node")  # filled when creating node_t
        )

        # TODO: remove this redundant header file
        module = self.generator.unit.append(structure.Module("nodes"))
        module.select("def").append(code.Import("includes"))

        # add more imports to includes
        anchor = self.generator.unit.select("includes").select("def").find(
            "foo-lib-start")
        code.Import("nodes").insert_before(anchor).tag("requires-tuples")
        code.Import("node_t").insert_before(anchor)
        code.Import("foo-lib/nodes").insert_before(anchor)
        code.Import("foo-lib/payload").insert_before(anchor)

        # initialiase nodes and add handling of receive packets
        self.generator.unit.find("init").append(
            code.FunctionCall("nodes_init"),
            code.FunctionCall("mesh_on_receive",
                              [code.SimpleVariable("payload_parser_parse")]))
예제 #2
0
    def extend_main(self, module):
        """
    Transforms the main module by adding nodes functionality to the event_loop.
    """
        self.add_import_nodes(module)
        if not module.find("nodes_main") is None: return
        module.tag("nodes_main")

        # get pointers into the code
        dec = module.select("dec")
        event_loop = module.find("event_loop")

        # prepare top-level actions in event_loop
        event_loop.append(code.Comment("nodes logic execution hook"))
        event_loop.append(code.FunctionCall("nodes_process"))

        # prepare a hook to setup scheduling
        scheduler_init = dec.append(
            code.Function("nodes_scheduler_init")).tag("nodes_scheduler_init")
        module.find("main_function").append(
            code.FunctionCall(scheduler_init.name).stick_top())
예제 #3
0
    def construct(self, code_module, module):
        """
    Constructs a code_module from a module.
    """
        self.add_import_nodes(code_module)
        code_module.select("dec").append(code.Import(code_module.data))
        code_module.select("def").append(code.Import("includes"))

        # add extensions to node_t definition
        node_type = self.generator.unit.find("node_type_def")
        node_type.append(code.Comment("extended properties for " +
                                      module.name))

        # add initializations to init_node function
        init = self.generator.unit.find("init_node")

        for ext in module.domains["nodes"].extensions:
            for prop in ext.extension.properties:
                if isinstance(prop.type, model.ManyType) and \
                   isinstance(prop.type.subtype, model.TupleType):
                    code.Import("tuples").insert_before(node_type)
                node_type.append(
                    code.Property(prop.name, self._translate(prop.type)))
                init.append(
                    code.Assign(code.ObjectProperty("node", prop.name),
                                self.translator.translate(prop.value)))
                # TODO: this should go in the emission of a functioncal :-/
                #       and lookup the function in the externals (no time now)
                if isinstance(prop.value, model.FunctionCallExp) and \
                   prop.value.name == "now":
                    self.generator.unit.select("node_t", "def").append(
                        code.Import("foo-lib/time"))

        # create all functions
        for function in module.functions:
            code_module.select("dec").append(self._translate(function))
예제 #4
0
    def visit_CaseStatement(self, stmt):
        """
    CaseStatements may be used to handle incoming payloads. These should be
    centralized in the processing of incoming payloads. Payload references are
    found in the case.expression.type == semantic.Nodes.payload_t.
    We now support the typical case with a contains() function. For each of
    these we generate a function based on the consequence, accepting a payload,
    positioned where it contains information following the case condition.
    The case condition's literals are added as to-find literals and a reference
    to the handling function is also registered with a general purpose byte-
    stream parser/state machine.
    """
        # TODO: take into account execution strategy

        # TODO: only supported now: SimpleVariable
        if isinstance(stmt.expression, code.SimpleVariable):
            if stmt.expression.info == SemanticNodes.payload_t:
                # move handling to centralized processing of incoming data
                for case, consequence in zip(stmt.cases, stmt.consequences):
                    # create a function that processes matched payload
                    handler = code.Function(
                        "nodes_process_incoming_case_" +
                        str(Transformer.processors),
                        params=[
                            code.Parameter("me", code.ObjectType("node")),
                            code.Parameter("sender", code.ObjectType("node")),
                            code.Parameter("from", code.ObjectType("node")),
                            code.Parameter("hop", code.ObjectType("node")),
                            code.Parameter("to", code.ObjectType("node")),
                            code.Parameter(
                                "payload",
                                self.translate(
                                    self.domain.get_type("payload")))
                        ])
                    Transformer.processors += 1

                    handler.append(
                        code.Comment("extract variables from payload"))
                    # declare matching local variables from case
                    # NOTE: these are inside a ListLiteral
                    for arg in case.arguments[0]:
                        if isinstance(arg, code.Variable):
                            code_type = self.translate(arg.info)
                            # TODO: generalize this more
                            code_type_name = {
                                "NamedType {'name': 'timestamp'}":
                                lambda: code_type.name,
                                "ByteType":
                                lambda: "byte",
                                # TODO: amount has type, should be recursively extracted
                                # TODO:            size
                                "AmountType {}":
                                lambda: "bytes",
                                "ObjectType {'name': 'nodes'}":
                                lambda: code_type.name[:-1],
                                "FloatType":
                                lambda: "float"
                            }[str(code_type)]()
                            # TODO: size should be generalized
                            args = [code.IntegerLiteral(code_type.size)] \
                                      if code_type_name == "bytes" else []
                            if isinstance(code_type, code.AmountType):
                                code_type = code.ManyType(code.ByteType())
                            handler.append(
                                code.Assign(
                                    code.VariableDecl(arg.name, code_type),
                                    code.FunctionCall(
                                        "payload_parser_consume_" +
                                        code_type_name,
                                        type=code_type,
                                        arguments=args)))

                    # add consequence
                    handler.append(code.Comment("perform handling actions"))
                    for statement in consequence:
                        handler.append(statement)

                    self.stack[0].find("nodes_main").select("dec").append(
                        handler)

                    # register the handle for the literals in the case
                    arguments = code.ListLiteral()
                    for arg in case.arguments[0]:
                        if isinstance(arg, code.Literal):
                            arguments.append(arg)
                    registration = code.FunctionCall(
                        "payload_parser_register",
                        [code.SimpleVariable(handler.name), arguments])
                    self.stack[0].find("init").append(registration)

                # if there is an else case, also generate it and register it
                if not stmt.case_else == None:
                    handler = code.Function(
                        "nodes_process_incoming_else",
                        params=[
                            code.Parameter("sender", code.ObjectType("node")),
                            code.Parameter("from", code.ObjectType("node")),
                            code.Parameter("hop", code.ObjectType("node")),
                            code.Parameter("to", code.ObjectType("node")),
                            code.Parameter(
                                "payload",
                                self.translate(
                                    self.domain.get_type("payload")))
                        ])
                    handler.append(self.translate(stmt.case_else))
                    self.stack[0].find("nodes_main").select("dec").append(
                        handler)

                    registration = code.FunctionCall(
                        "payload_parser_register_else",
                        [code.SimpleVariable(handler.name)])
                    self.stack[0].find("init").append(registration)
                # remove the case
                self.stack[-2].remove_child(self.child)
예제 #5
0
    def create_main_module(self, model):
        """
    Creates the top-level main and includes modules.
    """
        module = self.unit.append(Module("includes").tag("includes"))
        # add basic set of includes that apply to all generations, without causing
        # compilation problems
        module.select("def").append(code.Import("<stdint.h>"))

        for mod in model.modules.values():
            if len(mod.constants.items()) > 0:
                module.select("def").append(code.Import("constants"))
                break

        module.select("def").append(
            code.Import("foo-lib/crypto")).tag("foo-lib-start")
        module.select("def").append(code.Import("foo-lib/time"))

        module.select("def").append(code.Import("../lib/network"))

        # MAIN module
        module = self.unit.append(Module("main"))
        module.select("def").append(code.Import("includes"))
        module.select("dec").append(code.Import("main")).tag("main_h")

        for domain_module_name, domain_module in model.modules.items():
            for domain_name, domain in domain_module.domains.items():
                name = domain_name + "-" + domain_module_name
                module.select("def").append(code.Import(name))

        # init
        init = code.Function("init").tag("init") \
                   .contains(code.Comment("add framework init here"))

        # app
        app = code.Function("application_step") \
                  .contains(code.Comment("add application specific code here")) \
                  .tag("step")

        # main
        main = code.Function("main",
                             code.NamedType("int")).tag("main_function")
        main.append(code.FunctionCall("init").stick_top())
        main.append(code.Return(code.IntegerLiteral(1))).stick_bottom()

        module.select("dec").append(
            code.Comment("""init and application_step
can be implemented using application specific needs."""), init, app,
            code.Comment("""starting point
please don't change anything beyond this point."""), main)

        # construct an event_loop builder and hook it into the main function
        event_loop = code.WhileDo(code.BooleanLiteral(True))
        main.append(event_loop).tag("event_loop") \
            .append(code.Comment("your application gets its share"),
                    code.FunctionCall("application_step"))

        # allow each domain generator to extend the main section
        for mod in model.modules.values():
            for domain_name, domain in mod.domains.items():
                self.generator_for_domain(domain_name).extend(module)
예제 #6
0
 def test_multi_line_comment(self):
     tree = code.Comment("hello\nworld")
     self.assertEqualToSource(tree, "/*\n  hello\n  world\n*/")
예제 #7
0
 def test_single_line_comment(self):
     tree = code.Comment("hello world")
     self.assertEqualToSource(tree, "// hello world")