Skip to content

Commit

Permalink
Merge pull request #3 from lucasoshiro/cleaner_constructor
Browse files Browse the repository at this point in the history
Cleaner constructor
  • Loading branch information
mahdavipanah authored Nov 22, 2023
2 parents 5c936fd + c204714 commit 749370c
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 9 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ pyCFG library is in `cfg.py` module and can be imported and be used easily. For
```Python
from cfg import CFG

g = CFG({'S'}, {'a', 'b', 'c', 'λ'}, {('S', 'aSa'),
('S', 'bSb'),
('S', 'cSc'),
('S', 'λ')}, 'S', 'λ')
g = CFG(terminals={'a', 'b', 'c', 'λ'},
rules={'S': ['aSa', 'bSb', 'cSc', 'λ']}
)

string = input("Enter a string: ")

Expand All @@ -40,10 +39,23 @@ else:
```
Above program gets a string from input and tells if the defined grammer can generate the string or not.

## Tests

If you want to test, make sure that `pytest` is installed, then run:

~~~bash
pytest test.py
~~~

## Author

Hamidreza Mahdavipanah

### Contributors

- Lucas Seiki Oshiro


## License

[MIT](./LICENSE)
48 changes: 43 additions & 5 deletions cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,55 @@ class CFG(object):
Context free grammar (CFG) class
"""

def __init__(self, variables, terminals, rules, start_variable, null_character):
def __init__(self,
variables=None,
terminals=None,
rules=None,
start_variable='S',
null_character='λ'):
"""
Initialize method
Parameters
variables: grammar's variables set
variables (optional): grammar's variables set.
terminals: grammar's terminals set
rules: grammar's rules
start_variable: grammar's start variable
null_character: grammar's null character
"""
start_variable (optional, defaults to 'S'): grammar's start variable
null_character (optional, defaults to 'λ'): grammar's null character
"""

if variables is None:
variables = set()
elif hasattr(variables, '__iter__'):
variables = {*variables}
else:
raise TypeError(
"CFG variables must be a iterable, not {}".format(type(variables).__name__)
)

if isinstance(rules, dict):
variables |= {*rules}
rules = {
(var, var_rule)
for var, var_rules in rules.items()
for var_rule in var_rules
}
elif hasattr(rules, '__iter__'):
rules = {*rules}
else:
raise TypeError(
"CFG rules must be a collection or a dict, not {}".format(type(rules).__name__)
)

if isinstance(terminals, set):
terminals = terminals
elif hasattr(terminals, '__iter__'):
terminals = {*terminals}
else:
raise TypeError(
"CFG variables must be a iterable, not {}".format(type(variables).__name__)
)

self.variables = variables
self.terminals = terminals
self.start_variable = start_variable
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest
63 changes: 63 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env python3

import pytest

from itertools import product
from cfg import CFG


def test_old_behavior():
g = CFG(
{'S'},
{'a', 'b', 'c', 'λ'},
{('S', 'aSa'),
('S', 'bSb'),
('S', 'cSc'),
('S', 'λ')},
'S',
'λ'
)

observed = {x for x in map(''.join, product(*['abc'] * 4)) if g.cyk(x)}
expected = {'aaaa', 'abba', 'acca', 'baab', 'bbbb', 'bccb', 'caac', 'cbbc', 'cccc'}

assert observed == expected

def test_with_dict():
g = CFG(
{'S'},
{'a', 'b', 'c', 'λ'},
{'S': ['aSa', 'bSb', 'cSc', 'λ']},
'S',
'λ'
)

observed = {x for x in map(''.join, product(*['abc'] * 4)) if g.cyk(x)}
expected = {'aaaa', 'abba', 'acca', 'baab', 'bbbb', 'bccb', 'caac', 'cbbc', 'cccc'}

assert observed == expected

def test_without_start_variable_and_null_character():
g = CFG(
{'S'},
{'a', 'b', 'c', 'λ'},
{'S': ['aSa', 'bSb', 'cSc', 'λ']}
)

observed = {x for x in map(''.join, product(*['abc'] * 4)) if g.cyk(x)}
expected = {'aaaa', 'abba', 'acca', 'baab', 'bbbb', 'bccb', 'caac', 'cbbc', 'cccc'}

assert observed == expected

def test_without_variables():
g = CFG(
terminals={'a', 'b', 'c', 'λ'},
rules={'S': ['aSa', 'bSb', 'cSc', 'λ']}
)

observed = {x for x in map(''.join, product(*['abc'] * 4)) if g.cyk(x)}
expected = {'aaaa', 'abba', 'acca', 'baab', 'bbbb', 'bccb', 'caac', 'cbbc', 'cccc'}

assert observed == expected


0 comments on commit 749370c

Please sign in to comment.