# Development Guide

This document gives an overview of the code in boolean.py, explaining the layout and design decisions and some difficult algorithms. All used definitions and laws are stated in Concepts and Definitions.

## Testing

Test boolean.py with your current Python environment:

    python setup.py test

Test with all of the supported Python environments using tox:

    pip install -r requirements-dev.txt
    tox

If tox throws InterpreterNotFound, limit it to python interpreters that are actually installed on your machine:

    tox -e py36

## Classes Hierarchy

### Expression

### Symbol

### Function

### NOT

### AND

### OR

## Class creation

Except for BooleanAlgebra and Symbol, no other classes are is designed to be instantiated directly. Instead you should create a BooleanAlgebra instance, then use BooleanAlgebra.symbol, BooleanAlgebra.NOT, BooleanAlgebra.AND, BooleanAlgebra.OR BooleanAlgebra.TRUE and BooleanAlgebra.FALSE to compose your expressions in the context of this algebra.

## Class initialization

In this section for all classes is stated which arguments they will accept and how these arguments are processed before they are used.

### Symbol

& `obj` (Named Symbol)

## Ordering

As far as possible every expression should always be printed in exactly the same way. Therefore a strict ordering between different boolean classes and between instances of same classes is needed. This is defined primarily by the sort_order attribute.

### Class ordering

`BaseElement` < `Symbol` < `AND` < `OR`

`NOT` is an exception in this scheme. It will be sorted based on the sort order of its argument.

Class ordering is implemented by an attribute `sort_order` in all relevant classes. It holds an integer that will be used for comparison if it is available in both compared objects. For Symbols, the attached obj object is used instead.

`Class` | sort_order
--- | ---
`BaseElement` | 0
`Symbol` | 5
`AND` | 10
`OR` | 25

### Instance ordering

`BaseElement`

  `FALSE` < `TRUE`

`Symbol`

> `Symbol.obj` o `Symbol.obj`

`NOT`

  if `NOT.args[0]` == `other` —> `other` < `NOT`

  `NOT` o `other` —> `NOT.args[0]` o `other`

`AND`

  `AND` o `AND` —> `AND.args[0]` o `AND.args[0]`

  if undecided: repeat for all args

  if undecided: len(`AND.args`) o len(`AND.args`)

  if undecided: return `AND` < `AND`

`OR`

  `OR` o `OR` —> `OR.args[0]` o `OR.args[0]`

  if undecided: repeat for all args

  if undecided: len(`OR.args`) o len(`OR.args`)

  if undecided: return `OR` < `OR`

## Parsing

Parsing is done in two steps: A tokenizer iterates over string characters assigning a TOKEN_TYPE to each token. The parser receives this stream of token types and strings and creates adequate boolean objects from a parse tree.