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

feat: add to allow use comments in other scopes that is not from a function #454

Merged
merged 4 commits into from
Nov 20, 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
2 changes: 1 addition & 1 deletion norminette/norm_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
"BRACE_NEWLINE": "Expected newline before brace",
"EXP_NEWLINE": "Expected newline after control structure",
"ARG_TYPE_UKN": "Unrecognized variable type",
"COMMENT_ON_INSTR": "Comment must be on its own line",
"COMMENT_ON_INSTR": "Comment must be on its own line or at end of a line",
"COMMA_START_LINE": "Comma at line start",
"MIXED_SPACE_TAB": "Mixed spaces and tabs",
"ATTR_EOL": "Function attribute must be at the end of line",
Expand Down
72 changes: 47 additions & 25 deletions norminette/rules/check_comment.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
from norminette.rules import Rule

allowed_on_comment = ["COMMENT", "MULT_COMMENT", "SPACE", "TAB"]


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

def run(self, context):
"""
Comments are only allowed in GlobalScope.
Comments are forbidden inside functions and in the middle of instructions.
"""
i = context.skip_ws(0)
has_comment = False
while (
context.peek_token(i) is not None
and context.check_token(i, "NEWLINE") is False
):
if context.check_token(i, allowed_on_comment) is False:
if has_comment is True:
context.new_error("COMMENT_ON_INSTR", context.peek_token(i))
return True, i
elif context.check_token(i, ["COMMENT", "MULT_COMMENT"]) is True:
if (
context.scope.name != "GlobalScope"
or context.history[-1] == "IsFuncDeclaration"
):
context.new_error("WRONG_SCOPE_COMMENT", context.peek_token(i))
has_comment = True

tokens = []
while context.peek_token(i) and not context.check_token(i, "NEWLINE"):
token = context.peek_token(i)
tokens.append(token)
i += 1
i = context.skip_ws(0)
return False, 0

for index, token in enumerate(tokens):
if token.type in ("COMMENT", "MULT_COMMENT"):
if self.is_inside_a_function(context):
context.new_error("WRONG_SCOPE_COMMENT", token)
if index == 0 or self.is_last_token(token, tokens[index+1:]):
continue
context.new_error("COMMENT_ON_INSTR", token)

def is_inside_a_function(self, context):
if context.history[-2:] == ["IsFuncDeclaration", "IsBlockStart"]:
return True
if context.scope.__class__.__name__.lower() == "function":
return True
# Sometimes the context scope is a `ControlStructure` scope instead of
# `Function` scope, so, to outsmart this bug, we need check manually
# the `context.history`.
last = None
for index, record in enumerate(reversed(context.history)):
if record == "IsFuncDeclaration" and last == "IsBlockStart":
# Since the limited history API, we can't say if we're in a
# nested function to reach the first enclosing function, so,
# we'll consider that the user just declared a normal function
# in global scope.
stack = 1
index -= 1 # Jumps to next record after `IsBlockStart`
while index > 0 and stack > 0:
record = context.history[-index]
index -= 1
if record not in ("IsBlockStart", "IsBlockEnd"):
continue
stack = stack + (1, -1)[record == "IsBlockEnd"]
return bool(stack)
last = record
return False

def is_last_token(self, token, foward):
expected = ("SPACE", "TAB")
if token.type == "MULT_COMMENT":
expected += ("COMMENT", "MULT_COMMENT")
return all(it.type in ("SPACE", "TAB", "COMMENT", "MULT_COMMENT") for it in foward)
2 changes: 1 addition & 1 deletion norminette/rules/check_func_arguments_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def check_arg_format(self, context, pos):
p = 0
stop = ["COMMA", "RPARENTHESIS"]
if context.check_token(i, ["COMMENT", "MULT_COMMENT"]):
context.new_error("WRONG_SCOPE_COMMENT", context.peek_token(i))
# context.new_error("WRONG_SCOPE_COMMENT", context.peek_token(i))
i += 1
# if context.check_token(i, "NEWLINE"):
# context.new_error("NEWLINE_IN_DECL", context.peek_token(i))
Expand Down
21 changes: 21 additions & 0 deletions tests/rules/samples/test_comments.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
struct {
// points is to something
int points; // is an int :D
};

typedef /* oopss */ bool bool;

enum test {
// blaboe
hello, // it works
/* error*/ error
};

