Skip to content

Commit

Permalink
refactor grammar
Browse files Browse the repository at this point in the history
Use layering to prevent most shift/reduce conflicts and enforce associativity.
  • Loading branch information
Deric-W committed Apr 9, 2024
1 parent da21165 commit 5ba1d6a
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 6 deletions.
8 changes: 5 additions & 3 deletions src/lambda_repl/grammar.lark
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ VARIABLE: /[^\s().λ\\]+/

abstraction: ("\\" | "λ") VARIABLE "." term

application: ( abstraction | VARIABLE | brackets ) ( _WHITESPACE ( abstraction | VARIABLE | brackets ) )+
application: _application_term _WHITESPACE (abstraction | _simple_term)

?brackets: "(" term ")"
?term: abstraction | _application_term

?term: abstraction | application | VARIABLE | brackets
_application_term: application | _simple_term

_simple_term: VARIABLE | "(" term ")"
11 changes: 8 additions & 3 deletions src/lambda_repl/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from __future__ import annotations
from collections import deque
from collections.abc import Iterator, Sequence
from collections.abc import Iterator
from itertools import chain
from lambda_calculus.terms import Abstraction, Application, Term, Variable
from lark import Lark, Token
Expand Down Expand Up @@ -63,6 +63,10 @@ def __default__(self, data: object, children: object, meta: object) -> Term[str]
"""handle unknown nodes"""
raise UnexpectedInput(f"unknown node: {data}")

def __default_token__(self, token: Token) -> Token:
"""handle unknown tokens"""
raise UnexpectedInput(f"unknown token: {token}")

def VARIABLE(self, name: Token) -> Variable[str]:
"""transform a variable node"""
return Variable(name.value)
Expand All @@ -72,9 +76,10 @@ def abstraction(self, variable: Variable[str], body: Term[str]) -> Abstraction[s
"""transform an abstraction"""
return Abstraction(variable.name, body)

def application(self, children: Sequence[Term[str]]) -> Application[str]:
@v_args(inline=True)
def application(self, abstraction: Term[str], argument: Term[str]) -> Application[str]:
"""transform an application"""
return Application.with_arguments(children[0], children[1:])
return Application(abstraction, argument)


PARSER = Lark.open_from_package(
Expand Down
4 changes: 4 additions & 0 deletions tests/test_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def test_abstraction(self) -> None:
.apply_to(Variable("b"), Variable("c"))
.abstract("a", "b")
)
self.assertEqual(
self.transformer.transform_string("a λa.a b c"),
Variable("a").apply_to(Variable("a").apply_to(Variable("b"), Variable("c")).abstract("a"))
)

def test_brackets(self) -> None:
"""test bracket parsing"""
Expand Down

0 comments on commit 5ba1d6a

Please sign in to comment.