-
-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Register matcher for Nim style comments (#157) * Implement initial support for finding single line and multiline comments (#157) * Add files for testing (#157) * Rework depth calculation (#157) In particular, trigger end of multiline whenever m.depth == 0 * Remove extra test case (#157) * Corrected single line matching pattern (#157) * Tests now pass (#157) * Register all file extensions (#157) * Add Nim to README (#157) * Finish adding support for Nim comments (#157)
- Loading branch information
1 parent
818469f
commit d24d39d
Showing
7 changed files
with
263 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package nim | ||
|
||
import ( | ||
"github.com/preslavmihaylov/todocheck/matchers/state" | ||
) | ||
|
||
func NewCommentMatcher(callback state.CommentCallback) *CommentMatcher { | ||
return &CommentMatcher{ | ||
callback: callback, | ||
depth: 0, | ||
} | ||
} | ||
|
||
type CommentMatcher struct { | ||
callback state.CommentCallback | ||
buffer string | ||
lines []string | ||
lineCount int | ||
stringToken rune | ||
depth int | ||
} | ||
|
||
func (m *CommentMatcher) NonCommentState( | ||
filename, | ||
line string, | ||
lineCount int, | ||
prevToken, currToken, nextToken rune, | ||
) (state.CommentState, error) { | ||
if isSingleLineOpener(currToken, nextToken) { | ||
m.buffer += string(currToken) | ||
return state.SingleLineComment, nil | ||
} else if isMultiLineOpener(currToken, nextToken) { | ||
m.buffer += string(currToken) | ||
m.lines = []string{line} | ||
m.lineCount = lineCount | ||
m.depth += 1 | ||
return state.MultiLineComment, nil | ||
} else if currToken == '"' || currToken == '\'' || currToken == '`' { | ||
m.stringToken = currToken | ||
return state.String, nil | ||
} else { | ||
return state.NonComment, nil | ||
} | ||
} | ||
|
||
func (m *CommentMatcher) MultiLineCommentState( | ||
filename, line string, linecnt int, prevToken, currToken, nextToken rune, | ||
) (state.CommentState, error) { | ||
m.buffer += string(currToken) | ||
if isMultiLineOpener(currToken, nextToken) { | ||
// Capture nested comments | ||
m.depth += 1 | ||
} else if isMultiLineCloser(currToken, nextToken) { | ||
m.depth -= 1 | ||
} | ||
|
||
if m.depth == 0 { | ||
err := m.callback(m.buffer, filename, m.lines, m.lineCount) | ||
if err != nil { | ||
return state.NonComment, err | ||
} | ||
|
||
m.reset() | ||
return state.NonComment, nil | ||
} | ||
|
||
if prevToken == '\n' { | ||
m.lines = append(m.lines, line) | ||
} | ||
|
||
return state.MultiLineComment, nil | ||
} | ||
|
||
func (m *CommentMatcher) SingleLineCommentState( | ||
filename, line string, linecnt int, prevToken, currToken, nextToken rune, | ||
) (state.CommentState, error) { | ||
if currToken == '\n' { | ||
// Reach end of line i.e. end of comment | ||
err := m.callback(m.buffer, filename, []string{line}, linecnt) | ||
if err != nil { | ||
return state.NonComment, err | ||
} | ||
|
||
m.reset() | ||
return state.NonComment, nil | ||
} | ||
|
||
m.buffer += string(currToken) | ||
return state.SingleLineComment, nil | ||
} | ||
|
||
// StringState for standard comments | ||
func (m *CommentMatcher) StringState( | ||
filename, line string, linecnt int, prevToken, currToken, nextToken rune, | ||
) (state.CommentState, error) { | ||
if prevToken != '\\' && currToken == m.stringToken { | ||
return state.NonComment, nil | ||
} | ||
|
||
return state.String, nil | ||
} | ||
|
||
func isSingleLineOpener(currToken, nextToken rune) bool { | ||
return currToken == '#' && nextToken != '[' | ||
} | ||
|
||
func isMultiLineOpener(currToken, nextToken rune) bool { | ||
return currToken == '#' && nextToken == '[' | ||
} | ||
|
||
func isMultiLineCloser(currToken, nextToken rune) bool { | ||
return currToken == ']' && nextToken == '#' | ||
} | ||
|
||
func (m *CommentMatcher) reset() { | ||
m.buffer = "" | ||
m.lines = nil | ||
m.lineCount = 0 | ||
m.stringToken = 0 | ||
m.depth = 0 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Package scripts contains a todo matcher & comments matcher for Nim. | ||
// Source files contain # for single-line comments, and nestable #[ ]# multiline comments | ||
package nim |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package nim | ||
|
||
import ( | ||
"regexp" | ||
|
||
"github.com/preslavmihaylov/todocheck/common" | ||
"github.com/preslavmihaylov/todocheck/matchers/errors" | ||
) | ||
|
||
// NewTodoMatcher for Nim comments | ||
func NewTodoMatcher(todos []string) *TodoMatcher { | ||
pattern := common.ArrayAsRegexAnyMatchExpression(todos) | ||
|
||
// Single line | ||
singleLineTodoPattern := regexp.MustCompile(`^\s*#[^\[].*` + pattern) | ||
singleLineValidTodoPattern := regexp.MustCompile(`^\s*#[^\[]` + pattern + ` (#?[a-zA-Z0-9\-]+):.*`) | ||
|
||
// Multiline line | ||
multiLineTodoPattern := regexp.MustCompile(`(?s)^\s*(#\[).*` + pattern) | ||
multiLineValidTodoPattern := regexp.MustCompile(`(?s)^\s*(#\[).*` + pattern + ` (#?[a-zA-Z0-9\-]+):.*`) | ||
|
||
return &TodoMatcher{ | ||
singleLineTodoPattern: singleLineTodoPattern, | ||
singleLineValidTodoPattern: singleLineValidTodoPattern, | ||
multiLineTodoPattern: multiLineTodoPattern, | ||
multiLineValidTodoPattern: multiLineValidTodoPattern, | ||
} | ||
} | ||
|
||
// TodoMatcher for Nim comments | ||
type TodoMatcher struct { | ||
singleLineTodoPattern *regexp.Regexp | ||
singleLineValidTodoPattern *regexp.Regexp | ||
multiLineTodoPattern *regexp.Regexp | ||
multiLineValidTodoPattern *regexp.Regexp | ||
} | ||
|
||
// IsMatch checks if the current expression matches a Nim comment | ||
func (m *TodoMatcher) IsMatch(expr string) bool { | ||
return m.singleLineTodoPattern.Match([]byte(expr)) || m.multiLineTodoPattern.Match([]byte(expr)) | ||
} | ||
|
||
// IsValid checks if the expression is a valid todo comment | ||
func (m *TodoMatcher) IsValid(expr string) bool { | ||
return m.singleLineValidTodoPattern.Match([]byte(expr)) || m.multiLineValidTodoPattern.Match([]byte(expr)) | ||
} | ||
|
||
// ExtractIssueRef from the given expression. | ||
// If the expression is invalid, an ErrInvalidTODO is returned | ||
func (m *TodoMatcher) ExtractIssueRef(expr string) (string, error) { | ||
if !m.IsValid(expr) { | ||
return "", errors.ErrInvalidTODO | ||
} | ||
|
||
singleLineRes := m.singleLineValidTodoPattern.FindStringSubmatch(expr) | ||
multiLineRes := m.multiLineValidTodoPattern.FindStringSubmatch(expr) | ||
if len(singleLineRes) >= 2 { | ||
return singleLineRes[1], nil | ||
} else if len(multiLineRes) >= 3 { | ||
return multiLineRes[2], nil | ||
} | ||
|
||
panic("Invariant violated. No issue reference found in valid TODO") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# This is a single-line malformed TODO | ||
|
||
# TODO 1: This is a valid todo comment | ||
|
||
when isMainModule: | ||
# TODO 234: Invalid todo, with a closed issue | ||
discard "Hello World" | ||
|
||
#[ TODO 2: Another valid todo ]# | ||
|
||
discard "Magic here, magic there!" | ||
#[ | ||
#[ TODO 3: There is also a valid nested todo here! ]# | ||
]# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters