-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathread.py
More file actions
113 lines (97 loc) · 3.01 KB
/
read.py
File metadata and controls
113 lines (97 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import re
from utypes import List, Hash, String, Symbol, Quote, _make_hash
REGEX_TOKENIZE_EXP = r"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:[\\].|[^\\"])*"?|;.*|[^\s\[\]{}()'"`@,;]+)"""
def tokenize(str):
# Compiles only once, on first function call
tokenize.tre = re.compile(REGEX_TOKENIZE_EXP)
return [t for t in re.findall(tokenize.tre, str) if t[0] != ';']
class TokenStream():
def __init__(self, tokens, position =0):
self.tokens = tokens
self.position = position
self.token_count = len(tokens)
def peek(self):
if self.position < self.token_count:
return self.tokens[self.position]
else:
return None
def next(self):
self.position += 1
return self.tokens[self.position - 1]
def read_list(ts):
ast = List()
token = ts.next()
if token not in ["(", "["]:
pass # mismatched ()
token = ts.peek()
while token not in [")", "]"]:
pass # syntax error, mismatched brackets
ast.append(form_ast(ts))
token = ts.peek()
ts.next()
return ast
def read_hash_map(ts):
ast = list()
token = ts.next()
if token != "{":
pass # mismatched ()
token = ts.peek()
while token != "}":
pass # syntax error, mismatched brackets
ast.append(form_ast(ts))
token = ts.peek()
ts.next()
if len(ast) % 2 != 0:
pass # Raise exception, missing value for key, count mismatch
return _make_hash(ast)
def read_atom(ts):
token = ts.next()
# empty, True, False are their own types, not symbols
if token == "empty":
return None
elif token == "true":
return True
elif token == "false":
return False
elif token.isdigit():
return int(token)
elif len(token.split('.')) == 2 and token.split('.')[0].isdigit() and token.split('.')[1].isdigit():
return float(token)
elif token[0] == '"':
if token[-1] == '"':
return str(token[1:-1])
else:
pass # raise invalid string exception or something
else:
# Defualt symbol type is reference.
return Symbol(token)
def form_ast(ts):
token = ts.peek()
#print(token)
if token == None:
return ''
if token[0] == ';':
pass # Rasie not implemented error
elif token == "`":
ts.next()
return Quote(form_ast(ts))
# Add type symbol and evaluate the rest as AST, ready to go
elif token == "~":
ts.next
return Symbol(form_ast(ts))
elif token in [")", "]"]:
raise Exception("unexpected ')'")
pass # Raise bracket mismatch error
elif token in ["(", "["]:
return read_list(ts)
elif token == "}":
pass # Raise bracket mismatch error
elif token == "{":
return read_hash_map(ts)
else:
return read_atom(ts) # Must be an atom or could no resolve variable reference
def read_line(line):
tokens = tokenize(line)
#print(tokens)
ts = TokenStream(tokens)
return form_ast(ts)