Skip to content

Instantly share code, notes, and snippets.

@YuRen-tw
Created May 8, 2017 13:51
Show Gist options
  • Save YuRen-tw/24cdebfdc85127346f084e61f222584b to your computer and use it in GitHub Desktop.
Save YuRen-tw/24cdebfdc85127346f084e61f222584b to your computer and use it in GitHub Desktop.
Lispy
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