Exemplo n.º 1
0
def parse_text(
    text: Text,
    name: Text,
    print_on_error: bool,
    *,
    import_cache: ImportCache,
    additional_search_paths: Tuple[str, ...],
    filename: Text,
    fs_open: Callable[[Text], io.IOBase] = None,
) -> Tuple[ast.Module, type_info_mod.TypeInfo]:
    """Parses text into a module with name "name" and typechecks it."""
    logging.vlog(1, 'Parsing text; name: %r', name)
    module = parser_helpers.parse_text(text,
                                       name,
                                       print_on_error=print_on_error,
                                       filename=filename,
                                       fs_open=fs_open)
    logging.vlog(1, 'Parsed text; name: %r', name)

    try:
        type_info = cpp_typecheck.check_module(module, import_cache,
                                               additional_search_paths)
    except (XlsTypeError, TypeInferenceError) as e:
        if print_on_error:
            # If the typecheck fails, pretty-print the error.
            parser_helpers.pprint_positional_error(e, fs_open=fs_open)
        raise

    return module, type_info
Exemplo n.º 2
0
    def _typecheck(self,
                   text: Text,
                   error: Optional[Text] = None,
                   error_type=XlsTypeError):
        """Checks the first function in "text" for type errors.

    Args:
      text: Text to parse.
      error: Whether it is expected that the text will cause a type error.
      error_type: Type of error to check for, if "error" is given.
    """
        filename = '/fake/test_module.x'
        with fakefs_test_util.scoped_fakefs(filename, text):
            try:
                m = parser_helpers.parse_text(text,
                                              'test_module',
                                              print_on_error=True,
                                              filename=filename)
            except cpp_parser.CppParseError as e:
                parser_helpers.pprint_positional_error(e)
                raise

            if error:
                with self.assertRaises(error_type) as cm:
                    typecheck.check_module(m, f_import=None)
                self.assertIn(error, str(cm.exception))
            else:
                try:
                    typecheck.check_module(m, f_import=None)
                except (span.PositionalError, cpp_parser.CppParseError) as e:
                    parser_helpers.pprint_positional_error(e)
                    raise
Exemplo n.º 3
0
Arquivo: repl.py Projeto: hixio-mh/xls
def handle_line(line: str, stmt_index: int):
    """Runs a single user-provided line as a REPL input."""
    fn_name = f'repl_{stmt_index}'
    module_text = f"""
  import std
  fn {fn_name}() -> () {{
    {line}
  }}
  """

    # For error reporting we use a helper that puts this into a fake filesystem
    # location.
    def make_fakefs_open():
        fs = fake_filesystem.FakeFilesystem()
        fs.CreateFile(FILENAME, module_text)
        return fake_filesystem.FakeFileOpen(fs)

    import_cache = import_routines.ImportCache()

    while True:
        try:
            fake_module = parser.Parser(scanner.Scanner(FILENAME, module_text),
                                        fn_name).parse_module()
        except span.PositionalError as e:
            parser_helpers.pprint_positional_error(e,
                                                   fs_open=make_fakefs_open())
            return

        # First attempt at type checking, we expect this may fail the first time
        # around and we'll substitute the real return type we observe.
        try:
            f_import = functools.partial(import_routines.do_import,
                                         cache=import_cache)
            type_info = typecheck.check_module(fake_module, f_import=f_import)
        except xls_type_error.XlsTypeError as e:
            # We use nil as a placeholder, and swap it with the type that was expected
            # and retry once we determine what that should be.
            if e.rhs_type == concrete_type_mod.ConcreteType.NIL:
                module_text = module_text.replace(' -> ()',
                                                  ' -> ' + str(e.lhs_type))
                continue
            # Any other errors are likely real type errors in the code and we should
            # report them.
            parser_helpers.pprint_positional_error(e,
                                                   fs_open=make_fakefs_open())
            return

        # It type checked ok, and we can proceed.
        break

    # Interpret the line and print the result.
    # TODO(leary): 2020-06-20 No let bindings for the moment, just useful for
    # evaluating expressions -- could put them into the module scope as consts.
    interpreter = interpreter_mod.Interpreter(fake_module,
                                              type_info,
                                              f_import=f_import,
                                              trace_all=False)
    result = interpreter.run_function(fn_name, args=())
    print(result)
    return result
