def compile_cairo_extended( code: Union[str, Sequence[Tuple[str, str]]], prime: int, cairo_path: List[str] = [], debug_info: bool = False, preprocessor_cls: Type[Preprocessor] = Preprocessor, add_start: bool = False, simple: bool = False) -> Tuple[Program, Set[str]]: """ Same as compile_cairo(), except that imported Cairo modules are returned. """ file_contents_for_debug_info = {} if isinstance(code, str): codes_with_filenames = [(code, '')] if isinstance(code, list): codes_with_filenames = code if add_start: codes_with_filenames = add_start_code(codes_with_filenames) # Add the start code to the debug info if exists. if START_FILE_NAME == codes_with_filenames[0][1]: file_contents_for_debug_info[START_FILE_NAME] = codes_with_filenames[0][0] module_reader = get_module_reader(cairo_path) preprocessed_program = preprocess_codes( codes_with_filenames, prime, module_reader.read, MAIN_SCOPE, preprocessor_cls) program = assemble( preprocessed_program, main_scope=MAIN_SCOPE, add_debug_info=debug_info, file_contents_for_debug_info=file_contents_for_debug_info) if not simple: check_main_args(program) return program, module_reader.source_files
def verify_exception(code: str, error: str, files: Dict[str, str] = {}, main_scope: ScopedName = ScopedName(), exc_type=PreprocessorError, preprocessor_cls: Optional[Type[Preprocessor]] = None): """ Verifies that compiling the code results in the given error. """ with pytest.raises(exc_type) as e: preprocess_codes([(code, '')], prime=PRIME, read_module=read_file_from_dict(files), main_scope=main_scope, preprocessor_cls=preprocessor_cls) # Remove line and column information from the error using a regular expression. assert re.sub(':[0-9]+:[0-9]+: ', 'file:?:?: ', str(e.value)) == error.strip()
def preprocess_str( code: str, prime: int, main_scope: Optional[ScopedName] = None) -> PreprocessedProgram: if main_scope is None: main_scope = TEST_SCOPE return preprocess_codes([(code, '')], prime, read_module=default_read_module, main_scope=main_scope)
def test_import_identifiers(): # Define files used in this test. files = { '.': """ from a.b.c import alpha as x from a.b.c import beta from a.b.c import xi """, 'a.b.c': """ from tau import xi const alpha = 0 const beta = 1 const gamma = 2 """, 'tau': """ const xi = 42 """ } # Prepare auxiliary functions for tests. scope = ScopedName.from_string def get_full_name(name, curr_scope=''): try: return program.identifiers.search( accessible_scopes=[scope(curr_scope)], name=scope(name)).get_canonical_name() except IdentifierError: return None # Preprocess program. program = preprocess_codes(codes=[(files['.'], '.')], prime=PRIME, read_module=read_file_from_dict(files), main_scope=scope('__main__')) # Verify identifiers are resolved correctly. assert get_full_name('x', '__main__') == scope('a.b.c.alpha') assert get_full_name('beta', '__main__') == scope('a.b.c.beta') assert get_full_name('xi', '__main__') == scope('tau.xi') assert get_full_name('alpha', 'a.b.c') == scope('a.b.c.alpha') assert get_full_name('beta', 'a.b.c') == scope('a.b.c.beta') assert get_full_name('gamma', 'a.b.c') == scope('a.b.c.gamma') assert get_full_name('xi', 'a.b.c') == scope('tau.xi') assert get_full_name('xi', 'tau') == scope('tau.xi') # Verify inaccessible identifiers. assert get_full_name('alpha', '__main__') is None assert get_full_name('gamma', '__main__') is None assert get_full_name('a.b.c.alpha', '__main__') is None assert get_full_name('tau.xi', '__main__') is None
def test_import(): files = { '.': """ from a import f as g call g """, 'a': """ func f(): jmp f end """ } program = preprocess_codes(codes=[(files['.'], '.')], prime=PRIME, read_module=read_file_from_dict(files)) assert program.format() == """\
def main(): start_time = time.time() parser = argparse.ArgumentParser( description='A tool to compile Cairo code.') parser.add_argument('files', metavar='file', type=str, nargs='+', help='File names') parser.add_argument('--prime', type=int, default=DEFAULT_PRIME, help='The size of the finite field.') parser.add_argument( '--cairo_path', type=str, default='', help= ('A list of directories, separated by ":" to resolve import paths. ' 'The full list will consist of directories defined by this argument, followed by ' f'the environment variable {LIBS_DIR_ENVVAR}, the working directory and the standard ' 'library path.')) parser.add_argument( '--preprocess', action='store_true', help= 'Stop after the preprocessor step and output the preprocessed program.' ) parser.add_argument('--output', type=argparse.FileType('w'), help='The output file name (default: stdout).') parser.add_argument('--no_debug_info', dest='debug_info', action='store_false', help='Include debug information.') parser.add_argument( '--debug_info_with_source', action='store_true', help='Include debug information with a copy of the source code.') parser.add_argument( '--simple', action='store_true', help='Compile the program without adding additional code. ' 'In particular, program starts at the __start__ label, instead of the main() function.' ) parser.add_argument( '--cairo_dependencies', type=str, help= 'Output a list of the Cairo source files used during the compilation as a CMake file.' ) args = parser.parse_args() debug_info = args.debug_info or args.debug_info_with_source source_files = set() erred: bool = False try: codes = get_codes(args.files) if not args.simple: codes = add_start_code(codes) out = args.output if args.output is not None else sys.stdout cairo_path = list( filter( None, args.cairo_path.split(':') + os.getenv(LIBS_DIR_ENVVAR, '').split(':'))) if args.preprocess: module_reader = get_module_reader(cairo_path) preprocessed = preprocess_codes(codes, args.prime, module_reader.read, MAIN_SCOPE) source_files = module_reader.source_files print(preprocessed.format(), end='', file=out) else: program, source_files = compile_cairo_extended(codes, args.prime, cairo_path, debug_info, simple=args.simple) if args.debug_info_with_source: for source_file in source_files | set(args.files): program.debug_info.file_contents[source_file] = open( source_file).read() json.dump(Program.Schema().dump(program), out, indent=4, sort_keys=True) # Print a new line at the end. print(file=out) except LocationError as err: print(err, file=sys.stderr) erred = True if args.cairo_dependencies: generate_cairo_dependencies_file(args.cairo_dependencies, source_files | set(args.files), start_time) return 1 if erred else 0