Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bnf/apyds_bnf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ def visitFunction(self, ctx):
return f"{self.visit(ctx.term(0))}({', '.join(self.visit(t) for t in ctx.term()[1:])})"

def visitUnary(self, ctx):
return f"({ctx.getChild(0).getText()} {self.visit(ctx.term())})"
return f"({ctx.getChild(1).getText()} {self.visit(ctx.term())})"

def visitBinary(self, ctx):
return f"({self.visit(ctx.term(0))} {ctx.getChild(1).getText()} {self.visit(ctx.term(1))})"


def parse(input):
def parse(input: str) -> str:
chars = InputStream(input)
lexer = DspLexer(chars)
tokens = CommonTokenStream(lexer)
Expand All @@ -78,7 +78,7 @@ def parse(input):
return visitor.visit(tree)


def unparse(input):
def unparse(input: str) -> str:
chars = InputStream(input)
lexer = DsLexer(chars)
tokens = CommonTokenStream(lexer)
Expand Down
21 changes: 21 additions & 0 deletions bnf/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,24 @@ root = ".."

[tool.setuptools.packages.find]
include = ["apyds_bnf"]

[project.optional-dependencies]
dev = [
"ruff~=0.14.6",
"pytest~=9.0.1",
"pytest-cov~=7.0.0",
]

[tool.ruff]
line-length = 120

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["E741", "E743", "F841"]

[tool.ruff.format]

[tool.pytest.ini_options]
addopts = "--cov=apyds_bnf"
145 changes: 145 additions & 0 deletions bnf/tests/test_parse_unparse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
from apyds_bnf import parse, unparse


def test_parse_simple_rule() -> None:
"""Test parsing a simple rule with premises and conclusion"""
dsp_input = "a, b -> c"
ds_output = parse(dsp_input)
expected = "a\nb\n----\nc"
assert ds_output == expected


def test_parse_no_premises() -> None:
"""Test parsing a rule with no premises (axiom)"""
dsp_input = "a"
ds_output = parse(dsp_input)
expected = "----\na"
assert ds_output == expected


def test_parse_function() -> None:
"""Test parsing a function call"""
dsp_input = "f(a, b) -> c"
ds_output = parse(dsp_input)
expected = "(function f a b)\n----------------\nc"
assert ds_output == expected


def test_parse_subscript() -> None:
"""Test parsing subscript notation"""
dsp_input = "a[i, j] -> b"
ds_output = parse(dsp_input)
expected = "(subscript a i j)\n-----------------\nb"
assert ds_output == expected


def test_parse_binary_operator() -> None:
"""Test parsing binary operators"""
dsp_input = "(a + b) -> c"
ds_output = parse(dsp_input)
expected = "(binary + a b)\n--------------\nc"
assert ds_output == expected


def test_parse_unary_operator() -> None:
"""Test parsing unary operators"""
dsp_input = "~ a -> b"
ds_output = parse(dsp_input)
expected = "(unary ~ a)\n-----------\nb"
assert ds_output == expected


def test_parse_multiple_rules() -> None:
"""Test parsing multiple rules"""
dsp_input = "a -> b\nc -> d"
ds_output = parse(dsp_input)
expected = "a\n----\nb\n\nc\n----\nd"
assert ds_output == expected


def test_parse_complex_expression() -> None:
"""Test parsing complex nested expressions"""
dsp_input = "(a + b) * c, d[i] -> f(g, h)"
ds_output = parse(dsp_input)
expected = "(binary * (binary + a b) c)\n(subscript d i)\n---------------------------\n(function f g h)"
assert ds_output == expected


def test_unparse_simple_rule() -> None:
"""Test unparsing a simple rule"""
ds_input = "a\nb\n----\nc"
dsp_output = unparse(ds_input)
expected = "a, b -> c"
assert dsp_output == expected


def test_unparse_no_premises() -> None:
"""Test unparsing a rule with no premises"""
ds_input = "----\na"
dsp_output = unparse(ds_input)
expected = " -> a"
assert dsp_output == expected


def test_unparse_function() -> None:
"""Test unparsing a function"""
ds_input = "(function f a b)\n----\nc"
dsp_output = unparse(ds_input)
expected = "f(a, b) -> c"
assert dsp_output == expected


def test_unparse_subscript() -> None:
"""Test unparsing subscript notation"""
ds_input = "(subscript a i j)\n----\nb"
dsp_output = unparse(ds_input)
expected = "a[i, j] -> b"
assert dsp_output == expected


def test_unparse_binary_operator() -> None:
"""Test unparsing binary operators"""
ds_input = "(binary + a b)\n----\nc"
dsp_output = unparse(ds_input)
expected = "(a + b) -> c"
assert dsp_output == expected


def test_unparse_unary_operator() -> None:
"""Test unparsing unary operators"""
ds_input = "(unary ~ a)\n----\nb"
dsp_output = unparse(ds_input)
expected = "(~ a) -> b"
assert dsp_output == expected


def test_unparse_multiple_rules() -> None:
"""Test unparsing multiple rules"""
ds_input = "a\n----\nb\n\nc\n----\nd"
dsp_output = unparse(ds_input)
expected = "a -> b\nc -> d"
assert dsp_output == expected


def test_unparse_complex_expression() -> None:
"""Test unparsing complex nested expressions"""
ds_input = "(binary * (binary + a b) c)\n(subscript d i)\n----\n(function f g h)"
dsp_output = unparse(ds_input)
expected = "((a + b) * c), d[i] -> f(g, h)"
assert dsp_output == expected


def test_roundtrip_parse_unparse() -> None:
"""Test that parse followed by unparse produces consistent results"""
dsp_original = "a, b -> c"
ds_intermediate = parse(dsp_original)
dsp_result = unparse(ds_intermediate)
assert dsp_result == dsp_original


def test_roundtrip_unparse_parse() -> None:
"""Test that unparse followed by parse produces consistent results"""
ds_original = "a\nb\n----\nc"
dsp_intermediate = unparse(ds_original)
ds_result = parse(dsp_intermediate)
assert ds_result == ds_original
Loading