Esempio n. 1
0
File: repl.py Progetto: 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
Esempio n. 2
0
def parse_text(text: Text,
               name: Text,
               print_on_error: bool,
               filename: Text,
               *,
               fs_open=None) -> ast.Module:
    """Returns a parsed module from DSL program text.

  Pretty-prints error information to stderr if an error is encountered, before
  re-raising.

  Args:
    text: The text to parse.
    name: Name that should be given to the resulting module.
    print_on_error: Whether to print to stderr when an error occurs -- if false,
      the error is simply raised and nothing is printed.
    filename: Filename that "text" orginates from.
    fs_open: Lets the user substitute their own filesystem open; e.g. if the
      program is not materialized on the real filesystem.

  Raises:
    CppParseError: When a parsing error occurs.
    ScanError: When a scanning error occurs.
  """
    try:
        s = scanner.Scanner(filename, text)
        return parser.Parser(s, name).parse_module()
    except (parser.CppParseError, scanner.ScanError) as e:
        if print_on_error:
            pprint_positional_error(e, fs_open=fs_open)
        raise
Esempio n. 3
0
 def test_parse_error_get_span(self):
     s = scanner.Scanner(self.fake_filename, '+')
     p = parser.Parser(s, 'test_module')
     try:
         p.parse_expression(None)
     except parser.CppParseError as e:
         pos = Pos(self.fake_filename, 0, 0)
         want = Span(pos, pos.bump_col())
         self.assertEqual(parser.get_parse_error_span(str(e)), want)
     else:
         raise AssertionError
Esempio n. 4
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