Skip to content

Instantly share code, notes, and snippets.

@ympbyc
Created December 10, 2011 06:31
Show Gist options
  • Save ympbyc/1454699 to your computer and use it in GitHub Desktop.
Save ympbyc/1454699 to your computer and use it in GitHub Desktop.
リポジトリにするほどのもんでもないためgistに退避。リポジトリは消す
#!/usr/bin/python
import re
class Unbound: pass
###utilities###
def car(lst):
return lst[0]
def cdr(lst):
return lst[1:len(lst)]
def cons(a, d):
return [a, d]
def num(x):
if type(x) == int:
return 1
else: return 0
def symbol(x):
if type(x) == str:
return 1
else: return 0
def atom(x):
if symbol(x) or num(x):
return 1
else: return 0
def pair(x):
if type(x) == list and x != []:
return 1
else: return 0
def eq(x, y):
if x == y:
return 1
else: return 0
###main functions###
##hassoc - receive env; return a pair whith the car of given symbol. ['x', 3]
def hassoc(arg, env):
if not(pair(env)):
print ("unbound var", arg)
raise Unbound()
elif car(car(env)) == arg:
return car(env)
else:
return hassoc(arg, cdr(env))
##hevlis - modify the args (replace temp-arg with real-arg) which will be given to happly. eval each unknown symbol to get its real-arg.
def hevlis(sex, env):
if num(sex):
return [sex]
if not(pair(sex)):
return [] #doubt! better check!
elif cdr(sex) == []:
return heval(car(sex), env)
elif pair(sex):
return cons(heval(car(sex), env), hevlis(cdr(sex), env))
##hpairlis - cons temp-arg and real-arg; put it into the env. returns [['X1', evaluatedY1], ['X2', evaluatedY2], ..., []] i.e.: make new env
def hpairlis(x, y, env):
new_env = []
def hpairlis_core(x, y, env):
if not(pair(x)) or not(pair(y)):
return []
elif pair(x):
new_env.append([car(x), car(y)])
hpairlis_core(cdr(x), cdr(y), env)
return new_env
return hpairlis_core(x, y, env)
##hevcon - cond
def hevcon(e, env):
if heval(car(car(e)), env):
return heval(car(cdr(car(e))), env)
else:
return hevcon(cdr(e), env)
##happly - apply the function to its args. args contains real-arg only if atom(func)
def happly(func, argls, env):
if atom(func):
if func == 'car':
return car(argls)
elif func == 'cdr':
return car(cdr(argls))
elif func == 'cons':
return cons(car(argls), car(cdr(argls)))
elif func == 'atom?':
return atom(argls)
elif func == 'eq?':
return eq(car(argls), car(cdr(argls)))
elif func == 'true':
return 1
elif func == 'exit':
exit()
elif func == 'help':
print("car cdr cons atom? eq? true exit help lambda cond + - * /")
elif pair(argls) and num(car(argls)) and num(car(cdr(argls))):
a = car(argls); b = car(cdr(argls))
if func == '+':
return a + b
elif func == '-':
return a - b
elif func == '*':
return a * b
elif func == '/':
return a / b
else:
return happly(heval(func, argls), argls, env)
elif car(func) == 'lambda': ##eval the 2nd arg with new env generated by hpairlis
if atom(argls):
argls = cons(argls, []) ##just to make it a pair
return heval(car(cdr(cdr(func))), hpairlis(car(cdr(func)), car([argls]), env))
##heval - if num: return num; if symbol: return real-arg assigned by lambda; get it through hassoc;
## if pair: call happly. return the result. this return value will be the final result.
def heval(sex, env):
if atom(sex):
if num(sex):
return sex
if sex == '' or sex == []:
return 'nil'
else:
return car(cdr(hassoc(sex, env)))
elif pair(sex):
if atom(car(sex)):
if car(sex) == 'qt':
return car(cdr(sex))
if car(sex) == 'cond':
return hevcon(cdr(sex), env) ##[[[pred?] do][[true] do]]
else:
return happly(car(sex), hevlis(cdr(sex), env), env) ##func will be atom
else:
return happly(car(sex), hevlis(cdr(sex), env), env) ##func will be pair (i.e. lambda)
return 0
###macro###
##pythonize - read normal S-expressions like ((lambda (x) x) 2); convert it to python's list like [['lambda', ['x'], 'x'], 2]
##num will be left as it is. symbols turn into strings
def pythonize(sex):
sex = sex.replace(' ', ', ').replace('(', '[').replace(')', ']')
p = re.compile(r'([^\[\]\,\d\s]\w*)')
sex = p.sub(r"'\1'", sex)
try: sex = eval(sex) ##to convert string "['+', 1, 2]" to list ['+', 1, 2]
except: print ('typo! invalid syntax'); main()
else: return sex
##lisparen - convert back the pythonized list to string and substitute '[',']', and',' to make it lisp
def lisparen (sex):
if atom(sex):
return sex
else:
return str(sex).replace(',', '').replace('[', '(').replace(']', ')')
###REPL###
def main():
env = []
sex = pythonize(raw_input('hlisp>'))
try:
result = (heval(sex, env))
except Unbound:
pass
else:
print (lisparen(result))
main()
return 0
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment