#scheme.py



#This is a implementations of an intrepreter



#for a small subset of scheme.



#



#What it has:



#Commands



# Look at the function 'eval'



#Functions



# look at the dictionary 'predefineds'



#



#Examples:



#1)Fibonacci numbers



#python scheme.py



#>>>(define fibonacci



#... (lambda (n)



#... (define fib



#... (lambda (n1 n2 cnt)



#... (if (= cnt n)



#... n1



#... (fib n2 (+ n1 n2) (+ cnt 1)))))



#... (fib 0 1 0)))



#>>>(display (fibonacci 10))



#55



#>>>



#



#2)Coroutines



#python scheme.py



#>>>(define list (lambda l l))



#>>>(define message



#... (lambda (cont msg)



#... (call/cc



#... (lambda (newCont)



#... (cont (cons newCont msg))))))



#>>>(define f



#... (lambda (fname cont msg)



#... (display (cons fname msg))



#... (define msgList (message cont (+ 1 msg)))



#... (f fname (car msgList) (cdr msgList))))



#>>>(define msg



#... (call/cc (lambda (cont)



#... (f "f1:" cont 1))))



#>>>(f "f2" (car msg) (cdr msg))



#



#Changes;



#24-Feb-2005 Added quote and the quote symbol '



#25-Feb-2005 Fixed a bug with begin



#25-Feb-2005 Added eval



#25-Feb-2005 Added py-eval and py-exec



#Uncomment the following line if you are using python 2.2



#from __future__ import generators



import

class

context

def

setVars

if

return

elif

else

def

__init__

def

get

if

return

elif

return

else

"Unknown variable "

def

set

if

elif

return

else

"Unknown variable "

def

define

class

symbol

def

__init__

def

__str__

return

def

__repr__

return

"symbol('"

"')"

def

__eq__

if

return

else

return

# Predefined Symbols (can't be redefined)



"lambda"

"if"

"begin"

"set!"

"define"

"load"

"quote"

#The tokenizer



#Token Types



0

2

3

4

5

6

'\(|\)|(?:[\w+\-*/<>=!?.]+)|'

'(?:"(?:[^"]|\\")+")|'

'(?:#(?:t|f|(?:\\(?:newline|space|.))))|'

'\''

def

tokenize

"""This is a very simple tokenizer,

it accepts a string that represents

the code an returns a list of

token type, token paris"""

for

in

if

"("

yield

elif

")"

yield

elif

"."

yield

elif

"'"

yield

elif

yield

elif

0

'"'

yield

1

1

'\\'

"\\"

'\"'

'"'

elif

0

"#"

if

1

"\\"

2

if

"space"

" "

if

"newline"

"

"

yield

elif

1

"t"

yield

elif

1

"f"

yield

else

"Invalid token "

else

yield

#S-Espressions



def

process_sexpr

if

return

elif

while

if

not

in

")"

"."

1

1

else

if

"."

1

if

")"

return

1

else

"expected close bracket for expression "

else

return

def

sexpr

return

def

sexprs

"""Build an s-expression from a string"""

try

while

1

1

except

return

1

#Pedefined Functions



#Convert a python function into a form



#suitable for the interpreter



def

predefined_function

def

func

while

return

return

#Some basic predefined functions



def

display

def

callcc

def

cont_func

return

return

def

gen_eval

def

eval_func

return

return

def

py_exec

in

return

def

py_eval

return

"+"

"*"

"-"

"<"

">"

"="

"cons"

"car"

"cdr"

"display"

"call-with-current-continuation"

"call/cc"

"eval"

"py-exec"

"py-eval"

#Eval



#A continuation for the evaluation of an expression



class

eval_continuation

def

__init__

def

run

return

def

eval_str

if

return

#The eval method



def

eval

if

if

0

return

elif

0

return

elif

0

return

elif

0

return

elif

0

return

elif

0

return

elif

0

return

else

return

elif

return

else

return

#Helper to evaluate a list of expressions



class

expr_list_continuation

def

__init__

if

else

def

run

return

def

eval_expr_list

return

#Quote



def

eval_quote

return

#Load



def

eval_load

return

#Begin



def

eval_begin

return

#Lambda



def

eval_lambda

def

func

return

return

#Define



class

define_continuation

def

__init__

def

run

return

def

eval_define

return