Exemplo n.º 4
0
def main(argv):
    binary = os.path.basename(argv[0])
    if len(argv) < 2:
        raise app.UsageError('Wrong number of command-line arguments; '
                             'expect %s <input-file>' % binary)

    path = argv[1]
    with open(path, 'r') as f:
        text = f.read()

    name = os.path.basename(path)
    name, _ = os.path.splitext(name)
    module = parser_helpers.parse_text(text,
                                       name,
                                       print_on_error=True,
                                       filename=path)

    import_cache = {}
    f_import = functools.partial(import_routines.do_import, cache=import_cache)

    try:
        node_to_type = typecheck.check_module(module, f_import)
        if FLAGS.entry:
            print(
                ir_converter.convert_one_function(module, FLAGS.entry,
                                                  node_to_type))
        else:
            print(ir_converter.convert_module(module, node_to_type))
    except PositionalError as e:
        parser_helpers.pprint_positional_error(e)
        if FLAGS.raise_exception:
            raise
        else:
            sys.exit(1)
Exemplo n.º 5
0
def _run_typecheck(module: ast.Module, print_on_error: bool,
                   f_import: ImportFn,
                   fs_open: Callable[[Text], io.IOBase]) -> deduce.NodeToType:
    try:
        return typecheck.check_module(module, f_import)
    except XlsTypeError as e:
        if print_on_error:
            # If the typecheck fails, pretty-print the error.
            parser_helpers.pprint_positional_error(e, fs_open=fs_open)
        raise
Exemplo n.º 6
0
def _run_typecheck(
        module: ast.Module, print_on_error: bool, f_import: ImportFn,
        fs_open: Callable[[Text], io.IOBase]) -> type_info_mod.TypeInfo:
    try:
        return typecheck.check_module(module, f_import)
    except (XlsTypeError, TypeInferenceError) as e:
        if print_on_error:
            # If the typecheck fails, pretty-print the error.
            parser_helpers.pprint_positional_error(e, fs_open=fs_open)
        raise
Exemplo n.º 7
0
 def _parse_internal(
     self, program: Text, bindings: Optional[parser.Bindings],
     fparse: Callable[[parser.Parser, parser.Bindings],
                      TypeVar('T')]
 ) -> TypeVar('T'):
     with fakefs_test_util.scoped_fakefs(self.fake_filename, program):
         s = scanner.Scanner(self.fake_filename, program)
         b = bindings or parser.Bindings(None)
         try:
             e = fparse(parser.Parser(s, 'test_module'), b)
         except parser.CppParseError as e:
             parser_helpers.pprint_positional_error(e)
             raise
         self.assertTrue(s.at_eof())
         return e
Exemplo n.º 8
0
 def test_generates_valid_functions(self):
   g = ast_generator.AstGenerator(
       random.Random(0), ast_generator.AstGeneratorOptions())
   for i in range(32):
     print('Generating sample', i)
     _, m = g.generate_function_in_module('main', 'test')
     text = str(m)
     filename = '/fake/test_sample.x'
     with fakefs_test_util.scoped_fakefs(filename, text):
       try:
         module = parser_helpers.parse_text(
             text, name='test_sample', print_on_error=True, filename=filename)
         typecheck.check_module(module, f_import=None)
       except PositionalError as e:
         parser_helpers.pprint_positional_error(e)
         raise
Exemplo n.º 9
0
def main(argv):
    binary = os.path.basename(argv[0])
    if len(argv) < 2:
        raise app.UsageError('Wrong number of command-line arguments; '
                             'expect %s <input-file>' % binary)

    init_xls.init_xls(sys.argv)

    path = argv[1]
    with open(path, 'r') as f:
        text = f.read()

    name = os.path.basename(path)
    name, _ = os.path.splitext(name)
    module = parser_helpers.parse_text(text,
                                       name,
                                       print_on_error=True,
                                       filename=path)

    importer = import_helpers.Importer(tuple(FLAGS.dslx_path))
    type_info = None

    try:
        type_info = cpp_typecheck.check_module(
            module, importer.cache, importer.additional_search_paths)
        if FLAGS.entry:
            print(
                ir_converter.convert_one_function(module, FLAGS.entry,
                                                  type_info))
        else:
            print(ir_converter.convert_module(module, type_info))
    except (PositionalError, cpp_parser.CppParseError) as e:
        parser_helpers.pprint_positional_error(e)
        if FLAGS.raise_exception:
            raise
        else:
            sys.exit(1)
    finally:
        if type_info is not None:
            type_info.clear_type_info_refs_for_gc()
