Skip to content

Commit

Permalink
Fixed bugs in Parser implementation (Fixes #3)
Browse files Browse the repository at this point in the history
- Group parser would discard space token if no group opening tokens were found
- OR operator would keep current group's leading space only on left-hand side of the operator
  • Loading branch information
dolejska-daniel committed Oct 23, 2020
1 parent 5ff90f0 commit a0579ed
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 13 deletions.
13 changes: 11 additions & 2 deletions amcp_pylib/core/syntax/command_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,28 @@ def create_or_group(self):
""" Creates CommandGroupOr and transforms contents of this group to reflect it. """
# create "or group" (represents implementation of '|' operator)
or_group = CommandGroupOr()
# first token of the current group will be preserved for whole OR group
preserve_first_token = False

# use all contents of this group as left hand side of operator value
new_group_a = CommandGroup(is_required=self.is_required)
for x in self.display_order:
for _id, x in enumerate(self.display_order):
if isinstance(x, CommandGroup):
new_group_a.add_group(x)

elif isinstance(x, CommandArgument):
# first token of the group is space - this has to be preserved for whole OR group
# not just left-hand side
if _id == 0 and x.is_constant and x.value == " ":
preserve_first_token = True
continue

new_group_a.add_argument_object(x)

# reset moved contents
self.subgroups = []
self.arguments = []
self.display_order = []
self.display_order = self.display_order[:1] if preserve_first_token else []

# use the contents as first parameter
or_group.set_groups_a([new_group_a])
Expand Down
3 changes: 3 additions & 0 deletions amcp_pylib/core/syntax/command_group_or.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ def get_dict_repr(self, flatten=False):

def print_recursive_tree(self, indent: int = 0):
""" Recursively prints command argument structure. """
print(" " * indent + f"╠═╗ OR [is_usable: {self.is_usable()}, required: {self.is_required}]")
indent += 1

print(" " * indent + f"╠═╗ Option A [id: {indent}, required: {self.is_required}]")
for sg in self.subgroups_a:
sg.print_recursive_tree(indent + 1)
Expand Down
14 changes: 8 additions & 6 deletions amcp_pylib/core/syntax/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,22 +88,22 @@ def parse(self) -> CommandGroup:
:return: Syntax tree.
"""
# creates initial group holding everything else
group = CommandGroup(is_required=True)
root_group = CommandGroup(is_required=True)

while True:
if self.try_get_token(TokenType.END):
# input is at the end
break

# first try to find group definition and use this group as parent
if not self.try_group(group):
if not self.try_group(root_group):
# if unsuccessful allow <Keyword>, <Constant> or <ConstantSpace> tokens
token = self.get_token([TokenType.KEYWORD, TokenType.CONSTANT, TokenType.CONSTANT_SPACE])
# add found tokens to main group
group.add_constant_argument(token)
root_group.add_constant_argument(token)

# return generated syntax tree root (main group)
return group
return root_group

def try_group(self, parent_group: CommandGroup) -> bool:
"""
Expand Down Expand Up @@ -143,6 +143,10 @@ def try_group(self, parent_group: CommandGroup) -> bool:
self.optional_group_definition(parent_group)
return True

# space after the group between constant keywords or values must be returned
if token_space:
self.return_token(token_space)

# requested token was not found
return False

Expand Down Expand Up @@ -244,8 +248,6 @@ def group_inner(self, group: CommandGroup):
elif token.get_type() is TokenType.OPERATOR_OR:
group = group.create_or_group()

last_token = token

def variable_definition(self, group: CommandGroup):
"""
<Identifier>(/type_specification/)
Expand Down
10 changes: 5 additions & 5 deletions amcp_pylib/core/syntax/token_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def to_str(token_type) -> str:
TokenType.OPERATOR_TYPE: "of type",
TokenType.OPERATOR_COMMA: "comma",
TokenType.CONSTANT_SPACE: "space",
TokenType.REQUIRED_OPEN: "required open",
TokenType.REQUIRED_CLOSE: "required close",
TokenType.OPTIONAL_OPEN: "optional open",
TokenType.OPTIONAL_CLOSE: "optional close",
TokenType.END: "input end",
TokenType.REQUIRED_OPEN: "required_open",
TokenType.REQUIRED_CLOSE: "required_close",
TokenType.OPTIONAL_OPEN: "optional_open",
TokenType.OPTIONAL_CLOSE: "optional_close",
TokenType.END: "input_end",
}[token_type]

0 comments on commit a0579ed

Please sign in to comment.