diff --git a/src/lambda_repl/grammar.lark b/src/lambda_repl/grammar.lark index d430094..d898da0 100644 --- a/src/lambda_repl/grammar.lark +++ b/src/lambda_repl/grammar.lark @@ -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 \ No newline at end of file +_application_term: application | _simple_term + +_simple_term: VARIABLE | "(" term ")" diff --git a/src/lambda_repl/parsing.py b/src/lambda_repl/parsing.py index 4f8ab12..5002b71 100644 --- a/src/lambda_repl/parsing.py +++ b/src/lambda_repl/parsing.py @@ -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 @@ -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) @@ -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( diff --git a/tests/test_parsing.py b/tests/test_parsing.py index c23283d..d706995 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -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"""