def add_rules(self, **kwargs): """ Add rules to the grammar. The keyword arguments will provide a name to rules. :param dict[str, Parser] kwargs: The rules to add to the grammar. """ import ast loc = extract_library_location() class GetTheCall(ast.NodeVisitor): """ Helper visitor that will get the corresponding add_rule call in the source, so that we're then able to extract the precise line where each rule is added. """ def __init__(self): self.the_call = None def visit_Call(self, call): if (isinstance(call.func, ast.Attribute) and call.func.attr == 'add_rules' # Traceback locations are very imprecise, and python's ast # doesn't have an end location for nodes, so we'll keep # taking add_rules call, and the last is necessarily the # good one. and call.lineno <= loc.line): self.the_call = call the_call = GetTheCall() with open(loc.file) as f: file_ast = ast.parse(f.read(), f.name) the_call.visit(file_ast) # We're gonna use the keyword arguments to find back the precise line # where the rule was declared. keywords = {kw.arg: kw.value for kw in the_call.the_call.keywords} for name, rule in kwargs.items(): rule.set_name(names.Name.from_lower(name)) rule.set_grammar(self) rule.set_location(Location(loc.file, keywords[name].lineno, "")) rule.is_root = True with Context("In definition of rule '{}'".format(name), loc): check_source_language( name not in self.rules, "Rule '{}' is already present in the grammar".format(name)) self.rules[name] = rule
def run(self, argv=None): parsed_args = self.args_parser.parse_args(argv) for trace in parsed_args.trace: print("Trace {} is activated".format(trace)) Log.enable(trace) Diagnostics.set_style(parsed_args.diagnostic_style) if parsed_args.profile: import cProfile import pstats pr = cProfile.Profile() pr.enable() # Set the verbosity self.verbosity = parsed_args.verbosity self.no_ada_api = parsed_args.no_ada_api # If asked to, setup the exception hook as a last-chance handler to # invoke a debugger in case of uncaught exception. if parsed_args.debug: # Try to use IPython's debugger if it is available, otherwise # fallback to PDB. try: # noinspection PyPackageRequirements from IPython.core import ultratb except ImportError: ultratb = None # To keep PyCharm happy... def excepthook(type, value, tb): traceback.print_exception(type, value, tb) pdb.post_mortem(tb) sys.excepthook = excepthook else: sys.excepthook = ultratb.FormattedTB(mode='Verbose', color_scheme='Linux', call_pdb=1) del ultratb self.dirs.set_build_dir(parsed_args.build_dir) install_dir = getattr(parsed_args, 'install-dir', None) if install_dir: self.dirs.set_install_dir(install_dir) if getattr(parsed_args, 'list_warnings', False): WarningSet.print_list() return # noinspection PyBroadException try: parsed_args.func(parsed_args) except DiagnosticError: if parsed_args.debug: raise if parsed_args.verbosity.debug or parsed_args.full_error_traces: traceback.print_exc() print(col('Errors, exiting', Colors.FAIL), file=sys.stderr) sys.exit(1) except Exception as e: if parsed_args.debug: raise ex_type, ex, tb = sys.exc_info() # If we have a syntax error, we know for sure the last stack frame # points to the code that must be fixed. Otherwise, point to the # top-most stack frame that does not belong to Langkit. if e.args and e.args[0] == 'invalid syntax': loc = Location(e.filename, e.lineno) else: loc = extract_library_location(traceback.extract_tb(tb)) with Context("", loc, "recovery"): check_source_language(False, str(e), do_raise=False) # Keep Langkit bug "pretty" for users: display the Python stack # trace only when requested. if parsed_args.verbosity.debug or parsed_args.full_error_traces: traceback.print_exc() print(col('Internal error! Exiting', Colors.FAIL), file=sys.stderr) sys.exit(1) finally: if parsed_args.profile: pr.disable() ps = pstats.Stats(pr) ps.dump_stats('langkit.prof')
def run(self, argv=None): parsed_args = self.args_parser.parse_args(argv) from langkit import diagnostics diagnostics.EMIT_PARSABLE_ERRORS = parsed_args.parsable_errors if parsed_args.profile: import cProfile import pstats pr = cProfile.Profile() pr.enable() # If asked to, setup the exception hook as a last-chance handler to # invoke a debugger in case of uncaught exception. if parsed_args.debug: # Try to use IPython's debugger if it is available, otherwise # fallback to PDB. try: # noinspection PyPackageRequirements from IPython.core import ultratb except ImportError: ultratb = None # To keep PyCharm happy... def excepthook(type, value, tb): import traceback traceback.print_exception(type, value, tb) pdb.post_mortem(tb) sys.excepthook = excepthook else: sys.excepthook = ultratb.FormattedTB(mode='Verbose', color_scheme='Linux', call_pdb=1) del ultratb self.dirs.set_build_dir(parsed_args.build_dir) install_dir = getattr(parsed_args, 'install-dir', None) if install_dir: self.dirs.set_install_dir(install_dir) # Compute code coverage in the code generator if asked to if parsed_args.func == self.do_generate and parsed_args.coverage: try: cov = Coverage(self.dirs) except Exception as exc: import traceback print >> sys.stderr, 'Coverage not available:' traceback.print_exc(exc) sys.exit(1) cov.start() else: cov = None # noinspection PyBroadException try: parsed_args.func(parsed_args) except DiagnosticError: if parsed_args.debug: raise print >> sys.stderr, col('Errors, exiting', Colors.FAIL) sys.exit(1) except Exception, e: if parsed_args.debug: raise import traceback ex_type, ex, tb = sys.exc_info() if e.args[0] == 'invalid syntax': loc = Location(e.filename, e.lineno, "") else: loc = extract_library_location(traceback.extract_tb(tb)) with Context("", loc, "recovery"): check_source_language(False, str(e), do_raise=False) if parsed_args.verbosity.debug: traceback.print_exc() print >> sys.stderr, col('Internal error! Exiting', Colors.FAIL) sys.exit(1)
def process_unit(self, unit): base_filename = P.basename(unit.filename) print(f"Checking {base_filename}") content_changed = False # Get the file's content, for error reporting and for fixing content = unit.text.splitlines() add_content = {} # Parse, and report errors on fail if unit.root is None: print(f'Could not parse {base_filename}:') for diag in unit.diagnostics: print_error(diag.message, Location.from_sloc_range(unit, diag.sloc_range)) print(f' {diag}') # If successful, check boxes for every subprogram body for sb in unit.root.findall(lal.SubpBody): first_comment = check_unsync_box(sb) # Box is fine, or no box, continue if not first_comment: continue subp_name_node = sb.f_subp_spec.f_subp_name subp_name = subp_name_node.text # Box is malformed, report the error if first_comment == sb.token_start: print_error( f"No box for subprogram `{subp_name}`", Location.from_sloc_range(unit, subp_name_node.sloc_range)) # If user asked to fix boxes, replace the box in the source # list. if self.args.fix: content_changed = True first_line = first_comment.sloc_range.start.line indent = ' ' * (sb.sloc_range.start.column - 1) add_content[first_line - 1] = [ indent + ('-' * (len(subp_name) + 6)), f"{indent}-- {subp_name} --", indent + ('-' * (len(subp_name) + 6)), '' ] else: first_line = first_comment.sloc_range.start.line print_error( f"Malformed box for subprogram `{subp_name}`", Location.from_sloc_range(unit, first_comment.next.sloc_range)) # If user asked to fix boxes, replace the box in the source # list. if self.args.fix: content_changed = True box_dashes = indent + ("-" * (len(subp_name) + 6)) indent = ' ' * (sb.sloc_range.start.column - 1) content[first_line - 1] = box_dashes content[first_line] = f"{indent}-- {subp_name} --" content[first_line + 1] = box_dashes if content_changed: # Then dump to file again with open(unit.filename, 'w') as f: for i, l in enumerate(content): if i in add_content: for line in add_content[i]: f.write(f"{line}\n") f.write(f"{l}\n")
def run_no_exit(self, argv: Opt[List[str]] = None) -> int: parsed_args, unknown_args = self.args_parser.parse_known_args(argv) for trace in parsed_args.trace: print("Trace {} is activated".format(trace)) Log.enable(trace) Diagnostics.set_style(parsed_args.diagnostic_style) if parsed_args.profile: import cProfile import pstats pr = cProfile.Profile() pr.enable() # Set the verbosity self.verbosity = parsed_args.verbosity self.enable_build_warnings = getattr(parsed_args, "enable_build_warnings", False) # If there is no build_mode (ie. we're not running a command that # requires it), we still need one to call gnatpp, so set it to a dummy # build mode. self.build_mode = getattr(parsed_args, "build_mode", self.BUILD_MODES[0]) self.no_ada_api = parsed_args.no_ada_api # If asked to, setup the exception hook as a last-chance handler to # invoke a debugger in case of uncaught exception. if parsed_args.debug: # Try to use IPython's debugger if it is available, otherwise # fallback to PDB. try: # noinspection PyPackageRequirements from IPython.core import ultratb except ImportError: def excepthook(typ: Type[BaseException], value: BaseException, tb: TracebackType) -> Any: traceback.print_exception(typ, value, tb) pdb.post_mortem(tb) sys.excepthook = excepthook else: sys.excepthook = ultratb.FormattedTB(mode='Verbose', color_scheme='Linux', call_pdb=1) self.dirs.set_build_dir(parsed_args.build_dir) install_dir = getattr(parsed_args, 'install-dir', None) if install_dir: self.dirs.set_install_dir(install_dir) if getattr(parsed_args, 'list_warnings', False): WarningSet.print_list() return 0 # noinspection PyBroadException try: parsed_args.func(parsed_args, unknown_args) return 0 except DiagnosticError: if parsed_args.debug: raise if parsed_args.verbosity.debug or parsed_args.full_error_traces: traceback.print_exc() print(col('Errors, exiting', Colors.FAIL)) return 1 except Exception as e: if parsed_args.debug: raise ex_type, ex, tb = sys.exc_info() # If we have a syntax error, we know for sure the last stack frame # points to the code that must be fixed. Otherwise, point to the # top-most stack frame that does not belong to Langkit. if e.args and e.args[0] == 'invalid syntax': assert isinstance(e, SyntaxError) loc = Location(cast(str, e.filename), cast(int, e.lineno)) else: loc = cast(Location, extract_library_location(traceback.extract_tb(tb))) with diagnostic_context(loc): check_source_language(False, str(e), do_raise=False) # Keep Langkit bug "pretty" for users: display the Python stack # trace only when requested. if parsed_args.verbosity.debug or parsed_args.full_error_traces: traceback.print_exc() print(col('Internal error! Exiting', Colors.FAIL)) return 1 finally: if parsed_args.profile: pr.disable() ps = pstats.Stats(pr) ps.dump_stats('langkit.prof')