1b78f13911bfe6eda303e91ef215c87a165aae8aeAlexandre Rames# Copyright 2016, VIXL authors
288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# All rights reserved.
388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#
488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# Redistribution and use in source and binary forms, with or without
588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# modification, are permitted provided that the following conditions are met:
688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#
788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#   * Redistributions of source code must retain the above copyright notice,
888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#     this list of conditions and the following disclaimer.
988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#   * Redistributions in binary form must reproduce the above copyright notice,
1088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#     this list of conditions and the following disclaimer in the documentation
1188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#     and/or other materials provided with the distribution.
1288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#   * Neither the name of ARM Limited nor the names of its contributors may be
1388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#     used to endorse or promote products derived from this software without
1488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#     specific prior written permission.
1588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois#
1688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
1788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
2088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
2788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisimport json
2888c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisimport re
2988c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisimport os
3088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisimport hashlib
3188c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisimport collections
3288c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisimport itertools
3388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
3488c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisfrom test_generator import data_types
3588c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisfrom test_generator import generator
3688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
3788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisclass DataTypeBuilder(object):
3888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
3988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Factory object for building `data_types.Operand` and `data_types.Input`
4088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  objects. This object stores information about all operand and input types
4188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  described in JSON as dictionnaries indexed by their identifier. See
4288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  `test/a32/config/data-types.json` as a reference.
4388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
4488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Attributes:
4588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    operand_types    Dictionnary of type names corresponding to the JSON
4688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                     "type" field.
4788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    operand_variants Dictionnary of (variants, default) tuples.
4888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
4988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    input_types      Dictionnary of type names corresponding to the JSON
5088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                     "type" field.
5188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    input_values     Dictionnary of (values, default) tuples.
5288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
5388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
5488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  def __init__(self, operand_types, operand_variants, input_types,
5588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois               input_values):
5688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    self.operand_types = operand_types
5788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    self.operand_variants = operand_variants
5888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    self.input_types = input_types
5988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    self.input_values = input_values
6088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
6188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  def BuildOperand(self, name, identifier):
6288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    """
6388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Build a `data_types.Operand` object with the name `name`. `identifier`
6488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    identifies which type we want to create, as declared in JSON.
6588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    """
6688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    type_name = self.operand_types[identifier]
6788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    variants, default = self.operand_variants[identifier]
6888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # We simply pass the `type_name` as a parameter which will be used verbatim
6988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # in the code.
7088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    return data_types.Operand(name, type_name, variants, default)
7188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
7288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  def BuildInput(self, name, identifier):
7388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    """
7488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    Build a `data_types.Input` object with the name `name`. `identifier`
7588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    identifies which type we want to create, as declared in JSON.
7688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    """
7788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    type_name = self.input_types[identifier]
7888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    values, default = self.input_values[identifier]
7988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # For `data_types.Input` types, the `type_name` refers to the actual name of
8088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # the Python class, inheriting from `Input`. This is done so that different
8188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # input types can generate different C++ code by overriding the `Load` and
8288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # `Store` methods.
8388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    input_constructor = getattr(data_types, type_name)
8488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    return input_constructor(name, values, default)
8588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
8688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
8788c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef LoadJSON(filename):
8888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
8988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Read `filename`, strip its comments and load as JSON.
9088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
9188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  with open(filename, "r") as f:
9288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    match_cpp_comments = re.compile("//.*\n")
9388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # The order in which structures are described in JSON matters as we use them
9488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # as a seed. Computing a hash from a unordered dict always gives a different
9588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # value. We use the `object_pairs_hook` to make the json module create
9688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    # `OrderedDict` objects instead of builtin `dict` objects.
9788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    return json.loads(match_cpp_comments.sub("", f.read()),
9888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                      object_pairs_hook=collections.OrderedDict)
9988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
10088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
10188c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef ParseDataTypes(json_data_types):
10288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
10388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Build a `DataTypeBuilder` object containing all information from the JSON
10488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  description in `json_data_types`.
10588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
10688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
10788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
10888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operands": [
10988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
11088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "identifier": "AllRegistersButPC"
11188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "Register"
11288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "variants": [
11388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "r0",
11488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "r1",
11588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "r2",
11688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "r3"
11788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ]
11888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "default": "r0"
11988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
12088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
12188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ...
12288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
12388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
12488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "inputs": [
12588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
12688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "identifier": "Register"
12788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "Register"
12888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "values": [
12988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "0x00000000",
13088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "0xffffffff",
13188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "0xabababab"
13288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ]
13388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "default": "0xabababab"
13488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
13588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
13688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ...
13788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
13888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ]
13988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
14088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
14188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
14288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_types = {
14388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      json_operand_type["identifier"]: json_operand_type["type"]
14488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for json_operand_type in json_data_types["operands"]
14588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
14688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_variants = {
14788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      json_operand_type["identifier"]:
14888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          (json_operand_type["variants"], json_operand_type["default"])
14988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for json_operand_type in json_data_types["operands"]
15088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
15188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  input_types = {
15288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      json_input_type["identifier"]: json_input_type["type"]
15388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for json_input_type in json_data_types["inputs"]
15488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
15588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  input_values = {
15688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      json_input_type["identifier"]:
15788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          (json_input_type["values"], json_input_type["default"])
15888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for json_input_type in json_data_types["inputs"]
15988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
16088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return DataTypeBuilder(operand_types, operand_variants, input_types, input_values)
16188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
16288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
16388c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef ParseDescription(data_type_builder, json_description):
16488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
16588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Parse the instruction description into a
16688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  (`generator.OperandList`, `generator.InputList`) tuple.
16788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
16888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Example for an instruction that takes a condidition code, two registers and an
16988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  immediate as operand. It will also need inputs for the registers, as well as
17088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  NZCV flags.
17188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
17288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
17388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operands": [
17488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
17588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "cond",
17688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "Condition",
17788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
17888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
17988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "rd",
18088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "RegisterScratch",
18188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
18288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
18388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "rn",
18488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "RegisterScratch",
18588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
18688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      // The last operand needs to be wrapped into a C++ `Operand` object. We
18788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      // declare the operands that need to be wrapped as a list.
18888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
18988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "op",
19088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "wrapper": "Operand",
19188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "operands": [
19288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          {
19388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            "name": "immediate",
19488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois            "type": "ModifiedImmediate",
19588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          }
19688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        ]
19788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
19888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
19988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "inputs": [
20088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
20188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "apsr",
20288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "NZCV"
20388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
20488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
20588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "rd",
20688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "Register"
20788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      },
20888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      {
20988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "name": "rn",
21088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois        "type": "Register"
21188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      }
21288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ]
21388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ]
21488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
21588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
21688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
21788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operands = []
21888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  for json_operand in json_description["operands"]:
21988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if "name" in json_operand and "type" in json_operand:
22088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      operands.append(data_type_builder.BuildOperand(json_operand["name"],
22188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                                     json_operand["type"]))
22288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    elif "name" in json_operand and \
22388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois         "wrapper" in json_operand and \
22488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois         "operands" in json_operand:
22588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      wrapped_operands = [
22688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          data_type_builder.BuildOperand(json_wrapped_operand["name"],
22788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                         json_wrapped_operand["type"])
22888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          for json_wrapped_operand in json_operand["operands"]
22988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ]
23088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      operands.append(data_types.OperandWrapper(json_operand["name"],
23188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                                json_operand["wrapper"],
23288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                                                wrapped_operands))
23388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    else:
23488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      raise Exception("Parser failed to recognize JSON \"description\".")
23588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_list = generator.OperandList(operands)
23688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
23788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  json_description_inputs = json_description["inputs"]
23888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  input_list = generator.InputList([
23988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      data_type_builder.BuildInput(json_input["name"], json_input["type"])
24088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for json_input in json_description_inputs
24188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ])
24288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
24388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return operand_list, input_list
24488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
24588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
24688c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef ParseTestCase(json_test_case):
24788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
24888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Build a `generator.TestCase` object from its JSON description.
24988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
25088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
25188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
25288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "name": "RdIsNotRn",
25388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operands": [
25488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "rd", "rn"
25588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
25688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "inputs": [
25788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "rd", "rn"
25888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
25988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operand-filter": "rd != rn", // Python code to limit operand generation.
26088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operand-limit": 10           // Choose a random sample of 10 operands.
26188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
26288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ...
26388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
26488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "name": "Flags",
26588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operands": [
26688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "cond"
26788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
26888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "inputs": [
26988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "apsr", "q"
27088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
27188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "input-filter": "q == \"QFlag\"", // Python code to limit input generation
27288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "input-limit": 200                // Choose a random sample of 200 inputs.
27388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
27488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ...
27588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
27688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "name": "InITBlock",
27788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operands": [
27888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "cond", "rd", "rn", "rm"
27988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
2805b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois    "in-it-block": "{cond}", // Generate an extra IT instruction. This string
2815b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois                             // will be used as the operand passed to IT. One
2825b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois                             // needs to specify under what name the condition
2835b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois                             // operand is represented, in braces.
28488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "operand-filter": "cond != 'al' and rd == rm"
28588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
28688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
28788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
28888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
28988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # TODO: The fields in "operands" and "inputs" respectively refer to operands
29088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # and inputs declared in the instruction description (see `ParseDescription`).
29188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # We should assert that the user hasn't miss typed them and raise an
29288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # exception.
29388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
29488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # If the fields are not present, give them default values (empty list,
29588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # "True", or "None").
29688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_names = json_test_case["operands"] \
29788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if "operands" in json_test_case else []
29888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  input_names = json_test_case["inputs"] if "inputs" in json_test_case else []
29988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_filter = json_test_case["operand-filter"] \
30088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if "operand-filter" in json_test_case else "True"
30188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  input_filter = json_test_case["input-filter"] \
30288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if "input-filter" in json_test_case else "True"
30388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_limit = json_test_case["operand-limit"] \
30488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if "operand-limit" in json_test_case else None
30588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  input_limit = json_test_case["input-limit"] \
30688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      if "input-limit" in json_test_case else None
3075b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois  in_it_block = json_test_case["in-it-block"] \
3085b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois      if "in-it-block" in json_test_case else None
30988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
31088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # Create a seed from the test case description. It will only change if the
31188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # test case has changed.
31288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  md5 = hashlib.md5(str(json_test_case).encode())
31388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  seed = md5.hexdigest()
31488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
31588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return generator.TestCase(json_test_case["name"], seed, operand_names, input_names,
31688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                            operand_filter, input_filter, operand_limit,
3175b0cbc8d721ff369c76e09ff1e7ab878ffcae4e9Pierre Langlois                            input_limit, in_it_block)
31888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
31988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
32088c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef ParseTestFile(test_name, test_isa, mnemonics, operand_list, input_list,
32188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                  json_test_file):
32288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
32388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Build a `generator.Generator` object from a test file description. We have one
32488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  for each generated test files.
32588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
32688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
32788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
32888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "type": "simulator",  // Type of the test. This will control the prefix we
32988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                          // use when naming the file to generate.
33088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "name": "special-case",  // Optional name that will be included in the
33188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                             // generated filename.
33288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "mnemonics": [  // Optional list of instruction, overriding the top-level
33388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "Adc",        // one.
33488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "Add",
33588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ...
33688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
33788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "test-cases": [
33888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ... // Test case descriptions parsed with `ParseTestCase`.
33988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ]
34088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
34188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
34288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
34388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  name = json_test_file["name"] if "name" in json_test_file else ""
34488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if name is not "":
34588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    test_name = test_name + "-" + name
34688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # Override the top-level mnemonics list with a subset.
34788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  if "mnemonics" in json_test_file:
34888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if set(json_test_file["mnemonics"]) == set(mnemonics):
34988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      raise Exception(
35088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "Overriding mnemonic list is identical to the top-level list")
35188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    if not(set(json_test_file["mnemonics"]) < set(mnemonics)):
35288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      raise Exception(
35388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois          "Overriding mnemonic list should a subset of the top-level list")
35488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    mnemonics = json_test_file["mnemonics"]
35588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  test_cases = [
35688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ParseTestCase(json_test_case)
35788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for json_test_case in json_test_file["test-cases"]
35888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ]
35988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return generator.Generator(test_name, test_isa, json_test_file["type"],
36088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois                             mnemonics, operand_list, input_list, test_cases)
36188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
36288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
363d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langloisdef ParseConfig(test_name, test_isas, data_type_builder, json_config):
36488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
36588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Return a list of `generator.Generator` objects from a JSON description. This
36688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  is the top-level description.
36788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
36888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
36988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  {
37088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "mnemonics": [
37188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "Adc",
37288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      "Add",
37388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ...
37488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
37588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "description": [
37688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ... // Instruction description parsed with `ParseDescription`.
37788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ],
37888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    "test-files": [
37988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      ... // Test files descriptions parsed with `ParseTestFile`.
38088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois    ]
38188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  }
38288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ~~~
38388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
38488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  mnemonics = json_config["mnemonics"]
38588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  operand_list, input_list = ParseDescription(
38688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      data_type_builder, json_config["description"])
38788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
388d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  return itertools.chain(*[[
389d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois          ParseTestFile(test_name, test_isa, mnemonics, operand_list,
390d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois                        input_list, json_test_file)
391d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois          for json_test_file in json_config["test-files"]
392d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois      ]
393d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois      for test_isa in test_isas
394d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  ])
395d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois
396d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois
397d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langloisdef GetTestNameAndISAFromFileName(filename):
398d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  """
399d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  Return a tuple (name, [isa, ...]) extracted from the file name.
400d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  """
401d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  # Strip the ".json" extension
402d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  stripped_basename = os.path.splitext(os.path.basename(filename))[0]
403d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  # The ISA is the last element in the filename, seperated with "-".
404d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  if stripped_basename.endswith(('-a32', '-t32')):
405d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois    isa = [stripped_basename[-3:]]
406d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois    test_name = stripped_basename[:-4]
407d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  else:
408d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois    # If the ISA is ommitted, support both.
409d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois    isa = ["a32", "t32"]
410d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois    test_name = stripped_basename
411d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois
412d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  return (test_name, isa)
41388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
41488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
41588c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef GetTestNameFromFileName(filename):
41688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
417d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  Return the name given to this test from its file name, stripped of the
418d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  optional "a32" or "t32" at the end.
41988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
420d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  test_name, _ = GetTestNameAndISAFromFileName(filename)
421d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  return test_name
42288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
42388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
424d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langloisdef GetISAsFromFileName(filename):
42588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
426d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  Return a list of ISAs supported by the test, from the file name, either
427d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  ["a32"], ["t32"] or both.
42888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
429d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  _, isas = GetTestNameAndISAFromFileName(filename)
43088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
431d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois  return isas
43288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
43388c46b84df005638546de5e4e965bdcc31352f48Pierre Langloisdef Parse(data_type_file, config_files):
43488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
43588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  Parse the `data_type_file` and `test_case_files` json description files into a
43688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  list of (name, test_case) tuples. Test cases are `generator.TestCase`
43788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  objects that can be used to generate C++.
43888c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  """
43988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
44088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # Create a `DataTypeBuilder` object. This object will passed down and used to
44188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # instantiate `data_types.Operand` and `data_types.Input` objects.
44288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  data_type_builder = ParseDataTypes(LoadJSON(data_type_file))
44388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
44488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # Build a list of (name, JSON) tuples to represent the new tests.
44588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  json_configs = [
44688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      # We create the name of the test by looking at the file name stripped of
44788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      # its extension.
448d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois      (GetTestNameFromFileName(config_file), GetISAsFromFileName(config_file),
44988c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois       LoadJSON(config_file))
45088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois      for config_file in config_files
45188c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ]
45288c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois
45388c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # Return a list of Generator objects. The generator is the entry point to
45488c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # generate a file.
45588c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # Note that `ParseConfig` returns a list of generators already. We use `chain`
45688c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  # here to flatten a list of lists into just a list.
45788c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  return itertools.chain(*[
458d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois      ParseConfig(test_name, test_isas, data_type_builder, json_config)
459d1bf2784420717dcd20888a6eaecb18ab7f01d56Pierre Langlois      for test_name, test_isas, json_config in json_configs
46088c46b84df005638546de5e4e965bdcc31352f48Pierre Langlois  ])
461