From 11243b2e61e731c507de19009f99d9da694e82fa Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Tue, 10 Nov 2020 14:16:03 +0100 Subject: [PATCH 1/2] Fixed issues with test and control arguments. see #100 --- sievelib/parser.py | 50 ++++++++++++++++++++++------------- sievelib/tests/test_parser.py | 10 +++++++ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/sievelib/parser.py b/sievelib/parser.py index 78d52e5..9e5c9ae 100755 --- a/sievelib/parser.py +++ b/sievelib/parser.py @@ -193,18 +193,30 @@ def __up(self, onlyrecord=False): self.hash_comments = [] self.result += [self.__curcommand] - if not onlyrecord: - while self.__curcommand: - self.__curcommand = self.__curcommand.parent - # Make sure to detect all done tests (including 'not' ones). - condition = ( - self.__curcommand and - self.__curcommand.get_type() == "test" and - self.__curcommand.iscomplete() - ) - if condition: - continue + if onlyrecord: + # We are done + return + + while self.__curcommand: + self.__curcommand = self.__curcommand.parent + if not self.__curcommand: break + # Make sure to detect all done tests (including 'not' ones). + condition = ( + self.__curcommand.get_type() == "test" and + self.__curcommand.iscomplete() + ) + if condition: + continue + # If we are on a control accepting a test list, next token + # must be a comma + condition = ( + self.__curcommand.get_type() == "test" and + self.__curcommand.variable_args_nb + ) + if condition: + self.__set_expected("comma") + break def __check_command_completion(self, testsemicolon=True): """Check for command(s) completion @@ -224,9 +236,11 @@ def __check_command_completion(self, testsemicolon=True): return True ctype = self.__curcommand.get_type() - if ctype == "action" or \ - (ctype == "control" and - not self.__curcommand.accept_children): + condition = ( + ctype == "action" or + (ctype == "control" and not self.__curcommand.accept_children) + ) + if condition: if testsemicolon: self.__set_expected("semicolon") return True @@ -237,6 +251,7 @@ def __check_command_completion(self, testsemicolon=True): if self.__curcommand.get_type() in ["control", "test"]: if self.__curcommand.iscomplete(): if self.__curcommand.get_type() == "control": + self.__set_expected("left_cbracket") break continue if not self.__curcommand.check_next_arg("test", cmd, add=False): @@ -245,7 +260,6 @@ def __check_command_completion(self, testsemicolon=True): if self.__curcommand.variable_args_nb: self.__set_expected("comma", "right_parenthesis") break - return True def __stringlist(self, ttype, tvalue): @@ -442,9 +456,9 @@ def parse(self, text): if ttype not in self.__expected: if self.lexer.pos < len(text) + len(tvalue): msg = ( - "%s found while %s expected near '%s'" - % (ttype, "|".join(self.__expected), - text[self.lexer.pos]) + "{} found while {} expected near '{}'" + .format(ttype, "|".join(self.__expected), + text.decode()[self.lexer.pos]) ) else: msg = ( diff --git a/sievelib/tests/test_parser.py b/sievelib/tests/test_parser.py index 24ea59f..1b8b910 100644 --- a/sievelib/tests/test_parser.py +++ b/sievelib/tests/test_parser.py @@ -696,6 +696,16 @@ def test_control_command_in_test(self): if stop; """) + def test_extra_test_in_simple_control(self): + self.compilation_ko(b""" +if address "From" "example.com" header "Subject" "Example" { stop; } +""") + + def test_missing_comma_in_test_list(self): + self.compilation_ko(b""" +if allof(anyof(address "From" "example.com") header "Subject" "Example") { stop; } +""") + class LanguageRestrictions(SieveTest): def test_unknown_control(self): From 6d30a86bad118c045489355cf5026dd18320261b Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Mon, 7 Dec 2020 11:17:33 +0100 Subject: [PATCH 2/2] Don't forget command completion here. --- sievelib/parser.py | 4 ++-- sievelib/tests/test_parser.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sievelib/parser.py b/sievelib/parser.py index 9e5c9ae..ddc7664 100755 --- a/sievelib/parser.py +++ b/sievelib/parser.py @@ -209,13 +209,13 @@ def __up(self, onlyrecord=False): if condition: continue # If we are on a control accepting a test list, next token - # must be a comma + # must be a comma or a right parenthesis. condition = ( self.__curcommand.get_type() == "test" and self.__curcommand.variable_args_nb ) if condition: - self.__set_expected("comma") + self.__set_expected("comma", "right_parenthesis") break def __check_command_completion(self, testsemicolon=True): diff --git a/sievelib/tests/test_parser.py b/sievelib/tests/test_parser.py index 1b8b910..1e6c0d3 100644 --- a/sievelib/tests/test_parser.py +++ b/sievelib/tests/test_parser.py @@ -419,6 +419,11 @@ def test_singletest_testlist(self): discard (type: action) """) + def test_multitest_testlist(self): + self.compilation_ok(b""" +if anyof(allof(address :contains "From" ""), allof(header :contains "Subject" "")) {} +""") + def test_truefalse_testlist(self): self.compilation_ok(b""" if anyof(true, false) {