Created
May 8, 2017 13:51
-
-
Save YuRen-tw/24cdebfdc85127346f084e61f222584b to your computer and use it in GitHub Desktop.
Lispy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import enum | |
FULL_LINE_COMMENT = ';' | |
class CHAR(enum.Enum): | |
LEFT = 1 | |
RIGHT = 2 | |
SYMBOL = 3 | |
DIGIT = 4 | |
SPACE = 5 | |
class TOKEN(enum.Enum): | |
NONE = 0 | |
LEFT = 1 | |
RIGHT = 2 | |
VAR = 3 | |
NUMBER = 4 | |
SPACE = 5 | |
KEYWORDS = ( | |
(TOKEN.VAR, 'display'), | |
(TOKEN.VAR, 'begin'), | |
(TOKEN.VAR, 'if'), | |
(TOKEN.VAR, 'define'), | |
(TOKEN.VAR, 'lambda'), | |
(TOKEN.VAR, '+'), | |
(TOKEN.VAR, '-'), | |
(TOKEN.VAR, '<') | |
) | |
def char_type(char): | |
if char == '(': | |
return CHAR.LEFT | |
if char == ')': | |
return CHAR.RIGHT | |
if char in ' \t\r\n': | |
return CHAR.SPACE | |
code = ord(char) | |
if code in range(48, 58): | |
return CHAR.DIGIT | |
if code in range(33, 127): | |
return CHAR.SYMBOL | |
def file_CharGen(f): | |
for line in f: | |
sline = line.strip() | |
if sline.startswith(FULL_LINE_COMMENT) or sline == '': | |
continue | |
for char in line: | |
yield char | |
def TokenGen(charGen): | |
char_list = [] | |
token_type = TOKEN.NONE | |
for char in charGen: | |
ctype = char_type(char) | |
if ctype == CHAR.LEFT: | |
yield (token_type, ''.join(char_list)) | |
char_list = ['('] | |
token_type = TOKEN.LEFT | |
elif ctype == CHAR.RIGHT: | |
if token_type != TOKEN.SPACE: | |
yield (token_type, ''.join(char_list)) | |
char_list = [')'] | |
token_type = TOKEN.RIGHT | |
elif ctype == CHAR.SPACE: | |
if token_type == TOKEN.LEFT: | |
continue | |
elif token_type != TOKEN.SPACE: | |
yield (token_type, ''.join(char_list)) | |
char_list = [' '] | |
token_type = TOKEN.SPACE | |
elif ctype == CHAR.SYMBOL: | |
if token_type == TOKEN.VAR: | |
char_list.append(char) | |
else: | |
yield (token_type, ''.join(char_list)) | |
char_list = [char] | |
token_type = TOKEN.VAR | |
elif ctype == CHAR.DIGIT: | |
if token_type in (TOKEN.VAR, TOKEN.NUMBER): | |
char_list.append(char) | |
else: | |
yield (token_type, ''.join(char_list)) | |
char_list = [char] | |
token_type = TOKEN.NUMBER | |
yield (token_type, ''.join(char_list)) | |
yield (TOKEN.SPACE, ' ') | |
def Listize(tokenGen): | |
level_list = [[]] | |
item = None | |
for token in tokenGen: | |
token_type = token[0] | |
if token_type == TOKEN.LEFT: | |
level_list.append([]) | |
elif token_type in (TOKEN.VAR, TOKEN.NUMBER): | |
if item is None: | |
item = token | |
else: | |
raise SyntaxError('Where is the Space?') | |
elif token_type == TOKEN.SPACE: | |
if item is not None: | |
level_list[-1].append(item) | |
item = None | |
elif token_type == TOKEN.RIGHT: | |
if item is not None: | |
level_list[-1].append(item) | |
item_list = level_list.pop() | |
item = item_list | |
return level_list[0] | |
def Process_item(item, SCOPE={}, L_SCOPE={}): | |
if type(item) != tuple: | |
return item | |
if item in KEYWORDS: | |
return lambda *x: Process([item, *x], SCOPE, L_SCOPE) | |
token_type = item[0] | |
value = item[1] | |
if token_type == TOKEN.VAR: | |
return L_SCOPE.get(value, SCOPE[value]) | |
elif token_type == TOKEN.NUMBER: | |
return int(value) | |
def list_deep_replace(origin, index, replacement): | |
if type(origin) != list: | |
if origin in index: | |
r = replacement[index.index(origin)] | |
return r | |
else: | |
return origin | |
result = [] | |
for item in origin: | |
result.append(list_deep_replace(item, index, replacement)) | |
return result | |
def Process(item_list, SCOPE={}, L_SCOPE={}): | |
if type(item_list) != list: | |
return Process_item(item_list, SCOPE, L_SCOPE) | |
method = item_list[0] | |
if method not in KEYWORDS: | |
method = Process(method, SCOPE, L_SCOPE) | |
variable = [Process(item, SCOPE, L_SCOPE) for item in item_list[1:]] | |
return method(*variable) | |
elif method == (TOKEN.VAR, 'display'): | |
print(Process(item_list[1], SCOPE, L_SCOPE)) | |
return 0 | |
elif method == (TOKEN.VAR, 'begin'): | |
result = None | |
for item in item_list[1:]: | |
result = Process(item, SCOPE, L_SCOPE) | |
return result | |
elif method == (TOKEN.VAR, 'if'): | |
if Process(item_list[1], SCOPE) != 0: | |
return Process(item_list[2], SCOPE, L_SCOPE) | |
else: | |
return Process(item_list[3], SCOPE, L_SCOPE) | |
elif method == (TOKEN.VAR, 'define'): | |
if item_list[1][0] == TOKEN.VAR and item_list[1] not in KEYWORDS: | |
name = item_list[1][1] | |
SCOPE[name] = Process(item_list[2], SCOPE, L_SCOPE) | |
return SCOPE[name] | |
return 0 | |
elif method == (TOKEN.VAR, '+'): | |
a = Process(item_list[1], SCOPE, L_SCOPE) | |
b = Process(item_list[2], SCOPE, L_SCOPE) | |
return a + b | |
elif method == (TOKEN.VAR, '-'): | |
a = Process(item_list[1], SCOPE, L_SCOPE) | |
b = Process(item_list[2], SCOPE, L_SCOPE) | |
return a - b | |
elif method == (TOKEN.VAR, '<'): | |
a = Process(item_list[1], SCOPE, L_SCOPE) | |
b = Process(item_list[2], SCOPE, L_SCOPE) | |
return a < b | |
elif method == (TOKEN.VAR, 'lambda'): | |
L_SCOPE = dict(SCOPE) | |
def _func (*args): | |
code = list_deep_replace(item_list[2], item_list[1], args) | |
return Process(code, SCOPE, L_SCOPE) | |
return _func |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment