diff options
-rw-r--r-- | cmd2/parsing.py | 18 | ||||
-rw-r--r-- | tests/test_parsing.py | 22 |
2 files changed, 26 insertions, 14 deletions
diff --git a/cmd2/parsing.py b/cmd2/parsing.py index 84c7e27a..ddfd5f0d 100644 --- a/cmd2/parsing.py +++ b/cmd2/parsing.py @@ -121,25 +121,23 @@ class StatementParser: # double or single quotes. # # this big regular expression can be broken down into 3 regular - # expressions that are OR'ed together. + # expressions that are OR'ed together with a pipe character # - # /\*.*?(\*/|$) matches C-style comments, with an optional - # closing '*/'. The optional closing '*/' is - # there to retain backward compatibility with - # the pyparsing implementation of cmd2 < 0.9.0 - # \'(?:\\.|[^\\\'])*\' matches a single quoted string, allowing + # /\*.*\*/ Matches C-style comments (i.e. /* comment */) + # does not match unclosed comments. + # \'(?:\\.|[^\\\'])*\' Matches a single quoted string, allowing # for embedded backslash escaped single quote - # marks - # "(?:\\.|[^\\"])*" matches a double quoted string, allowing + # marks. + # "(?:\\.|[^\\"])*" Matches a double quoted string, allowing # for embedded backslash escaped double quote - # marks + # marks. # # by way of reminder the (?:...) regular expression syntax is just # a non-capturing version of regular parenthesis. We need the non- # capturing syntax because _comment_replacer() looks at match # groups self.comment_pattern = re.compile( - r'/\*.*?(\*/|$)|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + r'/\*.*\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE ) diff --git a/tests/test_parsing.py b/tests/test_parsing.py index 59f9a610..5dc78745 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -142,6 +142,20 @@ def test_parse_c_comment_empty(parser): assert not statement.pipe_to assert not statement.argv +def test_parse_c_comment_no_closing(parser): + statement = parser.parse('cat /tmp/*.txt') + assert statement.command == 'cat' + assert statement.args == '/tmp/*.txt' + assert not statement.pipe_to + assert statement.argv == ['cat', '/tmp/*.txt'] + +def test_parse_c_comment_multiple_opening(parser): + statement = parser.parse('cat /tmp/*.txt /tmp/*.cfg') + assert statement.command == 'cat' + assert statement.args == '/tmp/*.txt /tmp/*.cfg' + assert not statement.pipe_to + assert statement.argv == ['cat', '/tmp/*.txt', '/tmp/*.cfg'] + def test_parse_what_if_quoted_strings_seem_to_start_comments(parser): statement = parser.parse('what if "quoted strings /* seem to " start comments?') assert statement.command == 'what' @@ -292,13 +306,13 @@ def test_parse_multiline_command_ignores_redirectors_within_it(parser, line, ter def test_parse_multiline_with_incomplete_comment(parser): """A terminator within a comment will be ignored and won't terminate a multiline command. Un-closed comments effectively comment out everything after the start.""" - line = 'multiline command /* with comment in progress;' + line = 'multiline command /* with unclosed comment;' statement = parser.parse(line) assert statement.multiline_command == 'multiline' assert statement.command == 'multiline' - assert statement.args == 'command' - assert statement.argv == ['multiline', 'command'] - assert not statement.terminator + assert statement.args == 'command /* with unclosed comment' + assert statement.argv == ['multiline', 'command', '/*', 'with', 'unclosed', 'comment'] + assert statement.terminator == ';' def test_parse_multiline_with_complete_comment(parser): line = 'multiline command /* with comment complete */ is done;' |