From 8fd2db12b56c41e072b3fdab4e0003d49e1a9e3a Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Thu, 18 Jun 2020 17:10:34 +0200 Subject: [PATCH 1/6] Reuse code to generate the projection python code --- relational/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relational/parser.py b/relational/parser.py index a5d6d34..16909af 100644 --- a/relational/parser.py +++ b/relational/parser.py @@ -231,7 +231,7 @@ class Unary(Node): # Converting parameters if self.name == PROJECTION: - prop = '\"%s\"' % prop.replace(' ', '').replace(',', '\",\"') + prop = repr(self.get_projection_prop()) elif self.name == RENAME: prop = repr(self.get_rename_prop()) else: # Selection From 3056dafbffec5036a3dc7f161c452a9517cb0f72 Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Thu, 18 Jun 2020 17:12:57 +0200 Subject: [PATCH 2/6] Reuse code for optimizations --- relational/parser.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/relational/parser.py b/relational/parser.py index 16909af..f748e97 100644 --- a/relational/parser.py +++ b/relational/parser.py @@ -150,7 +150,7 @@ class Node: elif isinstance(self, Binary) and self.name == DIVISION: return list(set(self.left.result_format(rels)) - set(self.right.result_format(rels))) elif self.name == PROJECTION: - return [i.strip() for i in self.prop.split(',')] + return self.get_projection_prop() elif self.name == PRODUCT: return self.left.result_format(rels) + self.right.result_format(rels) elif self.name == SELECTION: @@ -270,8 +270,6 @@ class Unary(Node): self.prop = ','.join(f'{k}{ARROW}{v}' for k, v in renames.items()) - - def parse_tokens(expression: List[Union[list, str]]) -> Node: '''Generates the tree from the tokenized expression If no expression is specified then it will create an empty node''' From 7cb6d4941f6cc908737f815d7be41b879fe698f7 Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Thu, 18 Jun 2020 17:09:00 +0200 Subject: [PATCH 3/6] More parse details --- relational/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relational/parser.py b/relational/parser.py index f748e97..d0f9402 100644 --- a/relational/parser.py +++ b/relational/parser.py @@ -321,7 +321,7 @@ def parse_tokens(expression: List[Union[list, str]]) -> Node: prop=expression[1 + i].strip(), child=parse_tokens(expression[2 + i]) ) - raise ParserException('Parse error') #FIXME more details + raise ParserException(f'Parse error on {expression!r}') def _find_matching_parenthesis(expression: str, start=0, openpar='(', closepar=')') -> Optional[int]: From e5f7b1745cf49c38d8e4b8da7707f212e93c6120 Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Thu, 18 Jun 2020 16:59:58 +0200 Subject: [PATCH 4/6] Add new error about empty expressions. --- relational/parser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/relational/parser.py b/relational/parser.py index d0f9402..7d9d828 100644 --- a/relational/parser.py +++ b/relational/parser.py @@ -273,6 +273,8 @@ class Unary(Node): def parse_tokens(expression: List[Union[list, str]]) -> Node: '''Generates the tree from the tokenized expression If no expression is specified then it will create an empty node''' + if len(expression) == 0: + raise ParserException('Failed to parse empty expression') # If the list contains only a list, it will consider the lower level list. # This will allow things like ((((((a))))) to work From 0df6a263e524dad6458f40620a8be5cdabec4dcc Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Thu, 18 Jun 2020 17:01:52 +0200 Subject: [PATCH 5/6] Check it after removing nesting --- relational/parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/relational/parser.py b/relational/parser.py index 7d9d828..a765d6e 100644 --- a/relational/parser.py +++ b/relational/parser.py @@ -273,17 +273,17 @@ class Unary(Node): def parse_tokens(expression: List[Union[list, str]]) -> Node: '''Generates the tree from the tokenized expression If no expression is specified then it will create an empty node''' - if len(expression) == 0: - raise ParserException('Failed to parse empty expression') # If the list contains only a list, it will consider the lower level list. # This will allow things like ((((((a))))) to work while len(expression) == 1 and isinstance(expression[0], list): expression = expression[0] + if len(expression) == 0: + raise ParserException('Failed to parse empty expression') + # The list contains only 1 string. Means it is the name of a relation if len(expression) == 1: - if not rtypes.is_valid_relation_name(expression[0]): raise ParserException( u"'%s' is not a valid relation name" % expression[0]) From 31a59e1de0d5e3613b9ea05d100f083b11588fa6 Mon Sep 17 00:00:00 2001 From: Salvo 'LtWorf' Tomaselli Date: Thu, 18 Jun 2020 16:59:46 +0200 Subject: [PATCH 6/6] Fix error reporting in the parser --- relational/parser.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/relational/parser.py b/relational/parser.py index a765d6e..1015dbf 100644 --- a/relational/parser.py +++ b/relational/parser.py @@ -286,7 +286,7 @@ def parse_tokens(expression: List[Union[list, str]]) -> Node: if len(expression) == 1: if not rtypes.is_valid_relation_name(expression[0]): raise ParserException( - u"'%s' is not a valid relation name" % expression[0]) + f'{expression[0]!r} is not a valid relation name') return Variable(expression[0]) #FIXME Move validation in the object # Expression from right to left, searching for binary operators @@ -302,21 +302,20 @@ def parse_tokens(expression: List[Union[list, str]]) -> Node: for i in range(len(expression) - 1, -1, -1): if expression[i] in b_operators: # Binary operator - if len(expression[:i]) == 0: raise ParserException( - u"Expected left operand for '%s'" % self.name) + f'Expected left operand for {expression[i]!r}') if len(expression[i + 1:]) == 0: raise ParserException( - u"Expected right operand for '%s'" % self.name) + f'Expected right operand for {expression[i]!r}') return Binary(expression[i], parse_tokens(expression[:i]), parse_tokens(expression[i + 1:])) '''Searches for unary operators, parsing from right to left''' for i in range(len(expression) - 1, -1, -1): if expression[i] in u_operators: # Unary operator if len(expression) <= i + 2: raise ParserException( - u"Expected more tokens in '%s'" % self.name) + f'Expected more tokens in {expression[i]!r}') return Unary( expression[i],