Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Rule classes to be able add a rich context.history in Rules #457

Merged
merged 3 commits into from
Nov 22, 2023

Conversation

NiumXp
Copy link
Contributor

@NiumXp NiumXp commented Nov 20, 2023

Although norminette only does lexical analysis, we are not able to do syntax analysis that does not force a stop in norminette, we can use is_preprocessor_statement.py as a good example of this, we raise a lot of CParsingError when something is not syntactically correct instead of marking the pre-processor statement as "bad" or "malformed" and creating an error with new_error to report this error.

To add "rich" information in context.history I store instances of Rules instead of their names inside it. If in IsComment primary rule we store the COMMENT and MULT_COMMENT tokens in their instance, we can get the 42 header source with something like this:

def run(self, context):
    _header_lines = 11
    for index, record in enumerate(context.history):
        if record != "IsComment":
            continue
        records = record.history[index:index+_header_lines]
        if not all(it == "IsComment" for it in records):
            continue
        comments = tuple(it.comment for it in records)
        if not all(it.type == "MULT_COMMENT" for it in comments):
            continue
        header = '\n'.join(it.value for it in comments)
        if not self.is_valid_header(header):
            context.new_error("MISSING_HEADER", comments[0])
        elif index != 0:  # Header is not on top of file
            context.new_error("NOTONTOP_HEADER", comments[0])

Storing the comments tokens in history, we are able to say if the header is or not in top of file, if header is missing or if is header invalid in an easier way.

Some rules need to be run only once, like CheckHeader, CheckLineCount, CheckLineLen, CheckSpacing, etc. and to its case, I added a way to be able run a Check rule before and after Registry.run_rules. An example of CheckLineLen now:

from norminette.rules import Rule, Check


class CheckLineLen(Rule, Check):
    runs_on_rule = False  # Avoid run after an `Is*` rule
    runs_on_start = True

    def run(self, context):
        lines = context.file.source.splitlines()
        for lineno, line in enumerate(lines, start=1):
            if len(line) > 81:
                context.new_error("LINE_TOO_LONG", (lineno, 80))

This PR is just a step to improve norminette to be able fix errors like in #394 and #419. I want to make others improves like add more information in Token class to be able show better error messages in unexpected exceptions (reported in #411), improve context.tokens to be able add some helpers like skip_type_specifier, skip_expression, etc. to be easy fix problems like in #441.

@matthieu42Network matthieu42Network merged commit 8b11426 into 42School:master Nov 22, 2023
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants