예제 #1
0
def output_cpp(objs, output_fd, options={}):
    """
    Given a tree of objects, output C++ code to the file-like object `output_fd`.

    :param objs: A tree of objects (metrics and pings) as returned from
    `parser.parse_objects`.
    :param output_fd: Writeable file to write the output to.
    :param options: options dictionary.
    """

    # Monkeypatch a util.snake_case function for the templates to use
    util.snake_case = lambda value: value.replace(".", "_").replace("-", "_")

    # Monkeypatch util.get_jinja2_template to find templates nearby

    def get_local_template(template_name, filters=()):
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("cpp", "templates"),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        env.filters["camelize"] = util.camelize
        env.filters["Camelize"] = util.Camelize
        for filter_name, filter_func in filters:
            env.filters[filter_name] = filter_func
        return env.get_template(template_name)

    util.get_jinja2_template = get_local_template
    get_metric_id = generate_metric_ids(objs)
    get_ping_id = generate_ping_ids(objs)

    if len(objs) == 1 and "pings" in objs:
        template_filename = "cpp_pings.jinja2"
    else:
        template_filename = "cpp.jinja2"

    template = util.get_jinja2_template(
        template_filename,
        filters=(
            ("cpp", cpp_datatypes_filter),
            ("snake_case", util.snake_case),
            ("type_name", type_name),
            ("metric_id", get_metric_id),
            ("ping_id", get_ping_id),
            ("is_implemented_type", is_implemented_metric_type),
            ("Camelize", util.Camelize),
        ),
    )

    output_fd.write(template.render(all_objs=objs))
    output_fd.write("\n")
예제 #2
0
파일: js.py 프로젝트: liuchaofann/gecko-dev
def write_pings(objs, output_fd, template_filename):
    """
    Given a tree of objects `objs`, output pings-only code for the JS API to the
    file-like object `output_fd` using template `template_filename`
    """

    template = util.get_jinja2_template(
        template_filename,
        filters=(),
    )

    ping_string_table = StringTable()
    get_ping_id = generate_ping_ids(objs)
    # The map of a ping's name to its entry (a combination of a monotonic
    # integer and its index in the string table)
    pings = {}
    for ping_name in objs["pings"].keys():
        ping_id = get_ping_id(ping_name)
        ping_name = util.camelize(ping_name)
        pings[ping_name] = ping_entry(ping_id,
                                      ping_string_table.stringIndex(ping_name))

    ping_map = [(bytearray(ping_name, "ascii"), ping_entry)
                for (ping_name, ping_entry) in pings.items()]
    ping_string_table = ping_string_table.writeToString("gPingStringTable")
    ping_phf = PerfectHash(ping_map, 64)
    ping_by_name_lookup = ping_phf.cxx_codegen(
        name="PingByNameLookup",
        entry_type="ping_entry_t",
        lower_entry=lambda x: str(x[1]),
        key_type="const nsACString&",
        key_bytes="aKey.BeginReading()",
        key_length="aKey.Length()",
        return_type="static Maybe<uint32_t>",
        return_entry="return ping_result_check(aKey, entry);",
    )

    output_fd.write(
        template.render(
            ping_index_bits=PING_INDEX_BITS,
            ping_by_name_lookup=ping_by_name_lookup,
            ping_string_table=ping_string_table,
        ))
    output_fd.write("\n")
