def compile(self, input_path: str, platform: str, out_path: str): ast = self.parse_input(input_path) env = self.analysis(ast) generic = self.generate_generic_code(ast, env) if platform == 'ssm': self.generate_ssm_code(generic, out_path) elif platform == 'x64': self.generate_x64_code(generic, out_path) else: Logger.error(f'Unknown target platform {platform}') sys.exit(1) print(f'Compilation of {input_path} to {out_path} succeeded')
def parse_input(self, path: str): f = open(path, 'r') InputHandler.set_input_text(f.read()) Logger.info( '-------------------------------------------------------------') Logger.info( '------------------- Starting parsing phase ------------------') Logger.info( '-------------------------------------------------------------') lexer = Lexer() Logger.info('* Starting lexing') tokens = lexer.lex_input() Logger.info('- Lexing DONE') Logger.debug('*** Printing lexed tokens: ***') for i, t in enumerate(tokens): Logger.debug('{token_type}::{value}'.format( token_type=t.token_type, value=t.value)) if len(lexer.lex_errors) > 0: for e in lexer.lex_errors: Logger.error(e) sys.exit(1) tr = TokenReader(tokens) parser = Parser(tr) Logger.info('* Starting parsing') ast = parser.parse_spl() Logger.info('- Parsing DONE') Logger.info('*** Pretty printing AST: ***') Logger.info('\n' + ast.indented_print()) if len(parser.errors) > 0: for e in parser.errors: Logger.error(e) sys.exit(1) return ast
def assemble_and_link(self, file_path: str, out_path: str): object_path = out_path + '.o' cp = subprocess.run([ 'nasm', '-g', # Include debug info '-f macho64', # Macho-O file format '-o', object_path, file_path, ]) if cp.returncode == 0: cp = subprocess.run([ 'ld', '/usr/lib/libSystem.dylib', # Include C library object_path, # object file '-o', out_path ]) if cp.returncode == 0: Logger.info(f'Input file {file_path} assembled and linked to {out_path}') else: Logger.error('Error: linker returned non-zero status code') else: Logger.error('Error: assembler returned non-zero status code')
def analysis(self, ast: SPLFile): Logger.info( '-------------------------------------------------------------') Logger.info( '------------------ Starting analysis phase ------------------') Logger.info( '-------------------------------------------------------------') Logger.info('* Starting return value checking') rvc = ReturnValueChecker() return_warnings, return_errors = rvc.check_spl_file(ast) Logger.info('- Return value checking DONE') if len(return_warnings) > 0: for w in return_warnings: Logger.warning(w) if len(return_errors) > 0: for e in return_errors: Logger.error(e) sys.exit(1) context = Context() for b in self.builtins: b.add_to_context(context) Logger.info( f'- Added {len(self.builtins)} builtin functions to binding context: {self.get_builtin_str()}' ) binding_feedback = {'errors': [], 'warnings': []} Logger.info('* Starting binding analysis') ast.binding_analysis(context, binding_feedback) Logger.info('- Binding analysis DONE') Logger.info( '*** Pretty printing AST with identifier IDs after binding analysis: ***' ) Logger.info('\n' + ast.indented_print()) if len(binding_feedback['warnings']) > 0: for w in binding_feedback['warnings']: Logger.warning(w) if len(binding_feedback['errors']) > 0: for e in binding_feedback['errors']: Logger.error(e) sys.exit(1) env = Env() for b in self.builtins: b.add_to_env(env) Logger.info( f'- Added {len(self.builtins)} builtin functions to type environment: {self.get_builtin_str()}' ) subst = Subst.empty() Logger.info('* Starting type inference') try: subst = ast.infer_type(env, InferenceVoid()) except Exception as e: Logger.error(str(e)) # raise e sys.exit(1) env.substitute(subst) Logger.debug('* Inferred function types after inference:') for name, f in env.functions.items(): Logger.debug( f'- {name} :: args: [{", ".join(str(a) for a in f.usage.arg_types)}], ret: {str(f.usage.return_type)}' ) Logger.debug('* Inferred variable types after inference:') for num, v in env.variables.items(): Logger.debug(f'- {num} :: {str(v)}') Logger.info('- Typing DONE') return env