예제 #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 setup(self, unit):
        super(Demo, self).setup(unit)

        code.Import("../lib/application").insert_after(unit.find("main_h"))
        unit.find("init").append(code.Import("../lib/init.c")).stick_top()
        unit.find("step").append(code.Import("../lib/application_step.c"))
        unit.find("event_loop").append(
            code.FunctionCall("report_metrics")).stick_bottom()
예제 #3
0
 def setup(self, unit):
   unit.select("includes", "def").append(code.Import("moose/avr"))
   unit.select("includes", "def").append(code.Import("moose/bool"))
   unit.select("includes", "def").append(code.Import("moose/serial"))
   unit.select("includes", "def").append(code.Import("moose/clock"))
   unit.select("includes", "def").append(code.Import("moose/xbee"))
   
   unit.find("event_loop").append(code.FunctionCall("xbee_receive"))
예제 #4
0
 def test_function_call_with_arguments(self):
     arguments = [
         code.SimpleVariable("a"),
         code.SimpleVariable("b"),
         code.BooleanLiteral(False)
     ]
     self.unit.select("test", "dec") \
       .append(code.FunctionCall("some_func", arguments))
     self.assertEqualToSource(self.unit, "some_func(a, b, FALSE);")
예제 #5
0
 def after_visit_FunctionCallExp(self, call):
     # argument-expressions were pushed onto the code stack after a single
     # function-identifier.
     args = []
     while isinstance(self.code[-1], code.Expression):
         args.append(self.code.pop())
     assert isinstance(self.code[-1], code.Type)
     type = self.code.pop()
     function = self.code.pop()
     self.code.append(
         code.FunctionCall(function, list(reversed(args)), type=type))
예제 #6
0
    def create_when_execution(self, execution):
        if execution.event.name == "receive":
            f = self.generator.unit.find(execution.executed.name + "_decl")
            if not f is None and len(f.children) > 0:
                # if children are single CaseStatement, it will be handled by Transform
                if not isinstance(f.children[0], code.CaseStatement):
                    # else we need to register a catch-all handlers
                    self.generator.unit.find("init").append(
                        code.FunctionCall(
                            "payload_parser_register_all",
                            [code.SimpleVariable(execution.executed.name)]))
            return  # Case-based receiving is handled by Transform

        # TODO: generalize: only supported = after transmit for all nodes
        assert execution.timing == "after"
        assert execution.event.name == "transmit"
        assert isinstance(execution.scope, AllNodes)

        # wire transmit handler
        self.generator.unit.find("init").append(
            code.FunctionCall("mesh_on_transmit",
                              [code.SimpleVariable("handle_transmit")]))
        # setup transforming handle_transmit
        self.generator.unit.find("nodes_main").select("dec").append(
            code.Function(
                "handle_transmit",
                params=[
                    code.Parameter("from", code.IntegerType()),
                    code.Parameter("hop", code.IntegerType()),
                    code.Parameter("to", code.IntegerType()),
                    code.Parameter("size", code.ByteType()),
                    code.Parameter("payload", code.ManyType(code.ByteType()))
                ]).contains(
                    code.FunctionCall(
                        execution.executed.name,
                        arguments=[
                            code.FunctionCall(
                                "nodes_lookup",
                                type=code.ObjectType("node"),
                                arguments=[code.SimpleVariable("from")]),
                            code.FunctionCall(
                                "nodes_lookup",
                                type=code.ObjectType("node"),
                                arguments=[code.SimpleVariable("hop")]),
                            code.FunctionCall(
                                "nodes_lookup",
                                type=code.ObjectType("node"),
                                arguments=[code.SimpleVariable("to")]),
                            code.FunctionCall(
                                "make_payload",
                                type=code.ObjectType("payload"),
                                arguments=[
                                    code.SimpleVariable("payload"),
                                    code.SimpleVariable("size")
                                ]),
                        ])))