예제 #3
0
파일: js.py 프로젝트: guru-dot/gecko-dev
def output_js(objs, output_fd, options={}):
    """
    Given a tree of objects, output code for the JS API to the file-like object `output_fd`.

    :param objs: A tree of objects (metrics and pings) as returned from
    `parser.parse_objects`.
    :param output_fd: Writeable file to write the output to.
    :param options: options dictionary.
    """

    # Monkeypatch a util.snake_case function for the templates to use
    util.snake_case = lambda value: value.replace(".", "_").replace("-", "_")

    # Monkeypatch util.get_jinja2_template to find templates nearby

    def get_local_template(template_name, filters=()):
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("js", "templates"),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        env.filters["Camelize"] = util.Camelize
        for filter_name, filter_func in filters:
            env.filters[filter_name] = filter_func
        return env.get_template(template_name)

    util.get_jinja2_template = get_local_template
    template_filename = "js.jinja2"

    template = util.get_jinja2_template(
        template_filename,
        filters=(
            ("type_name", type_name),
            ("is_implemented_type", is_implemented_metric_type),
        ),
    )

    assert (INDEX_BITS + ID_BITS <
            ENTRY_WIDTH), "INDEX_BITS or ID_BITS are larger than allowed"

    get_metric_id = generate_metric_ids(objs)
    # Mapping from a metric's identifier to the entry (metric ID | type id | index)
    metric_id_mapping = {}
    categories = []

    category_string_table = StringTable()
    metric_string_table = StringTable()
    # Mapping from a type name to its ID
    metric_type_ids = {}

    for category_name, objs in objs.items():
        category_name = util.snake_case(category_name)
        id = category_string_table.stringIndex(category_name)
        categories.append((category_name, id))

        for metric in objs.values():
            identifier = metric_identifier(category_name, metric.name)
            if metric.type in metric_type_ids:
                type_id = metric_type_ids[metric.type]
            else:
                type_id = len(metric_type_ids) + 1
                metric_type_ids[metric.type] = type_id

            idx = metric_string_table.stringIndex(identifier)
            metric_id = get_metric_id(metric)
            entry = create_entry(metric_id, type_id, idx)
            metric_id_mapping[identifier] = entry

    # Create a lookup table for the metric categories only
    category_string_table = category_string_table.writeToString(
        "gCategoryStringTable")
    category_map = [(bytearray(category, "ascii"), id)
                    for (category, id) in categories]
    name_phf = PerfectHash(category_map, 64)
    category_by_name_lookup = name_phf.cxx_codegen(
        name="CategoryByNameLookup",
        entry_type="category_entry_t",
        lower_entry=lambda x: str(x[1]),
        key_type="const nsACString&",
        key_bytes="aKey.BeginReading()",
        key_length="aKey.Length()",
        return_type="static Maybe<uint32_t>",
        return_entry="return category_result_check(aKey, entry);",
    )

    # Create a lookup table for metric's identifiers.
    metric_string_table = metric_string_table.writeToString(
        "gMetricStringTable")
    metric_map = [(bytearray(metric_name, "ascii"), metric_id)
                  for (metric_name, metric_id) in metric_id_mapping.items()]
    metric_phf = PerfectHash(metric_map, 64)
    metric_by_name_lookup = metric_phf.cxx_codegen(
        name="MetricByNameLookup",
        entry_type="metric_entry_t",
        lower_entry=lambda x: str(x[1]),
        key_type="const nsACString&",
        key_bytes="aKey.BeginReading()",
        key_length="aKey.Length()",
        return_type="static Maybe<uint32_t>",
        return_entry="return metric_result_check(aKey, entry);",
    )

    output_fd.write(
        template.render(
            categories=categories,
            metric_id_mapping=metric_id_mapping,
            metric_type_ids=metric_type_ids,
            entry_width=ENTRY_WIDTH,
            index_bits=INDEX_BITS,
            id_bits=ID_BITS,
            category_string_table=category_string_table,
            category_by_name_lookup=category_by_name_lookup,
            metric_string_table=metric_string_table,
            metric_by_name_lookup=metric_by_name_lookup,
        ))
    output_fd.write("\n")
예제 #4
0
파일: js.py 프로젝트: liuchaofann/gecko-dev
def write_metrics(objs, output_fd, template_filename):
    """
    Given a tree of objects `objs`, output metrics-only code for the JS API to the
    file-like object `output_fd` using template `template_filename`
    """

    template = util.get_jinja2_template(
        template_filename,
        filters=(
            ("type_name", type_name),
            ("is_implemented_type", is_implemented_metric_type),
        ),
    )

    assert (INDEX_BITS + ID_BITS <
            ENTRY_WIDTH), "INDEX_BITS or ID_BITS are larger than allowed"

    get_metric_id = generate_metric_ids(objs)
    # Mapping from a metric's identifier to the entry (metric ID | type id | index)
    metric_id_mapping = {}
    categories = []

    category_string_table = StringTable()
    metric_string_table = StringTable()
    # Mapping from a type name to its ID
    metric_type_ids = {}

    for category_name, objs in objs.items():
        category_name = util.camelize(category_name)
        id = category_string_table.stringIndex(category_name)
        categories.append((category_name, id))

        for metric in objs.values():
            identifier = metric_identifier(category_name, metric.name)
            if metric.type in metric_type_ids:
                type_id = metric_type_ids[metric.type]
            else:
                type_id = len(metric_type_ids) + 1
                metric_type_ids[metric.type] = type_id

            idx = metric_string_table.stringIndex(identifier)
            metric_id = get_metric_id(metric)
            entry = create_entry(metric_id, type_id, idx)
            metric_id_mapping[identifier] = entry

    # Create a lookup table for the metric categories only
    category_string_table = category_string_table.writeToString(
        "gCategoryStringTable")
    category_map = [(bytearray(category, "ascii"), id)
                    for (category, id) in categories]
    name_phf = PerfectHash(category_map, 64)
    category_by_name_lookup = name_phf.cxx_codegen(
        name="CategoryByNameLookup",
        entry_type="category_entry_t",
        lower_entry=lambda x: str(x[1]),
        key_type="const nsACString&",
        key_bytes="aKey.BeginReading()",
        key_length="aKey.Length()",
        return_type="static Maybe<uint32_t>",
        return_entry="return category_result_check(aKey, entry);",
    )

    # Create a lookup table for metric's identifiers.
    metric_string_table = metric_string_table.writeToString(
        "gMetricStringTable")
    metric_map = [(bytearray(metric_name, "ascii"), metric_id)
                  for (metric_name, metric_id) in metric_id_mapping.items()]
    metric_phf = PerfectHash(metric_map, 64)
    metric_by_name_lookup = metric_phf.cxx_codegen(
        name="MetricByNameLookup",
        entry_type="metric_entry_t",
        lower_entry=lambda x: str(x[1]),
        key_type="const nsACString&",
        key_bytes="aKey.BeginReading()",
        key_length="aKey.Length()",
        return_type="static Maybe<uint32_t>",
        return_entry="return metric_result_check(aKey, entry);",
    )

    output_fd.write(
        template.render(
            categories=categories,
            metric_id_mapping=metric_id_mapping,
            metric_type_ids=metric_type_ids,
            entry_width=ENTRY_WIDTH,
            index_bits=INDEX_BITS,
            id_bits=ID_BITS,
            category_string_table=category_string_table,
            category_by_name_lookup=category_by_name_lookup,
            metric_string_table=metric_string_table,
            metric_by_name_lookup=metric_by_name_lookup,
        ))
    output_fd.write("\n")