void hello(/* nothing */ void) // error because comment is in middle of the line
{
// error because scope is from a function
{
// are you trying to cheat?
// error because scope is from a function
}
}
75 changes: 75 additions & 0 deletions tests/rules/samples/test_comments.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
test_comments.c - IsUserDefinedType In "GlobalScope" from "None" line 1":
<STRUCT> <SPACE> <LBRACE> <NEWLINE>
test_comments.c - IsComment In "UserDefinedType" from "GlobalScope" line 2":
<TAB> <COMMENT=// points is to something> <NEWLINE>
test_comments.c - IsVarDeclaration In "UserDefinedType" from "GlobalScope" line 3":
<TAB> <INT> <TAB> <IDENTIFIER=points> <SEMI_COLON> <SPACE>
test_comments.c - IsComment In "UserDefinedType" from "GlobalScope" line 3":
<COMMENT=// is an int :D> <NEWLINE>
test_comments.c - IsBlockEnd In "UserDefinedType" from "GlobalScope" line 4":
<RBRACE> <SEMI_COLON> <NEWLINE>
test_comments.c - IsEmptyLine In "GlobalScope" from "None" line 5":
<NEWLINE>
test_comments.c - IsUserDefinedType In "GlobalScope" from "None" line 6":
<TYPEDEF> <SPACE> <MULT_COMMENT=/* oopss */> <SPACE> <IDENTIFIER=bool> <SPACE> <IDENTIFIER=bool> <SEMI_COLON> <NEWLINE>
test_comments.c - IsEmptyLine In "GlobalScope" from "None" line 7":
<NEWLINE>
test_comments.c - IsUserDefinedType In "GlobalScope" from "None" line 8":
<ENUM> <SPACE> <IDENTIFIER=test> <SPACE> <LBRACE> <NEWLINE>
test_comments.c - IsComment In "UserDefinedEnum" from "GlobalScope" line 9":
<SPACE> <SPACE> <SPACE> <SPACE> <COMMENT=// blaboe> <NEWLINE>
test_comments.c - IsEnumVarDecl In "UserDefinedEnum" from "GlobalScope" line 10":
<SPACE> <SPACE> <SPACE> <SPACE> <IDENTIFIER=hello> <COMMA> <SPACE> <SPACE>
test_comments.c - IsComment In "UserDefinedEnum" from "GlobalScope" line 10":
<COMMENT=// it works> <NEWLINE>
test_comments.c - IsComment In "UserDefinedEnum" from "GlobalScope" line 11":
<SPACE> <SPACE> <SPACE> <SPACE> <MULT_COMMENT=/* error*/> <SPACE>
test_comments.c - IsEnumVarDecl In "UserDefinedEnum" from "GlobalScope" line 11":
<IDENTIFIER=error> <NEWLINE>
test_comments.c - IsBlockEnd In "UserDefinedEnum" from "GlobalScope" line 12":
<RBRACE> <SEMI_COLON> <NEWLINE>
test_comments.c - IsEmptyLine In "GlobalScope" from "None" line 13":
<NEWLINE>
test_comments.c - IsFuncDeclaration In "GlobalScope" from "None" line 14":
<VOID> <SPACE> <IDENTIFIER=hello> <LPARENTHESIS> <MULT_COMMENT=/* nothing */> <SPACE> <VOID> <RPARENTHESIS> <SPACE> <COMMENT=// error because comment is in middle of the line> <NEWLINE>
test_comments.c - IsBlockStart In "Function" from "GlobalScope" line 15":
<LBRACE> <NEWLINE>
test_comments.c - IsComment In "Function" from "GlobalScope" line 16":
<SPACE> <SPACE> <SPACE> <COMMENT=// error because scope is from a function> <NEWLINE>
test_comments.c - IsBlockStart In "Function" from "GlobalScope" line 17":
<SPACE> <SPACE> <SPACE> <LBRACE> <NEWLINE>
test_comments.c - IsComment In "ControlStructure" from "Function" line 18":
<SPACE> <SPACE> <SPACE> <SPACE> <SPACE> <SPACE> <COMMENT=// are you trying to cheat?> <NEWLINE>
test_comments.c - IsComment In "ControlStructure" from "Function" line 19":
<SPACE> <SPACE> <SPACE> <SPACE> <SPACE> <SPACE> <COMMENT=// error because scope is from a function> <NEWLINE>
test_comments.c - IsBlockEnd In "ControlStructure" from "Function" line 20":
<SPACE> <SPACE> <SPACE> <RBRACE> <NEWLINE>
test_comments.c - IsBlockEnd In "Function" from "GlobalScope" line 21":
<RBRACE> <NEWLINE>
test_comments.c: Error!
Error: INVALID_HEADER (line: 1, col: 1): Missing or invalid 42 header
Error: BRACE_NEWLINE (line: 1, col: 8): Expected newline before brace
Error: COMMENT_ON_INSTR (line: 6, col: 9): Comment must be on its own line or at end of a line
Error: SPACE_REPLACE_TAB (line: 6, col: 25): Found space when expecting tab
Error: USER_DEFINED_TYPEDEF (line: 6, col: 26): User defined typedef must start with t_
Error: ENUM_TYPE_NAMING (line: 8, col: 6): Enum name must start with e_
Error: BRACE_NEWLINE (line: 8, col: 11): Expected newline before brace
Error: SPACE_EMPTY_LINE (line: 9, col: 5): Space on empty line
Error: TOO_FEW_TAB (line: 10, col: 1): Missing tabs for indent level
Error: SPACE_REPLACE_TAB (line: 10, col: 5): Found space when expecting tab
Error: CONSECUTIVE_SPC (line: 10, col: 11): Two or more consecutives spaces
Error: SPACE_REPLACE_TAB (line: 11, col: 5): Found space when expecting tab
Error: TOO_FEW_TAB (line: 11, col: 16): Missing tabs for indent level
Error: SPACE_BEFORE_FUNC (line: 14, col: 5): space before function name
Error: COMMENT_ON_INSTR (line: 14, col: 12): Comment must be on its own line or at end of a line
Error: MISSING_IDENTIFIER (line: 14, col: 25): missing type qualifier or identifier in function arguments
Error: SPACE_EMPTY_LINE (line: 16, col: 4): Space on empty line
Error: WRONG_SCOPE_COMMENT (line: 16, col: 4): Comment is invalid in this scope
Error: TOO_FEW_TAB (line: 17, col: 1): Missing tabs for indent level
Error: SPACE_EMPTY_LINE (line: 17, col: 4): Space on empty line
Error: SPACE_EMPTY_LINE (line: 18, col: 7): Space on empty line
Error: WRONG_SCOPE_COMMENT (line: 18, col: 7): Comment is invalid in this scope
Error: SPACE_EMPTY_LINE (line: 19, col: 7): Space on empty line
Error: WRONG_SCOPE_COMMENT (line: 19, col: 7): Comment is invalid in this scope
Error: TOO_FEW_TAB (line: 20, col: 1): Missing tabs for indent level
Error: SPACE_EMPTY_LINE (line: 20, col: 4): Space on empty line
10 changes: 5 additions & 5 deletions tests/rules/samples/test_file_1019.out
Original file line number Diff line number Diff line change
Expand Up @@ -164,20 +164,20 @@ test_file_1019.c: Error!
Error: INVALID_HEADER (line: 1, col: 1): Missing or invalid 42 header
Error: RETURN_PARENTHESIS (line: 8, col: 12): Return value must be in parenthesis
Error: FORBIDDEN_CHAR_NAME (line: 28, col: 9): user defined identifiers should contain only lowercase characters, digits or '_'
Error: COMMENT_ON_INSTR (line: 35, col: 25): Comment must be on its own line
Error: COMMENT_ON_INSTR (line: 35, col: 6): Comment must be on its own line or at end of a line
Error: COMMENT_ON_INSTR (line: 41, col: 10): Comment must be on its own line or at end of a line
Error: WRONG_SCOPE_COMMENT (line: 41, col: 10): Comment is invalid in this scope
Error: COMMENT_ON_INSTR (line: 41, col: 29): Comment must be on its own line
Error: COMMENT_ON_INSTR (line: 42, col: 10): Comment must be on its own line or at end of a line
Error: WRONG_SCOPE_COMMENT (line: 42, col: 10): Comment is invalid in this scope
Error: COMMENT_ON_INSTR (line: 42, col: 29): Comment must be on its own line
Error: TOO_MANY_FUNCS (line: 46, col: 1): Too many functions in file
Error: GOTO_FBIDDEN (line: 50, col: 1): Goto statements are forbidden
Error: LABEL_FBIDDEN (line: 52, col: 1): Label statements are forbidden
Error: TOO_MANY_FUNCS (line: 56, col: 1): Too many functions in file
Error: COMMENT_ON_INSTR (line: 62, col: 27): Comment must be on its own line or at end of a line
Error: WRONG_SCOPE_COMMENT (line: 62, col: 27): Comment is invalid in this scope
Error: COMMENT_ON_INSTR (line: 62, col: 47): Comment must be on its own line
Error: TOO_MANY_FUNCS (line: 66, col: 1): Too many functions in file
Error: COMMENT_ON_INSTR (line: 70, col: 14): Comment must be on its own line or at end of a line
Error: WRONG_SCOPE_COMMENT (line: 70, col: 14): Comment is invalid in this scope
Error: COMMENT_ON_INSTR (line: 70, col: 32): Comment must be on its own line
Error: TOO_MANY_FUNCS (line: 73, col: 1): Too many functions in file
Error: SPC_BEFORE_NL (line: 73, col: 17): Space before newline
Error: TOO_MANY_FUNCS (line: 78, col: 1): Too many functions in file
Expand Down
1 change: 0 additions & 1 deletion tests/rules/samples/test_file_210128.out
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
<RBRACE> <NEWLINE>
test_file_210128.c: Error!
Error: INVALID_HEADER (line: 1, col: 1): Missing or invalid 42 header
Error: WRONG_SCOPE_COMMENT (line: 1, col: 15): Comment is invalid in this scope
Error: WRONG_SCOPE_COMMENT (line: 5, col: 14): Comment is invalid in this scope
Error: WRONG_SCOPE_COMMENT (line: 5, col: 14): Comment is invalid in this scope
Error: WRONG_SCOPE_COMMENT (line: 5, col: 63): Comment is invalid in this scope
Expand Down
Loading