#set!



class

set_continuation

def

__init__

def

run

return

def

eval_set

return

#If



class

if_continuation

def

__init__

def

run

if

return

else

return

def

eval_if

if

else

0

return

#Apply



class

apply_continuation

def

__init__

def

run

return

class

param_continuation

def

__init__

def

run

return

class

list_param_continuation

def

__init__

def

run

return

def

construct_param_continuations

if

if

return

else

return

else

return

def

eval_apply

return

#The read eval loop



class

read_eval_continuation

def

__init__

def

run

try

if

except

return

return

def

expression_reader

""

0

while

if

""

">>>"

else

"..."

" "

"("

")"

if

0

and

0

yield

""

def

read_eval_loop

"Simple scheme!!!"

while

if

"__main__"

import

repy_context = {}py_eval_func = eval(self, names, values):names == None:isinstance(names, symbol):self.vars[str(names)] = values(name, restNames) = names(value, restValues) = valuesself.vars[str(name)]=valueself.setVars(restNames, restValues)(self, parent, var_names = None, values = None):self.parent = parentself.vars = {}self.setVars(var_names, values)(self, var_name):self.vars.has_key(var_name):self.vars[var_name]self.parent != None:self.parent.get(var_name)raise KeyError(+var_name)(self, var_name, value):self.vars.has_key(var_name):self.vars[var_name] = valueself.parent != None:self.parent.set(var_name, value)raise Key(+ var_name)(self, var_name, value):self.vars[var_name] = value(self, value):self.value = value(self):self.value(self):+self.value+(self, value):isinstance(value, symbol):self.value == value.valueFalseLAMBDA = symbol(IF = symbol(BEGIN = symbol(SET = symbol(DEFINE = symbol(LOAD = symbol(QUOTE = symbol(OPENBRACKET =CLOSEBRACKET =ATOM =SYMBOL =DOT =SINGLE_QUOTE =tokens_re = re.compile(r(code):tokens = tokens_re.findall(code)tokentokens:token ==(OPENBRACKET, token)token ==(CLOSEBRACKET, token)token ==(DOT, token)token ==(SINGLE_QUOTE, token)token.isdigit():(ATOM, int(token))token[]==(ATOM, token[:-].replace(r).replace(r, r))token[]==token[]==char = token[:]char ==char =char ==char =(ATOM, char)token[]==(ATOM, True)token[]==(ATOM, False)raise Exception(+ token)(SYMBOL, symbol(token))(tokens):token_type, value = tokens.next()token_type == SINGLE_QUOTE:[QUOTE, [process_sexpr(tokens), None]]token_type == OPENBRACKET:cons = [None, None]lst = constoken = NoneTrue :token = process_sexpr(tokens)token]:cons[] = [token, None]cons = cons[breaktoken ==cons[] = process_sexpr(tokens)token_type, token = tokens.next()token ==lst[raise Exception(str(lst)+token)value(text):process_sexpr(tokenize(text))(text):lst = [None, None]cur = lsttokens = tokenize(text)True:cur[] = [process_sexpr(tokens), None]cur = cur[StopIteration:passlst[(function):(continuation, args):argList = []args!=None:arg, args = argsargList.append(arg)continuation, function(*argList)func(obj):print obj(continuation, args):(func, nil) = args(cont, (arg, nil)):(continuation, arg)func(continuation, (cont_func, None))(context):(continuation, arg):expr, nil = arg(eval_continuation(continuation, context, expr), None)eval_func(continuation, arg):code, nil = argexec codepy_context(continuation, None)(continuation, arg):code, nil = arg(continuation, py_eval_func(code, py_context))global_context = context(None)predefineds = {:predefined_function(lambda *args:sum(args)),:predefined_function(lambda *args:reduce(int.__mul__, args)),:predefined_function(lambda a, b:a - b),:predefined_function(lambda a, b:a < b),:predefined_function(lambda a, b:a > b),:predefined_function(lambda a, b:a == b),:predefined_function(lambda a, b:[a, b]),:predefined_function(lambda(a, b):a),:predefined_function(lambda(a, b):b),:predefined_function(display),:callcc,:callcc,:gen_eval(global_context),:py_exec,:py_eval}global_context.vars = predefineds(self, continuation, context, expr):self.next = continuationself.context = contextself.expr = expr(self, val):eval(self.next, self.context, self.expr)(continuation, context, code):isinstance(code, str):code = sexpr(code)eval(continuation, context, code)(continuation, context, code):isinstance(code, list):code[] == LAMBDA:eval_lambda(continuation, context, code)code[] == IF:eval_if(continuation, context, code)code[]== BEGIN:eval_begin(continuation, context, code)code[] == DEFINE:eval_define(continuation, context, code)code[] == SET:eval_set(continuation, context, code)code[] == QUOTE:eval_quote(continuation, context, code)code[] == LOAD:eval_load(continuation, context, code)eval_apply(continuation, context, code)isinstance(code, symbol):(continuation, context.get(str(code)))(continuation, code)(self, continuation, context, exprs):expr, rest = exprsself.expr = exprrest == None:self.continuation = continuationself.continuation = expr_list_continuation(continuation,context, rest)self.context = context(self, value):eval(self.continuation, self.context, self.expr)(continuation, context, exprs):(expr_list_continuation(continuation, context, exprs), None)(continuation, context, code):(quote, (item, nil)) = code(continuation, item)(continuation, context, code):(load, (filepath, nil)) = codefi = file(filepath)exprs = sexprs(fi.read())eval_expr_list(continuation, context, exprs)(continuation, context, code):begin, exprs = codeeval_expr_list(continuation, context, exprs)(continuation, parent_context, code):(lmbda, (params, exprs)) = code(continuation, args):new_context = context(parent_context, params, args)eval_expr_list(continuation, new_context, exprs)(continuation, func)(self, continuation, context, var_name):self.continuation = continuationself.context = contextself.var_name = var_name(self, value):self.context.define(self.var_name, value)self.continuation, None(continuation, context, code):(define, (var_name, (expr, nil))) = codecontinuation = define_continuation(continuation,context, str(var_name))eval(continuation, context, expr)(self, continuation, context, var_name):self.continuation = continuationself.context = contextself.var_name = var_name(self, value):self.context.set(self.var_name, value)self.continuation, None(continuation, context, code):(set, (var_name, (expr, nil))) = codecontinuation = set_continuation(continuation, context,str(var_name))eval(continuation, context, expr)(self, continuation, context, ifTrue, ifFalse):self.continuation = continuationself.context = contextself.ifTrue = ifTrueself.ifFalse = ifFalse(self, value):value:eval(self.continuation,self.context, self.ifTrue)eval(self.continuation,self.context, self.ifFalse)(continuation, context, code):(If, (predicate, (ifTrue, rest))) = coderest==None:ifFalse = NoneifFalse = rest[eval(if_continuation(continuation, context, ifTrue, ifFalse),context, predicate)(self, continuation):self.continuation = continuation(self, func):func(self.continuation, self.params)(self, continuation, prev):self.continuation = continuationself.prev = prevself.params = None(self, value):self.prev.params = (value, self.params)(self.continuation, None)(self, continuation, prev):self.continuation = continuationself.prev = prev(self, value):self.prev.params = value(self.continuation, None)(continuation,prev, context, code):isinstance(code, list):expr, rest = codeparamContinuation = param_continuation(continuation, prev)continuation = eval_continuation(paramContinuation, context, expr)rest == None:continuationconstruct_param_continuations(continuation, paramContinuation,context, rest)continuation = list_param_continuation(continuation, prev)eval_continuation(continuation, context, code)(continuation, context, code):(operator, exprs) = codeapply_cont = apply_continuation(continuation)continuation = eval_continuation(apply_cont, context, operator)continuation = construct_param_continuations(continuation, apply_cont,context, exprs)(continuation, None)(self, context, reader):self.context = contextself.reader = readerself.code = Noneself.continuation = None(self, value):self.code == None:self.code = self.reader.next()self.continuation = read_eval_continuation(self.context,self.reader)StopIteration:None, valueeval_str(self.continuation, self.context, self.code)(fi):code =brackets =True:code ==prompt =prompt =ln = raw_input(prompt)code+=ln+brackets+=ln.count() - ln.count(brackets ==len(ln.strip())!=codecode =(fi):reader = expression_reader(fi)continuation = read_eval_continuation(global_context, reader)value =(continuation!=None):(continuation, value) = continuation.run(value)__name__==sysread_eval_loop(sys.stdin)