Skip to content

Commit

Permalink
docs: add s-expression example
Browse files Browse the repository at this point in the history
  • Loading branch information
vberlier committed Jun 14, 2021
1 parent 8b0475c commit bb2b503
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 0 deletions.
6 changes: 6 additions & 0 deletions examples/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
3.0
$ python calculator.py '(2 + 9) / 3'
3.6666666666666665
$ python calculator.py 1 + 6 /
UnexpectedEOF: Expected number or brace '(' but reached end of file
$ python calculator.py '1 + 7) / 4 + 6'
InvalidSyntax: ) / 4 + 6
$ python calculator.py '1 + 7 - / 4 + 6'
UnexpectedToken: Expected number or brace '(' but got div '/'
"""


Expand Down
2 changes: 2 additions & 0 deletions examples/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
{'foo': 'bar', 'something': {'else': [42]}}
> {"this": "\"that\""}
{'this': '"that"'}
> [}
UnexpectedToken: Expected curly '{', bracket '[', string or number but got curly '}'
"""


Expand Down
41 changes: 41 additions & 0 deletions examples/sexp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""A basic S-expression parser.
Example usage:
$ python sexp.py '123'
123
$ python sexp.py 'hello'
'hello'
$ python sexp.py '(hello world)'
['hello', 'world']
$ python sexp.py '(foo (bar) thing 9 hello 9)'
['foo', ['bar'], 'thing', 9, 'hello', 9]
$ python sexp.py '(hello world'
UnexpectedEOF: Expected brace ')' but reached end of file
"""


import sys
from typing import Any

from tokenstream import InvalidSyntax, TokenStream


def parse_sexp(stream: TokenStream) -> Any:
with stream.syntax(brace=r"\(|\)", number=r"\d+", name=r"\w+"):
brace, number, name = stream.expect(("brace", "("), "number", "name")
if brace:
return [parse_sexp(stream) for _ in stream.peek_until(("brace", ")"))]
elif number:
return int(number.value)
elif name:
return name.value


if __name__ == "__main__":
try:
stream = TokenStream(" ".join(sys.argv[1:]))
result = parse_sexp(stream)
stream.expect_eof()
print(repr(result))
except InvalidSyntax as exc:
print(f"{exc.__class__.__name__}: {exc}")

0 comments on commit bb2b503

Please sign in to comment.