예제 #5
0
파일: rust.py 프로젝트: Floflis/gecko-b2g
def output_rust(objs, output_fd, options={}):
    """
    Given a tree of objects, output Rust code to the file-like object `output_fd`.

    :param objs: A tree of objects (metrics and pings) as returned from
    `parser.parse_objects`.
    :param output_fd: Writeable file to write the output to.
    :param options: options dictionary, presently unused.
    """

    # Monkeypatch a util.snake_case function for the templates to use
    util.snake_case = lambda value: value.replace(".", "_").replace("-", "_")

    # Monkeypatch util.get_jinja2_template to find templates nearby

    def get_local_template(template_name, filters=()):
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("rust", "templates"),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        env.filters["camelize"] = util.camelize
        env.filters["Camelize"] = util.Camelize
        for filter_name, filter_func in filters:
            env.filters[filter_name] = filter_func
        return env.get_template(template_name)

    util.get_jinja2_template = get_local_template
    get_metric_id = generate_metric_ids(objs)
    get_ping_id = generate_ping_ids(objs)

    # Map from a tuple (const, typ) to an array of tuples (id, path)
    # where:
    #   const: The Rust constant name to be used for the lookup map
    #   typ:   The metric type to be stored in the lookup map
    #   id:    The numeric metric ID
    #   path:  The fully qualified path to the metric object in Rust
    #
    # This map is only filled for metrics, not for pings.
    #
    # Example:
    #
    #   ("COUNTERS", "CounterMetric") -> [(1, "test_only::clicks"), ...]
    objs_by_type = {}

    # Map from a metric ID to the fully qualified path of the event object in Rust.
    # Required for the special handling of event lookups.
    #
    # Example:
    #
    #   17 -> "test_only::an_event"
    events_by_id = {}

    if len(objs) == 1 and "pings" in objs:
        template_filename = "rust_pings.jinja2"
    else:
        template_filename = "rust.jinja2"

        for category_name, metrics in objs.items():
            for metric in metrics.values():

                # The constant is all uppercase and suffixed by `_MAP`
                const_name = util.snake_case(metric.type).upper() + "_MAP"
                typ = type_name(metric)
                key = (const_name, typ)

                metric_name = util.snake_case(metric.name)
                category_name = util.snake_case(category_name)
                full_path = f"{category_name}::{metric_name}"

                if metric.type == "event":
                    events_by_id[get_metric_id(metric)] = full_path
                    continue

                if key not in objs_by_type:
                    objs_by_type[key] = []
                objs_by_type[key].append((get_metric_id(metric), full_path))

    # Now for the modules for each category.
    template = util.get_jinja2_template(
        template_filename,
        filters=(
            ("rust", rust_datatypes_filter),
            ("snake_case", util.snake_case),
            ("type_name", type_name),
            ("extra_type_name", extra_type_name),
            ("ctor", ctor),
            ("extra_keys", extra_keys),
            ("metric_id", get_metric_id),
            ("ping_id", get_ping_id),
        ),
    )

    output_fd.write(
        template.render(
            all_objs=objs,
            common_metric_data_args=common_metric_data_args,
            metric_by_type=objs_by_type,
            extra_args=util.extra_args,
            events_by_id=events_by_id,
            min_submetric_id=2**27 + 1,  # One more than 2**ID_BITS from js.py
        ))
    output_fd.write("\n")
