Skip to content

Commit

Permalink
Fix parser bug with escaped characters
Browse files Browse the repository at this point in the history
This is the proper fix for #28
  • Loading branch information
roehling committed Apr 16, 2016
1 parent f5a63e0 commit f767a39
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 5 deletions.
21 changes: 17 additions & 4 deletions src/catkin_lint/cmake.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ def _resolve_vars(s, var, env_var):
( 'SKIP', r'[ \t]+' ),
( 'LPAREN', r'\(' ),
( 'RPAREN', r'\)' ),
( 'STRING', r'"[^\\"]*(?:\\.[^\\"]*)*"' ),
( 'STRING', r'"(?:\\.|[^\\"])*"' ),
( 'SEMICOLON', r';'),
( 'WORD', r'[^\(\)"# \t\r\n;]+' ),
( 'WORD', r'(?:\\.|[^\\\(\)"# \t\r\n;])+' ),
( 'PRAGMA', r'#catkin_lint:.*?$' ),
( 'COMMENT', r'#.*?$' ),
]
Expand Down Expand Up @@ -99,17 +99,30 @@ def _lexer(s):
if pos != len(s):
raise SyntaxError("Unexpected character %r on line %d" % (s[pos], line))

_arg_spec = [
( 'SKIP', r';' ),
( 'ARG', r'(?:\\.|[^;])+' ),
]
_next_arg = re.compile('|'.join('(?P<%s>%s)' % pair for pair in _arg_spec)).match

def _resolve_args(arg_tokens, var, env_var):
args = []
for typ, val in arg_tokens:
if typ == "STRING":
val = _resolve_vars(val, var, env_var)
# Treat quoted strings as a single word
args.append(_unescape(val))
elif typ == "WORD":
val = _resolve_vars(val, var, env_var)
if val:
args += re.split(r";|[ \t]+", _unescape(val))
# Split unquoted text into list items
mo = _next_arg(val)
while mo is not None:
typ = mo.lastgroup
if typ != "SKIP":
arg = mo.group(typ)
args.append(_unescape(arg))
pos = mo.end()
mo = _next_arg(val, pos)
elif typ != "SEMICOLON":
args.append(val)
return args
Expand Down
14 changes: 13 additions & 1 deletion test/test_cmake_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def test_string(self):
self.parse_all('cmd("string that spans\nmultiple lines")'),
[ ("cmd", [ 'string that spans\nmultiple lines' ]) ]
)
self.assertEqual(
self.parse_all('cmd("\\\\"\\")'),
[ ("cmd", [ '\\', '"' ]) ]
)

def test_macro(self):
self.assertEqual(
Expand Down Expand Up @@ -224,6 +228,14 @@ def test_arguments(self):
self.parse_all('cmd("\\"")'),
[ ("cmd", [ '"' ]) ]
)
self.assertEqual(
self.parse_all('cmd(\\")'),
[ ("cmd", [ '"' ]) ]
)
self.assertEqual(
self.parse_all('cmd(a\\ b)'),
[ ("cmd", [ 'a b' ]) ]
)
self.assertEqual(
self.parse_all("cmd(ENV{PATH})"),
[ ("cmd", [ "ENV{PATH}" ]) ]
Expand All @@ -249,7 +261,7 @@ def test_substitution(self):
)
self.assertEqual(
self.parse_all("cmd(${args})", var={ "args" : "one two three"}),
[ ("cmd", [ "one", "two", "three" ]) ]
[ ("cmd", [ "one two three" ]) ]
)
self.assertEqual(
self.parse_all('cmd("${args}")', var={ "args" : "one;two;three"}),
Expand Down

0 comments on commit f767a39

Please sign in to comment.