Esempio n. 1
0
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
Esempio n. 2
0
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()
Esempio n. 3
0
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)
Esempio n. 4
0
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
Esempio n. 5
0
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() == """\
Esempio n. 6
0
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