Skip to content

Commit

Permalink
create and update command parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
aidanhb committed Oct 26, 2019
1 parent 44ab5c3 commit f262e45
Showing 1 changed file with 74 additions and 37 deletions.
111 changes: 74 additions & 37 deletions tinytalk/grammar.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import pprint

from parsimonious.grammar import Grammar, NodeVisitor
from parsimonious.nodes import RegexNode
import pprint

grammar = Grammar(
r"""
query = "when" condition (";" condition)* ws?
condition = adjectives? tags data? (ws alias)?
program = query write
query = "when" entry (";" entry)*
write = (create / update) (";" (create / update))*
create = ws "create" entry
update = ws "update" ws name data
entry = adjectives? tags data? (ws alias)?
adjectives = (ws adjective)+
tags = (ws tag)+
data = (ws datum)+
Expand All @@ -27,44 +32,82 @@ def not_whitespace(o):
return not (isinstance(o, RegexNode) and o.expr_name == "ws")


class Condition:

def __init__(self, *_, adjectives, tags, data, alias):
class Entry:
def __init__(self, *_, adjectives, tags, data):
self.adjectives = adjectives
self.tags = tags
self.data = data

def __str__(self):
return pprint.pformat(self)


class AliasEntry(Entry):

def __init__(self, *_, adjectives, tags, data, alias):
super().__init__(adjectives=adjectives, tags=tags, data=data)
self.alias = alias

def __repr__(self):
return f"{self.__class__.__name__}(adjectives={self.adjectives}, tags={self.tags}, data={self.data}, alias={self.alias})"
return f"{self.__class__.__name__}(adjectives={self.adjectives}, " \
f"tags={self.tags}, " \
f"data={self.data}, " \
f"alias={self.alias})"

def __str__(self):
return pprint.pformat(self)

class Update(Entry):

def __init__(self, *_, alias, data):
super().__init__(adjectives=None, tags=None, data=data)
self.alias = alias

def __repr__(self):
return f"{self.__class__.__name__}(alias={self.alias}, " \
f"data={self.data})"


class TinyTalkVisitor(NodeVisitor):
def visit_program(self, _node, visited_children):
query, write = visited_children
return {"query": query, "write": write}

def visit_write(self, _node, visited_children):
first, rest = visited_children
write = [first[0]]
if isinstance(rest, list):
write += [pair[1][0] for pair in rest]
return write

def visit_create(self, _node, visited_children):
ws1, _create, entry = visited_children
return entry

def visit_update(self, _node, visited_children):
_ws1, _update, _ws2, alias, data = visited_children
return Update(alias=alias, data=data)

def visit_query(self, _node, visited_children):
""" Returns the overall output. """
_when, first, rest, _ws = visited_children
_when, first, rest = visited_children
query = [first]
if isinstance(rest, list):
query += [pair[1] for pair in rest]
return query

def visit_condition(self, _node, visited_children):
def visit_entry(self, _node, visited_children):
adjectives_opt, tags, data_opt, alias_opt = visited_children
adjectives = set(adjectives_opt[0]) if isinstance(adjectives_opt, list) else None
data = dict(data_opt[0]) if isinstance(data_opt, list) else None
data = data_opt[0] if isinstance(data_opt, list) else None
alias = alias_opt[0][1] if isinstance(alias_opt, list) else None
cond = Condition(adjectives=adjectives,
tags=set(tags),
data=data,
alias=alias)
cond = AliasEntry(adjectives=adjectives,
tags=set(tags),
data=data,
alias=alias)
return cond

def visit_alias(self, _node, visited_children):
_as, _ws, name = visited_children
return name.text
return name

def visit_adjectives(self, _node, visited_children):
adjs = [child[1] for child in visited_children]
Expand All @@ -79,31 +122,25 @@ def visit_tags(self, _node, visited_children):

def visit_tag(self, _node, visited_children):
_pound, name = visited_children
return name.text
return name

def visit_data(self, _node, visited_children):
data = [child[1] for child in visited_children]
return data
return dict(data)

def visit_datum(self, _node, visited_children):
_as, name, val_opt = visited_children
val = "ANY"
if isinstance(val_opt, list):
_ws, _colon, val = val_opt[0]
val = val[0]
return name.text, val

def visit_number(self, _node, visited_children):
sign_opt, integer, decimal_opt = visited_children
number = integer[0]
if isinstance(decimal_opt, list):
point, decimal = decimal_opt[0]
number += point.text
number += decimal[0]
if isinstance(sign_opt, list):
sign = sign_opt[0][0].text
number = sign + number
return float(number)
return name, val

def visit_number(self, node, _visited_children):
return float(node.text)

def visit_name(self, node, _visited_children):
return node.text

def visit_digit(self, node, _visited_children):
return node.text
Expand Down Expand Up @@ -134,14 +171,14 @@ def generic_visit(self, node, visited_children):
# TODO fix rules to block protected namespaces?

# * namespace Pong
# when #aruco x where 0 < x < 100, y [create friend #paddle x: 100, y]
# when [#aruco x where 0 < x < 100, y] create [friend #paddle x: 100, y]
# ** app #paddle x y
# when friend #aruco y as marker [update my y: marker y]
# when global nearby #ball
# when [friend #aruco y] as marker update [my y: marker y]
# when [global nearby #ball
# x where 90 < x < 110,
# velocity_x,
# y where (my y - 50) < y < (my y + 50)
# y where (my y - 50) < y < (my y + 50)]
# as ball
# [update ball velocity_x: (ball velocity_x * -1)]
# update [ball velocity_x: (ball velocity_x * -1)]

# implies that the #paddle was declared in the Pong namespace

0 comments on commit f262e45

Please sign in to comment.