xref: /aosp_15_r20/external/emboss/compiler/front_end/glue.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1*99e0aae7SDavid Rees# Copyright 2019 Google LLC
2*99e0aae7SDavid Rees#
3*99e0aae7SDavid Rees# Licensed under the Apache License, Version 2.0 (the "License");
4*99e0aae7SDavid Rees# you may not use this file except in compliance with the License.
5*99e0aae7SDavid Rees# You may obtain a copy of the License at
6*99e0aae7SDavid Rees#
7*99e0aae7SDavid Rees#     https://www.apache.org/licenses/LICENSE-2.0
8*99e0aae7SDavid Rees#
9*99e0aae7SDavid Rees# Unless required by applicable law or agreed to in writing, software
10*99e0aae7SDavid Rees# distributed under the License is distributed on an "AS IS" BASIS,
11*99e0aae7SDavid Rees# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*99e0aae7SDavid Rees# See the License for the specific language governing permissions and
13*99e0aae7SDavid Rees# limitations under the License.
14*99e0aae7SDavid Rees
15*99e0aae7SDavid Rees"""Main driver for the Emboss front-end.
16*99e0aae7SDavid Rees
17*99e0aae7SDavid ReesThe parse_emboss_file function performs a complete parse of the specified file,
18*99e0aae7SDavid Reesand returns an IR or formatted error message.
19*99e0aae7SDavid Rees"""
20*99e0aae7SDavid Rees
21*99e0aae7SDavid Reesimport collections
22*99e0aae7SDavid Rees
23*99e0aae7SDavid Reesfrom compiler.front_end import attribute_checker
24*99e0aae7SDavid Reesfrom compiler.front_end import constraints
25*99e0aae7SDavid Reesfrom compiler.front_end import dependency_checker
26*99e0aae7SDavid Reesfrom compiler.front_end import expression_bounds
27*99e0aae7SDavid Reesfrom compiler.front_end import lr1
28*99e0aae7SDavid Reesfrom compiler.front_end import module_ir
29*99e0aae7SDavid Reesfrom compiler.front_end import parser
30*99e0aae7SDavid Reesfrom compiler.front_end import symbol_resolver
31*99e0aae7SDavid Reesfrom compiler.front_end import synthetics
32*99e0aae7SDavid Reesfrom compiler.front_end import tokenizer
33*99e0aae7SDavid Reesfrom compiler.front_end import type_check
34*99e0aae7SDavid Reesfrom compiler.front_end import write_inference
35*99e0aae7SDavid Reesfrom compiler.util import error
36*99e0aae7SDavid Reesfrom compiler.util import ir_data
37*99e0aae7SDavid Reesfrom compiler.util import ir_data_utils
38*99e0aae7SDavid Reesfrom compiler.util import parser_types
39*99e0aae7SDavid Reesfrom compiler.util import resources
40*99e0aae7SDavid Rees
41*99e0aae7SDavid Rees_IrDebugInfo = collections.namedtuple("IrDebugInfo", ["ir", "debug_info",
42*99e0aae7SDavid Rees                                                      "errors"])
43*99e0aae7SDavid Rees
44*99e0aae7SDavid Rees
45*99e0aae7SDavid Reesclass DebugInfo(object):
46*99e0aae7SDavid Rees  """Debug information about Emboss parsing."""
47*99e0aae7SDavid Rees  __slots__ = ("modules")
48*99e0aae7SDavid Rees
49*99e0aae7SDavid Rees  def __init__(self):
50*99e0aae7SDavid Rees    self.modules = {}
51*99e0aae7SDavid Rees
52*99e0aae7SDavid Rees  def __eq__(self, other):
53*99e0aae7SDavid Rees    return self.modules == other.modules
54*99e0aae7SDavid Rees
55*99e0aae7SDavid Rees  def __ne__(self, other):
56*99e0aae7SDavid Rees    return not self == other
57*99e0aae7SDavid Rees
58*99e0aae7SDavid Rees
59*99e0aae7SDavid Reesclass ModuleDebugInfo(object):
60*99e0aae7SDavid Rees  """Debug information about the parse of a single file.
61*99e0aae7SDavid Rees
62*99e0aae7SDavid Rees  Attributes:
63*99e0aae7SDavid Rees    file_name: The name of the file from which this module came.
64*99e0aae7SDavid Rees    tokens: The tokenization of this module's source text.
65*99e0aae7SDavid Rees    parse_tree: The raw parse tree for this module.
66*99e0aae7SDavid Rees    ir: The intermediate representation of this module, before additional
67*99e0aae7SDavid Rees        processing such as symbol resolution.
68*99e0aae7SDavid Rees    used_productions: The set of grammar productions used when parsing this
69*99e0aae7SDavid Rees        module.
70*99e0aae7SDavid Rees    source_code: The source text of the module.
71*99e0aae7SDavid Rees  """
72*99e0aae7SDavid Rees  __slots__ = ("file_name", "tokens", "parse_tree", "ir", "used_productions",
73*99e0aae7SDavid Rees               "source_code")
74*99e0aae7SDavid Rees
75*99e0aae7SDavid Rees  def __init__(self, file_name):
76*99e0aae7SDavid Rees    self.file_name = file_name
77*99e0aae7SDavid Rees    self.tokens = None
78*99e0aae7SDavid Rees    self.parse_tree = None
79*99e0aae7SDavid Rees    self.ir = None
80*99e0aae7SDavid Rees    self.used_productions = None
81*99e0aae7SDavid Rees    self.source_code = None
82*99e0aae7SDavid Rees
83*99e0aae7SDavid Rees  def __eq__(self, other):
84*99e0aae7SDavid Rees    return (self.file_name == other.file_name and self.tokens == other.tokens
85*99e0aae7SDavid Rees            and self.parse_tree == other.parse_tree and self.ir == other.ir and
86*99e0aae7SDavid Rees            self.used_productions == other.used_productions and
87*99e0aae7SDavid Rees            self.source_code == other.source_code)
88*99e0aae7SDavid Rees
89*99e0aae7SDavid Rees  def __ne__(self, other):
90*99e0aae7SDavid Rees    return not self == other
91*99e0aae7SDavid Rees
92*99e0aae7SDavid Rees  def format_tokenization(self):
93*99e0aae7SDavid Rees    """Renders self.tokens in a human-readable format."""
94*99e0aae7SDavid Rees    return "\n".join([str(token) for token in self.tokens])
95*99e0aae7SDavid Rees
96*99e0aae7SDavid Rees  def format_parse_tree(self, parse_tree=None, indent=""):
97*99e0aae7SDavid Rees    """Renders self.parse_tree in a human-readable format."""
98*99e0aae7SDavid Rees    if parse_tree is None:
99*99e0aae7SDavid Rees      parse_tree = self.parse_tree
100*99e0aae7SDavid Rees    result = []
101*99e0aae7SDavid Rees    if isinstance(parse_tree, lr1.Reduction):
102*99e0aae7SDavid Rees      result.append(indent + parse_tree.symbol)
103*99e0aae7SDavid Rees      if parse_tree.children:
104*99e0aae7SDavid Rees        result.append(":\n")
105*99e0aae7SDavid Rees        for child in parse_tree.children:
106*99e0aae7SDavid Rees          result.append(self.format_parse_tree(child, indent + "  "))
107*99e0aae7SDavid Rees      else:
108*99e0aae7SDavid Rees        result.append("\n")
109*99e0aae7SDavid Rees    else:
110*99e0aae7SDavid Rees      result.append("{}{}\n".format(indent, parse_tree))
111*99e0aae7SDavid Rees    return "".join(result)
112*99e0aae7SDavid Rees
113*99e0aae7SDavid Rees  def format_module_ir(self):
114*99e0aae7SDavid Rees    """Renders self.ir in a human-readable format."""
115*99e0aae7SDavid Rees    return ir_data_utils.IrDataSerializer(self.ir).to_json(indent=2)
116*99e0aae7SDavid Rees
117*99e0aae7SDavid Rees
118*99e0aae7SDavid Reesdef format_production_set(productions):
119*99e0aae7SDavid Rees  """Renders a set of productions in a human-readable format."""
120*99e0aae7SDavid Rees  return "\n".join([str(production) for production in sorted(productions)])
121*99e0aae7SDavid Rees
122*99e0aae7SDavid Rees
123*99e0aae7SDavid Rees_cached_modules = {}
124*99e0aae7SDavid Rees
125*99e0aae7SDavid Rees
126*99e0aae7SDavid Reesdef parse_module_text(source_code, file_name):
127*99e0aae7SDavid Rees  """Parses the text of a module, returning a module-level IR.
128*99e0aae7SDavid Rees
129*99e0aae7SDavid Rees  Arguments:
130*99e0aae7SDavid Rees    source_code: The text of the module to parse.
131*99e0aae7SDavid Rees    file_name: The name of the module's source file (will be included in the
132*99e0aae7SDavid Rees        resulting IR).
133*99e0aae7SDavid Rees
134*99e0aae7SDavid Rees  Returns:
135*99e0aae7SDavid Rees    A module-level intermediate representation (IR), prior to import and symbol
136*99e0aae7SDavid Rees    resolution, and a corresponding ModuleDebugInfo, for debugging the parser.
137*99e0aae7SDavid Rees
138*99e0aae7SDavid Rees  Raises:
139*99e0aae7SDavid Rees    FrontEndFailure: An error occurred while parsing the module.  str(error)
140*99e0aae7SDavid Rees        will give a human-readable error message.
141*99e0aae7SDavid Rees  """
142*99e0aae7SDavid Rees  # This is strictly an optimization to speed up tests, mostly by avoiding the
143*99e0aae7SDavid Rees  # need to re-parse the prelude for every test .emb.
144*99e0aae7SDavid Rees  if (source_code, file_name) in _cached_modules:
145*99e0aae7SDavid Rees    debug_info = _cached_modules[source_code, file_name]
146*99e0aae7SDavid Rees    ir = ir_data_utils.copy(debug_info.ir)
147*99e0aae7SDavid Rees  else:
148*99e0aae7SDavid Rees    debug_info = ModuleDebugInfo(file_name)
149*99e0aae7SDavid Rees    debug_info.source_code = source_code
150*99e0aae7SDavid Rees    tokens, errors = tokenizer.tokenize(source_code, file_name)
151*99e0aae7SDavid Rees    if errors:
152*99e0aae7SDavid Rees      return _IrDebugInfo(None, debug_info, errors)
153*99e0aae7SDavid Rees    debug_info.tokens = tokens
154*99e0aae7SDavid Rees    parse_result = parser.parse_module(tokens)
155*99e0aae7SDavid Rees    if parse_result.error:
156*99e0aae7SDavid Rees      return _IrDebugInfo(
157*99e0aae7SDavid Rees          None,
158*99e0aae7SDavid Rees          debug_info,
159*99e0aae7SDavid Rees          [error.make_error_from_parse_error(file_name, parse_result.error)])
160*99e0aae7SDavid Rees    debug_info.parse_tree = parse_result.parse_tree
161*99e0aae7SDavid Rees    used_productions = set()
162*99e0aae7SDavid Rees    ir = module_ir.build_ir(parse_result.parse_tree, used_productions)
163*99e0aae7SDavid Rees    ir.source_text = source_code
164*99e0aae7SDavid Rees    debug_info.used_productions = used_productions
165*99e0aae7SDavid Rees    debug_info.ir = ir_data_utils.copy(ir)
166*99e0aae7SDavid Rees    _cached_modules[source_code, file_name] = debug_info
167*99e0aae7SDavid Rees  ir.source_file_name = file_name
168*99e0aae7SDavid Rees  return _IrDebugInfo(ir, debug_info, [])
169*99e0aae7SDavid Rees
170*99e0aae7SDavid Rees
171*99e0aae7SDavid Reesdef parse_module(file_name, file_reader):
172*99e0aae7SDavid Rees  """Parses a module, returning a module-level IR.
173*99e0aae7SDavid Rees
174*99e0aae7SDavid Rees  Arguments:
175*99e0aae7SDavid Rees    file_name: The name of the module's source file.
176*99e0aae7SDavid Rees    file_reader: A callable that returns either:
177*99e0aae7SDavid Rees        (file_contents, None) or
178*99e0aae7SDavid Rees        (None, list_of_error_detail_strings)
179*99e0aae7SDavid Rees
180*99e0aae7SDavid Rees  Returns:
181*99e0aae7SDavid Rees    (ir, debug_info, errors), where ir is a module-level intermediate
182*99e0aae7SDavid Rees    representation (IR), debug_info is a ModuleDebugInfo containing the
183*99e0aae7SDavid Rees    tokenization, parse tree, and original source text of all modules, and
184*99e0aae7SDavid Rees    errors is a list of tokenization or parse errors.  If errors is not an empty
185*99e0aae7SDavid Rees    list, ir will be None.
186*99e0aae7SDavid Rees
187*99e0aae7SDavid Rees  Raises:
188*99e0aae7SDavid Rees    FrontEndFailure: An error occurred while reading or parsing the module.
189*99e0aae7SDavid Rees        str(error) will give a human-readable error message.
190*99e0aae7SDavid Rees  """
191*99e0aae7SDavid Rees  source_code, errors = file_reader(file_name)
192*99e0aae7SDavid Rees  if errors:
193*99e0aae7SDavid Rees    location = parser_types.make_location((1, 1), (1, 1))
194*99e0aae7SDavid Rees    return None, None, [
195*99e0aae7SDavid Rees        [error.error(file_name, location, "Unable to read file.")] +
196*99e0aae7SDavid Rees        [error.note(file_name, location, e) for e in errors]
197*99e0aae7SDavid Rees    ]
198*99e0aae7SDavid Rees  return parse_module_text(source_code, file_name)
199*99e0aae7SDavid Rees
200*99e0aae7SDavid Rees
201*99e0aae7SDavid Reesdef get_prelude():
202*99e0aae7SDavid Rees  """Returns the module IR and debug info of the Emboss Prelude."""
203*99e0aae7SDavid Rees  return parse_module_text(
204*99e0aae7SDavid Rees      resources.load("compiler.front_end", "prelude.emb"), "")
205*99e0aae7SDavid Rees
206*99e0aae7SDavid Rees
207*99e0aae7SDavid Reesdef parse_emboss_file(file_name, file_reader, stop_before_step=None):
208*99e0aae7SDavid Rees  """Fully parses an .emb, and returns an IR suitable for passing to a back end.
209*99e0aae7SDavid Rees
210*99e0aae7SDavid Rees  parse_emboss_file is a convenience function which calls only_parse_emboss_file
211*99e0aae7SDavid Rees  and process_ir.
212*99e0aae7SDavid Rees
213*99e0aae7SDavid Rees  Arguments:
214*99e0aae7SDavid Rees    file_name: The name of the module's source file.
215*99e0aae7SDavid Rees    file_reader: A callable that returns the contents of files, or raises
216*99e0aae7SDavid Rees        IOError.
217*99e0aae7SDavid Rees    stop_before_step: If set, parse_emboss_file will stop normalizing the IR
218*99e0aae7SDavid Rees        just before the specified step.  This parameter should be None for
219*99e0aae7SDavid Rees        non-test code.
220*99e0aae7SDavid Rees
221*99e0aae7SDavid Rees  Returns:
222*99e0aae7SDavid Rees    (ir, debug_info, errors), where ir is a complete IR, ready for consumption
223*99e0aae7SDavid Rees    by an Emboss back end, debug_info is a DebugInfo containing the
224*99e0aae7SDavid Rees    tokenization, parse tree, and original source text of all modules, and
225*99e0aae7SDavid Rees    errors is a list of tokenization or parse errors.  If errors is not an empty
226*99e0aae7SDavid Rees    list, ir will be None.
227*99e0aae7SDavid Rees  """
228*99e0aae7SDavid Rees  ir, debug_info, errors = only_parse_emboss_file(file_name, file_reader)
229*99e0aae7SDavid Rees  if errors:
230*99e0aae7SDavid Rees    return _IrDebugInfo(None, debug_info, errors)
231*99e0aae7SDavid Rees  ir, errors = process_ir(ir, stop_before_step)
232*99e0aae7SDavid Rees  if errors:
233*99e0aae7SDavid Rees    return _IrDebugInfo(None, debug_info, errors)
234*99e0aae7SDavid Rees  return _IrDebugInfo(ir, debug_info, errors)
235*99e0aae7SDavid Rees
236*99e0aae7SDavid Rees
237*99e0aae7SDavid Reesdef only_parse_emboss_file(file_name, file_reader):
238*99e0aae7SDavid Rees  """Parses an .emb, and returns an IR suitable for process_ir.
239*99e0aae7SDavid Rees
240*99e0aae7SDavid Rees  only_parse_emboss_file parses the given file and all of its transitive
241*99e0aae7SDavid Rees  imports, and returns a first-stage intermediate representation, which can be
242*99e0aae7SDavid Rees  passed to process_ir.
243*99e0aae7SDavid Rees
244*99e0aae7SDavid Rees  Arguments:
245*99e0aae7SDavid Rees    file_name: The name of the module's source file.
246*99e0aae7SDavid Rees    file_reader: A callable that returns the contents of files, or raises
247*99e0aae7SDavid Rees        IOError.
248*99e0aae7SDavid Rees
249*99e0aae7SDavid Rees  Returns:
250*99e0aae7SDavid Rees    (ir, debug_info, errors), where ir is an intermediate representation (IR),
251*99e0aae7SDavid Rees    debug_info is a DebugInfo containing the tokenization, parse tree, and
252*99e0aae7SDavid Rees    original source text of all modules, and errors is a list of tokenization or
253*99e0aae7SDavid Rees    parse errors.  If errors is not an empty list, ir will be None.
254*99e0aae7SDavid Rees  """
255*99e0aae7SDavid Rees  file_queue = [file_name]
256*99e0aae7SDavid Rees  files = {file_name}
257*99e0aae7SDavid Rees  debug_info = DebugInfo()
258*99e0aae7SDavid Rees  ir = ir_data.EmbossIr(module=[])
259*99e0aae7SDavid Rees  while file_queue:
260*99e0aae7SDavid Rees    file_to_parse = file_queue[0]
261*99e0aae7SDavid Rees    del file_queue[0]
262*99e0aae7SDavid Rees    if file_to_parse:
263*99e0aae7SDavid Rees      module, module_debug_info, errors = parse_module(file_to_parse,
264*99e0aae7SDavid Rees                                                       file_reader)
265*99e0aae7SDavid Rees    else:
266*99e0aae7SDavid Rees      module, module_debug_info, errors = get_prelude()
267*99e0aae7SDavid Rees    if module_debug_info:
268*99e0aae7SDavid Rees      debug_info.modules[file_to_parse] = module_debug_info
269*99e0aae7SDavid Rees    if errors:
270*99e0aae7SDavid Rees      return _IrDebugInfo(None, debug_info, errors)
271*99e0aae7SDavid Rees    ir.module.extend([module])  # Proto supports extend but not append here.
272*99e0aae7SDavid Rees    for import_ in module.foreign_import:
273*99e0aae7SDavid Rees      if import_.file_name.text not in files:
274*99e0aae7SDavid Rees        file_queue.append(import_.file_name.text)
275*99e0aae7SDavid Rees        files.add(import_.file_name.text)
276*99e0aae7SDavid Rees  return _IrDebugInfo(ir, debug_info, [])
277*99e0aae7SDavid Rees
278*99e0aae7SDavid Rees
279*99e0aae7SDavid Reesdef process_ir(ir, stop_before_step):
280*99e0aae7SDavid Rees  """Turns a first-stage IR into a fully-processed IR.
281*99e0aae7SDavid Rees
282*99e0aae7SDavid Rees  process_ir performs all of the semantic processing steps on `ir`: resolving
283*99e0aae7SDavid Rees  symbols, checking dependencies, adding type annotations, normalizing
284*99e0aae7SDavid Rees  attributes, etc.  process_ir is generally meant to be called with the result
285*99e0aae7SDavid Rees  of parse_emboss_file(), but in theory could be called with a first-stage
286*99e0aae7SDavid Rees  intermediate representation (IR) from another source.
287*99e0aae7SDavid Rees
288*99e0aae7SDavid Rees  Arguments:
289*99e0aae7SDavid Rees    ir: The IR to process.  This structure will be modified during processing.
290*99e0aae7SDavid Rees    stop_before_step: If set, process_ir will stop normalizing the IR just
291*99e0aae7SDavid Rees        before the specified step.  This parameter should be None for non-test
292*99e0aae7SDavid Rees        code.
293*99e0aae7SDavid Rees
294*99e0aae7SDavid Rees  Returns:
295*99e0aae7SDavid Rees    (ir, errors), where ir is a complete IR, ready for consumption by an Emboss
296*99e0aae7SDavid Rees    back end, and errors is a list of compilation errors.  If errors is not an
297*99e0aae7SDavid Rees    empty list, ir will be None.
298*99e0aae7SDavid Rees  """
299*99e0aae7SDavid Rees  passes = (synthetics.desugar,
300*99e0aae7SDavid Rees            symbol_resolver.resolve_symbols,
301*99e0aae7SDavid Rees            dependency_checker.find_dependency_cycles,
302*99e0aae7SDavid Rees            dependency_checker.set_dependency_order,
303*99e0aae7SDavid Rees            symbol_resolver.resolve_field_references,
304*99e0aae7SDavid Rees            type_check.annotate_types,
305*99e0aae7SDavid Rees            type_check.check_types,
306*99e0aae7SDavid Rees            expression_bounds.compute_constants,
307*99e0aae7SDavid Rees            attribute_checker.normalize_and_verify,
308*99e0aae7SDavid Rees            constraints.check_constraints,
309*99e0aae7SDavid Rees            write_inference.set_write_methods)
310*99e0aae7SDavid Rees  assert stop_before_step in [None] + [f.__name__ for f in passes], (
311*99e0aae7SDavid Rees      "Bad value for stop_before_step.")
312*99e0aae7SDavid Rees  # Some parts of the IR are synthesized from "natural" parts of the IR, before
313*99e0aae7SDavid Rees  # the natural parts have been fully error checked.  Because of this, the
314*99e0aae7SDavid Rees  # synthesized parts can have errors; in a couple of cases, they can have
315*99e0aae7SDavid Rees  # errors that show up in an earlier pass than the errors in the natural parts
316*99e0aae7SDavid Rees  # of the IR.  As an example:
317*99e0aae7SDavid Rees  #
318*99e0aae7SDavid Rees  #     struct Foo:
319*99e0aae7SDavid Rees  #       0 [+1]  bits:
320*99e0aae7SDavid Rees  #         0 [+1]  Flag  flag
321*99e0aae7SDavid Rees  #       1 [+flag]  UInt:8  field
322*99e0aae7SDavid Rees  #
323*99e0aae7SDavid Rees  # In this case, the use of `flag` as the size of `field` is incorrect, because
324*99e0aae7SDavid Rees  # `flag` is a boolean, but the size of a field must be an integer.
325*99e0aae7SDavid Rees  #
326*99e0aae7SDavid Rees  # Type checking occurs in two passes: in the first pass, expressions are
327*99e0aae7SDavid Rees  # checked for internal consistency.  In the second pass, expression types are
328*99e0aae7SDavid Rees  # checked against their location.  The use of `flag` would be caught in the
329*99e0aae7SDavid Rees  # second pass.
330*99e0aae7SDavid Rees  #
331*99e0aae7SDavid Rees  # However, the generated_fields pass will synthesize a $size_in_bytes virtual
332*99e0aae7SDavid Rees  # field that would look like:
333*99e0aae7SDavid Rees  #
334*99e0aae7SDavid Rees  #     struct Foo:
335*99e0aae7SDavid Rees  #       0 [+1]  bits:
336*99e0aae7SDavid Rees  #         0 [+1]  Flag  flag
337*99e0aae7SDavid Rees  #       1 [+flag]  UInt:8  field
338*99e0aae7SDavid Rees  #       let $size_in_bytes = $max(true ? 0 + 1 : 0, true ? 1 + flag : 0)
339*99e0aae7SDavid Rees  #
340*99e0aae7SDavid Rees  # Since `1 + flag` is not internally consistent, this type error would be
341*99e0aae7SDavid Rees  # caught in the first pass, and the user would see a very strange error
342*99e0aae7SDavid Rees  # message that "the right-hand argument of operator `+` must be an integer."
343*99e0aae7SDavid Rees  #
344*99e0aae7SDavid Rees  # In order to avoid showing these kinds of errors to the user, we defer any
345*99e0aae7SDavid Rees  # errors in synthetic parts of the IR.  Unless there is a compiler bug, those
346*99e0aae7SDavid Rees  # errors will show up as errors in the natural parts of the IR, which should
347*99e0aae7SDavid Rees  # be much more comprehensible to end users.
348*99e0aae7SDavid Rees  #
349*99e0aae7SDavid Rees  # If, for some reason, there is an error in the synthetic IR, but no error in
350*99e0aae7SDavid Rees  # the natural IR, the synthetic errors will be shown.  In this case, the
351*99e0aae7SDavid Rees  # formatting for the synthetic errors will show '[compiler bug]' for the
352*99e0aae7SDavid Rees  # error location, which (hopefully) will provide the end user with a cue that
353*99e0aae7SDavid Rees  # the error is a compiler bug.
354*99e0aae7SDavid Rees  deferred_errors = []
355*99e0aae7SDavid Rees  for function in passes:
356*99e0aae7SDavid Rees    if stop_before_step == function.__name__:
357*99e0aae7SDavid Rees      return (ir, [])
358*99e0aae7SDavid Rees    errors, hidden_errors = error.split_errors(function(ir))
359*99e0aae7SDavid Rees    if errors:
360*99e0aae7SDavid Rees      return (None, errors)
361*99e0aae7SDavid Rees    deferred_errors.extend(hidden_errors)
362*99e0aae7SDavid Rees
363*99e0aae7SDavid Rees  if deferred_errors:
364*99e0aae7SDavid Rees    return (None, deferred_errors)
365*99e0aae7SDavid Rees
366*99e0aae7SDavid Rees  assert stop_before_step is None, "Bad value for stop_before_step."
367*99e0aae7SDavid Rees  return (ir, [])
368