Convertible Parsing Tutorial

Todo

Rewrite this tutorial to explain step-by-step how to develop an small yet real project with Booleano.

Overview

Convertible parsing is when the boolean expressions should be converted into something else, most likely another filter.

What you need

For this you need a grammar, passed to a convertible parse manager and finally, your converter class.

Configuring the grammar

We’re going to use the grammar with the default tokens, except for the “belongs to” and “is sub-set of” operators (the default tokens are “∈” and “⊂”, respectively, which is not easy to type in a keyboard):

from booleano.parser import Grammar

grammar = Grammar(belongs_to="in", is_subset="is subset of")

With this grammar, we can write expressions like:

  • "thursday" in {"monday", "tuesday", "wednesday", "thursday", "friday"}
  • "thursday" in week_days
  • {"thursday", "monday"} is subset of {"monday", "tuesday", "wednesday", "thursday", "friday"}
  • {"thursday", "monday"} is subset of week_days

Configuring the convertible parse manager

This is easy. You just need the grammar we created before:

from booleano.parser import ConvertibleParseManager

parse_manager = ConvertibleParseManager(grammar)

Defining a converter

You have to subclass booleano.operations.converters.BaseConverter and define its abstract methods (i.e., the node-specific converters) so they return the data type you want.

Parsing and converting expressions

That’s all you need. Your module should look like this:

from booleano.parser import Grammar, ConvertibleParseManager
from your_project import YourCustomConverter

grammar = Grammar(belongs_to="in", is_subset="is subset of")
parse_manager = ConvertibleParseManager(grammar)
converter = YourCustomConverter()

It’s now time to put out parser to the test! Let’s start by checking how expressions are parsed:

>>> parse_manager.parse('"thursday" in {"monday", "tuesday", "wednesday", "thursday", "friday"}')
<Parse tree (convertible) <BelongsTo <Set <String "monday">, <String "tuesday">, <String "friday">, <String "thursday">, <String "wednesday">> <String "thursday">>>
>>> parse_manager.parse('today == "2009-07-17"')
<Parse tree (convertible) <Equal <Placeholder variable "today"> <String "2009-07-17">>>
>>> parse_manager.parse('today != "2009-07-17"')
<Parse tree (convertible) <NotEqual <Placeholder variable "today"> <String "2009-07-17">>>
>>> parse_manager.parse('~ today == "2009-07-17"')
<Parse tree (convertible) <Not <Equal <Placeholder variable "today"> <String "2009-07-17">>>>
>>> parse_manager.parse('today > "2009-07-17"')
<Parse tree (convertible) <GreaterThan <Placeholder variable "today"> <String "2009-07-17">>>
>>> parse_manager.parse('time:today == "sunday" & ~weather:will_it_rain_today("paris")')
<Parse tree (convertible) <And <Equal <Placeholder variable "today" at namespace="time"> <String "sunday">> <Not <Placeholder function call "will_it_rain_today"(<String "paris">) at namespace="weather">>>>

OK, it seems like all the expressions above were parsed as expected.

In order to convert these trees with YourCustomConverter, you’d just need to pass its instance converter to the parse tree (which is a callable). For example:

>>> parse_tree = parse_manager.parse('today > "2009-07-17"')
>>> the_conversion_result = parse_tree(converter)

And the_conversion_result will be, well, the conversion result.