def value_from_string(s: str) -> Value: scanner = Scanner('<text>', s) try: return value_from_scanner(scanner) except ScanError as e: raise ValueParseError( 'Could not parse value from string {!r}: {}'.format(s, e))
def _bit_value_from_scanner(s: Scanner, signed: bool) -> Value: s.drop_or_error(TokenKind.OBRACK) bit_count_tok = s.pop_or_error(TokenKind.NUMBER) s.drop_or_error(TokenKind.CBRACK) s.drop_or_error(TokenKind.COLON) value_tok = s.pop_or_error(TokenKind.NUMBER) constructor = Value.make_sbits if signed else Value.make_ubits return constructor( bit_count=ast_helpers.get_token_value_as_int(bit_count_tok), value=ast_helpers.get_token_value_as_int(value_tok))
def _bit_value_from_scanner(s: Scanner, signed: bool) -> Value: s.pop_or_error(TokenKind.OBRACK) bit_count_tok = s.pop_or_error(TokenKind.NUMBER) s.pop_or_error(TokenKind.CBRACK) s.pop_or_error(TokenKind.COLON) value_tok = s.pop_or_error(TokenKind.NUMBER) tag = Tag.SBITS if signed else Tag.UBITS return Value.make_bits( tag, ir_bits.from_long( bit_count=ast_helpers.get_token_value_as_int(bit_count_tok), value=ast_helpers.get_token_value_as_int(value_tok)))
def main(argv): if len(argv) > 2: raise app.UsageError('Too many command-line arguments.') path = argv[1] with open(path, 'r') as f: text = f.read() pprint.pprint(Scanner(path, text).pop_all())
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
def value_from_scanner(s: Scanner) -> Value: """Recursive call for converting a stream of tokens into a value.""" s = _LookaheadWrapper(s) if s.try_pop(TokenKind.OPAREN): elements = [] must_end = False while True: if s.try_pop(TokenKind.CPAREN): break if must_end: s.pop_or_error(TokenKind.CPAREN) break elements.append(value_from_scanner(s)) must_end = not s.try_pop(TokenKind.COMMA) return Value.make_tuple(tuple(elements)) if s.try_pop(TokenKind.OBRACK): elements = [] must_end = False while True: if s.try_pop(TokenKind.CBRACK): break if must_end: s.pop_or_error(TokenKind.CBRACK) break elements.append(value_from_scanner(s)) must_end = not s.try_pop(TokenKind.COMMA) return Value.make_array(tuple(elements)) if s.try_pop_keyword(Keyword.BITS) or s.try_pop_keyword(Keyword.UN): return _bit_value_from_scanner(s, signed=False) if s.try_pop_keyword(Keyword.BITS) or s.try_pop_keyword(Keyword.SN): return _bit_value_from_scanner(s, signed=True) tok = s.pop() if tok.is_type_keyword(): type_ = tok s.pop_or_error(TokenKind.COLON) value_tok = s.pop_or_error(TokenKind.NUMBER) signedness, bit_count = scanner_mod.TYPE_KEYWORDS_TO_SIGNEDNESS_AND_BITS[ type_.value] constructor = Value.make_sbits if signedness else Value.make_ubits return constructor(bit_count=bit_count, value=ast_helpers.get_token_value_as_int(value_tok)) raise ScanError(tok.span.start, 'Unexpected token in value; found {}'.format(tok.kind))