Created
December 10, 2011 06:31
-
-
Save ympbyc/1454699 to your computer and use it in GitHub Desktop.
リポジトリにするほどのもんでもないためgistに退避。リポジトリは消す
This file contains 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
#!/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