def first_expression(source): """Split string into (exp, rest) where exp is the first expression in the string and rest is the rest of the string after this expression.""" source = source.strip() if source[0] == "'": exp, rest = first_expression(source[1:]) return source[0] + exp, rest elif source[0] == "(": last = find_matching_paren(source) return source[:last + 1], source[last + 1:] else: match = re.match(r"^[^\s)']+", source) end = match.end() atom = source[:end] return atom, source[end:]
def test_find_matching_paren_throws_exception_on_no_closing_paren(): """The function should raise error when there is no matching paren to be found""" with assert_raises_regexp(LispError, "Incomplete expression"): find_matching_paren("string (without closing paren", 7)
def test_find_matching_paren_throws_exception_on_bad_initial_position(): """If asked to find closing paren from an index where there is no opening paren, the function should raise an error""" with assert_raises(AssertionError): find_matching_paren("string without parens", 4)
def test_find_matching_empty_parens(): assert_equals(1, find_matching_paren("()", 0))
def test_find_matching_paren(): source = "(foo (bar) '(this ((is)) quoted))" assert_equals(32, find_matching_paren(source, 0)) assert_equals(9, find_matching_paren(source, 5))