def specs_to_ir(specs, version='<STR_LIT>', debug=False, route_whitelist_filter=None):
parser_factory = ParserFactory(debug=debug)<EOL>partial_asts = []<EOL>for path, text in specs:<EOL><INDENT>logger.info('<STR_LIT>', path)<EOL>parser = parser_factory.get_parser()<EOL>if debug:<EOL><INDENT>parser.test_lexing(text)<EOL><DEDENT>partial_ast = parser.parse(text, path)<EOL>if parser.got_errors_parsing():<EOL><INDENT>msg, lineno, path = parser.get_errors()[<NUM_LIT:0>]<EOL>raise InvalidSpec(msg, lineno, path)<EOL><DEDENT>elif len(partial_ast) == <NUM_LIT:0>:<EOL><INDENT>logger.info('<STR_LIT>', path)<EOL><DEDENT>else:<EOL><INDENT>partial_asts.append(partial_ast)<EOL><DEDENT><DEDENT>return IRGenerator(partial_asts, version, debug=debug,<EOL>route_whitelist_filter=route_whitelist_filter).generate_IR()<EOL>
Converts a collection of Stone specifications into the intermediate
representation used by Stone backends.

The process is: Lexer -> Parser -> Semantic Analyzer -> IR Generator.

The code is structured as:
    1. Parser (Lexer embedded within)
    2. IR Generator (Semantic Analyzer embedded within)

:type specs: List[Tuple[path: str, text: str]]
:param specs: `path` is never accessed and is only used to report the
    location of a bad spec to the user. `spec` is the text contents of
    a spec (.stone) file.

:raises: InvalidSpec

:returns: stone.ir.Api