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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 29 additions & 30 deletions norminette/registry.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import collections
from functools import cmp_to_key
from operator import attrgetter

import norminette.rules as rules
from norminette.rules import Rules, Primary
from norminette.exceptions import CParsingError

rules = Rules()


def sort_errs(a, b):
if a.col == b.col and a.line == b.line:
Expand All @@ -14,37 +18,25 @@ class Registry:
global has_err

def __init__(self):
self.rules = rules.rules
self.primary_rules = rules.primary_rules
self.dependencies = {}
for k, r in self.rules.items():
r.register(self)
for k, v in self.dependencies.items():
self.dependencies[k] = sorted(self.dependencies[k], reverse=True)
self.dependencies = collections.defaultdict(list)
for rule in rules.checks:
rule.register(self)
for name, dependencies in self.dependencies.items():
self.dependencies[name] = sorted(dependencies, reverse=True, key=attrgetter("__name__"))

def run_rules(self, context, rule):
if rule.name.startswith("Is"):
ret, read = rule.run(context)
else:
# print (rule.name)
ret = False
read = 0
rule.run(context)
# print(context.history, context.tokens[:5], rule)
# if rule.name.startswith("Is"):
# print (rule.name, ret)
if ret is True:
rule = rule(context)
result = rule.run(context)
ret, read = result if isinstance(rule, Primary) else (False, 0)
if ret:
context.scope.instructions += 1
if rule.name.startswith("Is"):
# print ("Line", context.tokens[0].pos[0], rule.name)
if isinstance(rule, Primary):
context.tkn_scope = read
context.history.append(rule.name)
for r in self.dependencies.get(rule.name, []):
self.run_rules(context, self.rules[r])
if "all" in self.dependencies:
for r in self.dependencies["all"]:
self.run_rules(context, self.rules[r])
# context.history.pop(-1)
context.history.append(rule)
for rule in self.dependencies[rule.name]:
self.run_rules(context, rule)
for rule in self.dependencies["_rule"]:
self.run_rules(context, rule)
context.tkn_scope = 0
return ret, read

Expand All @@ -57,10 +49,14 @@ def run(self, context, source):
dependencies
"""
unrecognized_tkns = []
context.state = "starting"
for rule in self.dependencies["_start"]:
self.run_rules(context, rule)
context.state = "running"
while context.tokens != []:
context.tkn_scope = len(context.tokens)
for rule in self.primary_rules:
if type(context.scope) not in rule.scope and rule.scope != []:
for rule in rules.primaries:
if rule.scope and context.scope not in rule.scope:
continue
ret, jump = self.run_rules(context, rule)
if ret is True:
Expand All @@ -82,6 +78,9 @@ def run(self, context, source):
unrecognized_tkns.append(context.tokens[0])
context.pop_tokens(1) # ##################################
# #############################################################
context.state = "ending"
for rule in self.dependencies["_end"]:
self.run_rules(context, rule)
if unrecognized_tkns != []:
print(context.debug)
if context.debug > 0:
Expand Down
48 changes: 21 additions & 27 deletions norminette/rules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
__all__ = (
"rules",
"primary_rules",
"Rule",
"PrimaryRule",
)

import operator
import itertools
import importlib
import os
from operator import attrgetter

from norminette.rules.rule import PrimaryRule
from norminette.rules.rule import Rule


def partition(predicate, iterable):
it1, it2 = itertools.tee(iterable)
return itertools.filterfalse(predicate, it1), filter(predicate, it2)

from norminette.rules.rule import Rule, Primary, Check

path = os.path.dirname(os.path.realpath(__file__))

for f in os.listdir(path):
name, _ = os.path.splitext(f)
importlib.import_module("norminette.rules." + name)
class Rules:
__slots__ = (
"all",
"primaries",
"checks",
)

_all_rules = Rule.__subclasses__()[1:] + PrimaryRule.__subclasses__()
_all_rules = map(type.__call__, _all_rules) # In 3.11^ we can just use `operator.call``
__instance = None

_is_primary_rule = operator.attrgetter("primary")
_rules, _primary_rules = partition(_is_primary_rule, _all_rules)
def __new__(cls):
if not cls.__instance:
cls.__instance = super().__new__(cls)
return cls.__instance

rules = {rule.__class__.__name__: rule for rule in _rules}
def __init__(self) -> None:
path = os.path.dirname(os.path.realpath(__file__))
for f in os.listdir(path):
name, _ = os.path.splitext(f)
importlib.import_module("norminette.rules." + name)

primary_rules = sorted(_primary_rules, reverse=True, key=operator.attrgetter("priority"))
self.all = Rule.__subclasses__()
self.checks = Check.__subclasses__()
self.primaries = sorted(Primary.__subclasses__(), reverse=True, key=attrgetter("priority"))
10 changes: 5 additions & 5 deletions norminette/rules/check_assignation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check

assigns = [
"RIGHT_ASSIGN",
Expand All @@ -17,10 +17,10 @@
special_assigns = ["INC", "DEC"]


class CheckAssignation(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsAssignation"]
class CheckAssignation(Rule, Check):
depends_on = (
"IsAssignation",
)

def check_brace_assign(self, context, i):
i += 1
Expand Down
18 changes: 8 additions & 10 deletions norminette/rules/check_assignation_indent.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check
from norminette.exceptions import CParsingError


Expand Down Expand Up @@ -42,15 +42,13 @@
nest_kw = ["RPARENTHESIS", "LPARENTHESIS", "NEWLINE"]


class CheckAssignationIndent(Rule):
def __init__(self):
super().__init__()
self.depends_on = [
"IsAssignation",
"IsFuncPrototype",
"IsFunctionCall",
"IsVarDeclaration",
]
class CheckAssignationIndent(Rule, Check):
depends_on = (
"IsAssignation",
"IsFuncPrototype",
"IsFunctionCall",
"IsVarDeclaration",
)

def run(self, context):
"""
Expand Down
10 changes: 5 additions & 5 deletions norminette/rules/check_block_start.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check
from norminette.scope import GlobalScope, ControlStructure


