52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
from core.parser.clean_string import cleanString
|
|
from core.parser.parse_token import parseToken
|
|
from core.parser.find_prefix import findPrefix
|
|
|
|
from core.primitives.list import (
|
|
cons,
|
|
NIL
|
|
)
|
|
from core.exceptions import (
|
|
syntaxError,
|
|
runtimeError
|
|
)
|
|
|
|
from core.tokens import SpecialForm
|
|
|
|
def parseExpression(s: str) -> tuple:
|
|
s = cleanString(s)
|
|
if not s:
|
|
return NIL, s
|
|
match s[0]:
|
|
case '"': # string
|
|
matching = s.find('"', 1)
|
|
if matching < 0:
|
|
raise syntaxError(f'the closing " is missing: {s}')
|
|
return s[1:matching], s[matching + 1:]
|
|
case '(': # list
|
|
cache = s # saving initial view for Error illustration
|
|
s = s[1:]
|
|
arr: list = []
|
|
while s and s[0] != ')':
|
|
elem, s = parseExpression(s)
|
|
arr.append(elem)
|
|
s = cleanString(s)
|
|
if not s:
|
|
raise syntaxError(f'the closing ) is missing: {cache}')
|
|
result = NIL
|
|
for elem in reversed(arr):
|
|
result = cons(elem, result)
|
|
return result, s[1:]
|
|
case ')':
|
|
raise syntaxError(f'extra closing bracket: {s}') # TODO debug
|
|
case "'":
|
|
try:
|
|
v, rem = parseExpression(s[1:])
|
|
except Exception as e:
|
|
raise runtimeError(f'invalid quote: {s}') from e
|
|
if v is None:
|
|
raise syntaxError(f'quote of nothing: {s}')
|
|
return cons(SpecialForm.QUOTE, cons(v, NIL)), rem
|
|
case _: # maybe we can find token
|
|
first = findPrefix(s)
|
|
return parseToken(first) if first else NIL, s[len(first):] |