Exemplo n.º 10
0
    def test_pprint_parse_error(self):
        output = io.StringIO()
        filename = '/fake/test_file.x'
        text = 'oh\nwhoops\nI did an\nerror somewhere\nthat is bad'
        with fakefs_util.scoped_fakefs(filename, text):
            pos = scanner.Pos(filename, lineno=2, colno=0)
            span = Span(pos, pos.bump_col())
            error = parser.ParseError(span, 'This is bad')
            parser_helpers.pprint_positional_error(error,
                                                   output=cast(
                                                       io.IOBase, output),
                                                   color=False,
                                                   error_context_line_count=3)

        expected = textwrap.dedent("""\
    /fake/test_file.x:2-4
      0002: whoops
    * 0003: I did an
            ^^ This is bad @ /fake/test_file.x:3:1
      0004: error somewhere
    """)
        self.assertMultiLineEqual(expected, output.getvalue())
Exemplo n.º 11
0
def parse_and_test(program: Text,
                   name: Text,
                   *,
                   filename: Text,
                   raise_on_error: bool = True,
                   test_filter: Optional[Text] = None,
                   trace_all: bool = False,
                   compare_jit: bool = True,
                   seed: Optional[int] = None) -> bool:
    """Parses program and run all tests contained inside.

  Args:
    program: The program text to parse.
    name: Name for the module.
    filename: The filename from which "program" text originates.
    raise_on_error: When true, raises exceptions that happen in tests;
      otherwise, simply returns a boolean to the caller when all test have run.
    test_filter: Test filter specification (e.g. as passed from bazel test
      environment).
    trace_all: Whether or not to trace all expressions.
    compare_jit: Whether or not to assert equality between interpreted and
      JIT'd function return values.
    seed: Seed for QuickCheck random input stimulus.

  Returns:
    Whether or not an error occurred during parsing/testing.

  Raises:
    ScanError, ParseError: In case of front-end errors.
    TypeInferenceError, TypeError: In case of type errors.
    EvaluateError: In case of a runtime failure.
  """
    did_fail = False
    test_name = None
    import_cache = import_routines.ImportCache()
    f_import = functools.partial(import_routines.do_import, cache=import_cache)
    type_info = None

    try:
        module = Parser(Scanner(filename, program), name).parse_module()
        type_info = typecheck.check_module(module, f_import)

        ir_package = (ir_converter.convert_module_to_package(
            module, type_info, traverse_tests=True) if compare_jit else None)

        interpreter = Interpreter(module,
                                  type_info,
                                  f_import,
                                  trace_all=trace_all,
                                  ir_package=ir_package)
        for test_name in module.get_test_names():
            if not _matches(test_name, test_filter):
                continue
            print('[ RUN UNITTEST     ]', test_name, file=sys.stderr)
            interpreter.run_test(test_name)
            print('[               OK ]', test_name, file=sys.stderr)

        if ir_package and module.get_quickchecks():
            if seed is None:
                # We want to guarantee non-determinism by default. See
                # https://abseil.io/docs/cpp/guides/random#stability-of-generated-sequences
                # for rationale.
                seed = int(os.getpid() * time.time())
            print(f'[ SEED: {seed} ]')
            for quickcheck in module.get_quickchecks():
                test_name = quickcheck.f.name.identifier
                print('[ RUN QUICKCHECK   ]', test_name, file=sys.stderr)
                interpreter.run_quickcheck(quickcheck, seed=seed)
                print('[               OK ]', test_name, file=sys.stderr)

    except PositionalError as e:
        did_fail = True
        parser_helpers.pprint_positional_error(e)
        if test_name:
            print('[           FAILED ]',
                  test_name,
                  e.__class__.__name__,
                  file=sys.stderr)
        if raise_on_error:
            raise
    finally:
        if type_info is not None:
            type_info.clear_type_info_refs_for_gc()

    return did_fail