diff --git a/lisp.py b/lisp.py index 0000000..f2a5c3d --- /dev/null +++ b/lisp.py @@ -0,0 +1,78 @@ +import re + +class LispParser: + def __init__(self, expression): + self.expression = expression + self.tokens = self.tokenize() + self.index = 0 + + def tokenize(self): + token_pattern = r'\s*([()])|(\d+)|([a-zA-Z_][a-zA-Z0-9_]*)' + tokens = re.findall(token_pattern, self.expression) + return [token for group in tokens for token in group if token] + + def parse(self): + result = [] + while self.index < len(self.tokens): + token = self.tokens[self.index] + if token == '(': + self.index += 1 + result.append(self.parse()) + elif token == ')': + return result + else: + result.append(self.parse_atom(token)) + self.index += 1 + if len(result) == 1: + return result[0] + return result + + def parse_atom(self, token): + try: + return int(token) + except ValueError: + return token + +def parse_lisp(expression): + parser = LispParser(expression) + return parser.parse() + +if __name__ == "__main__": + expression = "(1 2 (3 4) a b)" + print(parse_lisp(expression)) diff --git a/tests/test_lisp.py b/tests/test_lisp.py index 0000000..b5c7d8e --- /dev/null +++ b/tests/test_lisp.py @@ -0,0 +1,39 @@ +import unittest +from lisp import parse_lisp + +class TestLispParser(unittest.TestCase): + def test_parse_numbers(self): + self.assertEqual(parse_lisp("123"), 123) + self.assertEqual(parse_lisp("(1 2 3)"), [1, 2, 3]) + + def test_parse_symbols(self): + self.assertEqual(parse_lisp("a"), "a") + self.assertEqual(parse_lisp("(a b c)"), ["a", "b", "c"]) + + def test_parse_nested_lists(self): + self.assertEqual(parse_lisp("(1 (2 3) 4)"), [1, [2, 3], 4]) + self.assertEqual(parse_lisp("((a b) (c d))"), [["a", "b"], ["c", "d"]]) + + def test_unbalanced_parentheses(self): + with self.assertRaises(IndexError): + parse_lisp("(") + with self.assertRaises(IndexError): + parse_lisp(")") + with self.assertRaises(IndexError): + parse_lisp("(1 2 (3 4)")