예제 #7
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())
예제 #8
0
    def create_every_execution(self, execution):
        if isinstance(execution.scope, AllNodes):
            name = "nodes_schedule_all"
        else:
            name = "nodes_schedule_own"

        self.generator.unit.find("nodes_scheduler_init").append(
            code.FunctionCall(name,
                              arguments=[
                                  self._translate(execution.interval),
                                  code.SimpleVariable(execution.executed.name)
                              ]))
예제 #9
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)
예제 #10
0
    def visit_MethodCall(self, call):
        """
    Methodcalls to the nodes domain are rewritten to function-calls.
    """
        if isinstance(call.obj, code.Object) and call.obj.name == "nodes":
            # FIXME: this is a bit too local, would nicer at C-level, based on the
            # definition of the parameters of these functions. not for now ;-)

            # these function call take vararg bytes. we need to convert each non-byte
            # argument to a ListLiteral of corresponding bytes.
            # create function-call

            # strategy:
            # AtomLiteral     will be expanded later, so we skip them here
            # ObjectProperty  check/convert property type
            # SimpleVariable
            # FunctionCall    extract from arguments, assign to variable, convert

            assert isinstance(call.arguments[0], code.ListLiteral)

            # TODO: mark this somehow and move logic to emitter
            #       the UnionType solution is to C-specific - no more time to do it
            #       right :-(

            # rebuild the arguments
            args = code.ListLiteral()
            temp = 0
            for index, arg in enumerate(call.arguments[0]):
                # TODO: generalize a bit more - this only support our minimal needs

                if isinstance(arg, code.FunctionCall):
                    code.Assign(code.VariableDecl("temp" + str(temp), arg.type), arg) \
                        .insert_before(call)
                    if isinstance(arg.type, code.AmountType) and \
                       isinstance(arg.type.type, code.ByteType):
                        for i in range(arg.type.size):
                            args.append(
                                code.ListVariable("temp" + str(temp), i))
                    temp += 1

                elif isinstance(arg, code.SimpleVariable):
                    if str(arg.info) == "TimestampType":
                        code.VariableDecl(
                          "temp" + str(temp),
                          code.UnionType("temp" + str(temp)) \
                              .contains( code.Property("value", code.NamedType("timestamp")),
                                         code.Property(
                                           "b", code.AmountType(code.ByteType(), 4) # platf?
                                         )
                                       )
                        ).insert_before(call)

                        code.Assign(code.StructProperty("temp" + str(temp), "value"), arg) \
                          .insert_before(call)

                        for i in range(4):
                            args.append(
                                code.ListVariable(
                                    code.StructProperty(
                                        "temp" + str(temp), "b"), i))
                        temp += 1
                    elif str(arg.info) == "ObjectType(nodes)":
                        # a node is identified in a distributed manner by its nw address
                        # TODO: maybe not always correct, but split it out as 2 bytes
                        args.append(
                            code.ShiftLeft(
                                code.ObjectProperty(arg.name, "address"), 8),
                            code.ObjectProperty(arg.name, "address"))

                elif isinstance(arg, code.ObjectProperty):

                    if isinstance(arg.type, code.ByteType):
                        args.append(arg)

                    elif isinstance(arg.type, code.FloatType):
                        code.VariableDecl(
                          "temp" + str(temp),
                          code.UnionType("temp" + str(temp)) \
                              .contains( code.Property("value", code.FloatType() ),
                                         code.Property(
                                           "b", code.AmountType(code.ByteType(), 4)
                                         )
                                       )
                        ).insert_before(call)

                        code.Assign(code.StructProperty("temp" + str(temp), "value"), arg) \
                          .insert_before(call)

                        for i in range(4):
                            args.append(
                                code.ListVariable(
                                    code.StructProperty(
                                        "temp" + str(temp), "b"), i))
                        temp += 1

                else:
                    args.append(arg)

            # replace by functioncall
            return code.FunctionCall("nodes_" + call.method.name, [args])
예제 #11
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)
예제 #12
0
 def test_function_call_without_arguments(self):
     self.unit.select("test", "dec") \
       .append(code.FunctionCall("some_func"))
     self.assertEqualToSource(self.unit, "some_func();")