class CheckBlockStart(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsBlockStart"]
class CheckBlockStart(Rule, Check):
depends_on = (
"IsBlockStart",
)

def run(self, context):
"""
Expand Down
11 changes: 6 additions & 5 deletions norminette/rules/check_brace.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


class CheckBrace(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsBlockStart", "IsBlockEnd"]
class CheckBrace(Rule, Check):
depends_on = (
"IsBlockStart",
"IsBlockEnd",
)

def run(self, context):
"""
Expand Down
4 changes: 2 additions & 2 deletions norminette/rules/check_comment.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


class CheckComment(Rule):
class CheckComment(Rule, Check):
def run(self, context):
"""
Comments are forbidden inside functions and in the middle of instructions.
Expand Down
10 changes: 5 additions & 5 deletions norminette/rules/check_comment_line_len.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


class CheckCommentLineLen(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsComment"]
class CheckCommentLineLen(Rule, Check):
depends_on = (
"IsComment",
)

def run(self, context):
"""
Expand Down
10 changes: 5 additions & 5 deletions norminette/rules/check_control_statement.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


forbidden_cs = ["FOR", "SWITCH", "CASE", "GOTO"]
Expand All @@ -17,10 +17,10 @@
]


class CheckControlStatement(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsControlStatement"]
class CheckControlStatement(Rule, Check):
depends_on = (
"IsControlStatement",
)

def check_nest(self, context, i):
depth = 1
Expand Down
10 changes: 5 additions & 5 deletions norminette/rules/check_declaration.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


class CheckDeclaration(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsDeclaration"]
class CheckDeclaration(Rule, Check):
depends_on = (
"IsDeclaration",
)

def run(self, context):
"""
Expand Down
8 changes: 2 additions & 6 deletions norminette/rules/check_empty_line.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


class CheckEmptyLine(Rule):
def __init__(self):
super().__init__()
self.depends_on = []

class CheckEmptyLine(Rule, Check):
def run(self, context):
"""
Empty line must not contains tabs or spaces
Expand Down
10 changes: 5 additions & 5 deletions norminette/rules/check_enum_var_decl.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check


class CheckEnumVarDecl(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsEnumVarDecl"]
class CheckEnumVarDecl(Rule, Check):
depends_on = (
"IsEnumVarDecl",
)

def run(self, context):
"""
Expand Down
20 changes: 9 additions & 11 deletions norminette/rules/check_expression_statement.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check

kw = [
# C reserved keywords #
Expand Down Expand Up @@ -36,16 +36,14 @@
]


class CheckExpressionStatement(Rule):
def __init__(self):
super().__init__()
self.depends_on = [
"IsExpressionStatement",
"IsControlStatement",
"IsFunctionCall",
"IsAssignation",
"IsCast",
]
class CheckExpressionStatement(Rule, Check):
depends_on = (
"IsExpressionStatement",
"IsControlStatement",
"IsFunctionCall",
"IsAssignation",
"IsCast",
)

def run(self, context):
"""
Expand Down
11 changes: 6 additions & 5 deletions norminette/rules/check_func_arguments_name.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from norminette.rules import Rule
from norminette.rules import Rule, Check

type_specifiers = ["CHAR", "DOUBLE", "ENUM", "FLOAT", "INT", "UNION", "VOID", "SHORT"]

Expand All @@ -13,10 +13,11 @@
arg_separator = ["COMMA", "CLOSING_PARENTHESIS"]


class CheckFuncArgumentsName(Rule):
def __init__(self):
super().__init__()
self.depends_on = ["IsFuncDeclaration", "IsFuncPrototype"]
class CheckFuncArgumentsName(Rule, Check):
depends_on = (
"IsFuncDeclaration",
"IsFuncPrototype",
)

def check_arg_format(self, context, pos):
"""
Expand Down
Loading
Loading