예제 #6
0
def output_rust(objs, output_fd, options={}):
    """
    Given a tree of objects, output Rust code to the file-like object `output_fd`.

    :param objs: A tree of objects (metrics and pings) as returned from
    `parser.parse_objects`.
    :param output_fd: Writeable file to write the output to.
    :param options: options dictionary, presently unused.
    """

    # Monkeypatch a util.snake_case function for the templates to use
    util.snake_case = lambda value: value.replace(".", "_").replace("-", "_")

    # Monkeypatch util.get_jinja2_template to find templates nearby

    def get_local_template(template_name, filters=()):
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("rust", "templates"),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        env.filters["camelize"] = util.camelize
        env.filters["Camelize"] = util.Camelize
        for filter_name, filter_func in filters:
            env.filters[filter_name] = filter_func
        return env.get_template(template_name)

    util.get_jinja2_template = get_local_template
    get_metric_id = generate_metric_ids(objs)

    # Map from a tuple (const, typ) to an array of tuples (id, path)
    # where:
    #   const: The Rust constant name to be used for the lookup map
    #   typ:   The metric type to be stored in the lookup map
    #   id:    The numeric metric ID
    #   path:  The fully qualified path to the metric object in Rust
    #
    # This map is only filled for metrics, not for pings.
    #
    # Example:
    #
    #   ("COUNTERS", "CounterMetric") -> [(1, "test_only::clicks"), ...]
    objs_by_type = {}

    if len(objs) == 1 and "pings" in objs:
        template_filename = "rust_pings.jinja2"
    else:
        template_filename = "rust.jinja2"

        for category_name, metrics in objs.items():
            for metric in metrics.values():
                # FIXME: Support events correctly
                if metric.type == "event":
                    continue

                # The constant is all uppercase and suffixed by `_MAP`
                const_name = util.snake_case(metric.type).upper() + "_MAP"
                typ = type_name(metric)
                key = (const_name, typ)
                if key not in objs_by_type:
                    objs_by_type[key] = []

                metric_name = util.snake_case(metric.name)
                category_name = util.snake_case(category_name)
                full_path = f"{category_name}::{metric_name}"
                objs_by_type[key].append((get_metric_id(metric), full_path))

    # Now for the modules for each category.
    template = util.get_jinja2_template(
        template_filename,
        filters=(
            ("rust", rust_datatypes_filter),
            ("snake_case", util.snake_case),
            ("type_name", type_name),
            ("ctor", ctor),
            ("extra_keys", extra_keys),
            ("metric_id", get_metric_id),
        ),
    )

    # The list of all args to CommonMetricData (besides category and name).
    # No particular order is required, but I have these in common_metric_data.rs
    # order just to be organized.
    common_metric_data_args = [
        "name",
        "category",
        "send_in_pings",
        "lifetime",
        "disabled",
        "dynamic_label",
    ]

    output_fd.write(
        template.render(
            all_objs=objs,
            common_metric_data_args=common_metric_data_args,
            metric_by_type=objs_by_type,
            extra_args=util.extra_args,
        ))
    output_fd.write("\n")
예제 #7
0
def output_rust(objs, output_fd, options={}):
    """
    Given a tree of objects, output Rust code to the file-like object `output_fd`.

    :param objs: A tree of objects (metrics and pings) as returned from
    `parser.parse_objects`.
    :param output_fd: Writeable file to write the output to.
    :param options: options dictionary, presently unused.
    """

    # Monkeypatch a util.snake_case function for the templates to use
    util.snake_case = lambda value: value.replace('.', '_').replace('-', '_')
    # Monkeypatch util.get_jinja2_template to find templates nearby

    def get_local_template(template_name, filters=()):
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("rust", "templates"),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        env.filters["camelize"] = util.camelize
        env.filters["Camelize"] = util.Camelize
        for filter_name, filter_func in filters:
            env.filters[filter_name] = filter_func
        return env.get_template(template_name)

    util.get_jinja2_template = get_local_template

    if len(objs) == 1 and "pings" in objs:
        template_filename = "rust_pings.jinja2"
    else:
        template_filename = "rust.jinja2"

    # Now for the modules for each category.
    template = util.get_jinja2_template(
        template_filename,
        filters=(
            ("rust", rust_datatypes_filter),
            ("snake_case", util.snake_case),
            ("type_name", type_name),
            ("ctor", ctor),
            ("extra_keys", extra_keys),
        ),
    )

    # The list of all args to CommonMetricData (besides category and name).
    # No particular order is required, but I have these in common_metric_data.rs
    # order just to be organized.
    common_metric_data_args = [
        'name',
        'category',
        'send_in_pings',
        'lifetime',
        'disabled',
        'dynamic_label',
    ]

    output_fd.write(template.render(
        all_objs=objs, common_metric_data_args=common_metric_data_args,
        extra_args=util.extra_args))
    output_fd.write("\n")