Commits

Leonardo Santagada committed 0b83548

it translates and runs very very simple programs

Comments (0)

Files changed (1)

 from __future__ import division
 import os
 
-Symbol = str
+class W_object(object):
+    pass
 
-class Env(dict):
+class W_int(W_object):
+    def __init__(self, ival):
+        self.ival = ival
+
+    def to_str(self):
+        return str(self.ival)
+
+class W_float(W_object):
+    def __init__(self, fval):
+        self.fval = fval
+
+    def to_str(self):
+        return str(self.fval)
+
+class W_list(W_object):
+    def __init__(self, lval):
+        self.lval = lval
+
+    def to_str(self):
+        return '('+' '.join([w_val.to_str() for w_val in self.lval])+')'
+
+class W_symbol(W_object):
+    def __init__(self, val):
+        self.val = val
+
+    def to_str(self):
+        return self.val
+
+class W_function(W_object):
+    def __init__(self, w_exp, w_args, env):
+        self.w_exp = w_exp
+        self.w_args = w_args
+        self.outer = env
+
+    def eval(self, exps):
+        return eval(self.w_exp, Env(self.w_args.lval, exps, self.outer))
+
+    def to_str(self):
+        return '(lambda ' + self.w_args.to_str() + self.w_exp.to_str() + ')'
+
+class W_builtin(W_function):
+    def __init__(self):
+        pass
+
+    def eval(self, exps):
+        pass
+
+    def to_str(self):
+        return '(builtin)'
+
+class W_add(W_builtin):
+    def eval(self, exps):
+        w_a = exps[0]
+        w_b = exps[1]
+        if isa(w_a, W_int) and isa(w_b, W_int):
+            return W_int(w_a.ival + w_b.ival)
+        else:
+            return W_int(0)
+
+
+class Env(object):
     "An environment: a dict of {'var':val} pairs, with an outer Env."
-    def __init__(self, parms=(), args=(), outer=None):
-        self.update(zip(parms,args))
+    def __init__(self, parms=[], args=[], outer=None):
+        self.d = {}
+        i = 0
+        while i < len(parms):
+            assert isa(parms[i], W_symbol)
+            assert isa(args[i], W_object)
+            self.d[parms[i].val] = args[i]
+            i += 1
         self.outer = outer
+
     def find(self, var):
         "Find the innermost Env where var appears."
-        return self if var in self else self.outer.find(var)
+        if var in self.d:
+            return self
+        else:
+            self.outer.find(var)
 
 def add_globals(env):
     "Add some Scheme standard procedures to an environment."
     import math, operator as op
-    env.update(vars(math)) # sin, sqrt, ...
-    env.update(
-     {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
-      '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
-      'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
-      'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
-      'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
-      'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
+    ## env.d.update(vars(math)) # sin, sqrt, ...
+    ## env.d.update(
+    ##  {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
+    ##   '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
+    ##   'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
+    ##   'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
+    ##   'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
+    ##   'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, W_symbol)})
+    env.d['+'] = W_add()
     return env
 
-global_env = add_globals(Env())
-
 isa = isinstance
 
 ################ eval
 
-def eval(x, env=global_env):
+def eval(w_x, env):
     "Evaluate an expression in an environment."
-    if isa(x, Symbol):             # variable reference
-        return env.find(x)[x]
-    elif not isa(x, list):         # constant literal
-        return x
-    elif x[0] == 'quote':          # (quote exp)
-        (_, exp) = x
-        return exp
-    elif x[0] == 'if':             # (if test conseq alt)
-        (_, test, conseq, alt) = x
-        return eval((conseq if eval(test, env) else alt), env)
-    elif x[0] == 'set!':           # (set! var exp)
-        (_, var, exp) = x
-        env.find(var)[var] = eval(exp, env)
-    elif x[0] == 'define':         # (define var exp)
-        (_, var, exp) = x
-        env[var] = eval(exp, env)
-    elif x[0] == 'lambda':         # (lambda (var*) exp)
-        (_, vars, exp) = x
-        return lambda *args: eval(exp, Env(vars, args, env))
-    elif x[0] == 'begin':          # (begin exp*)
-        for exp in x[1:]:
-            val = eval(exp, env)
-        return val
-    else:                          # (proc exp*)
-        exps = [eval(exp, env) for exp in x]
-        proc = exps.pop(0)
-        return proc(*exps)
+    if isa(w_x, W_symbol):             # variable reference
+        denv = env.find(w_x.val)
+        return denv.d[w_x.val]
+    elif not isa(w_x, W_list):         # constant literal
+        return w_x
+
+    if isa(w_x, W_list):
+        l = w_x.lval
+        if l[0].val == 'quote':          # (quote exp)
+            (_, exp) = l
+            return exp
+        elif l[0].val == 'if':             # (if test conseq alt)
+            (_, test, conseq, alt) = l
+            return eval((conseq if eval(test, env) else alt), env)
+        elif l[0].val == 'set!':           # (set! var exp)
+            (_, var, exp) = l
+            env.find(var.val).d[var.val] = eval(exp, env)
+        elif l[0].val == 'define':         # (define var exp)
+            (_, var, exp) = l
+            env.d[var.val] = eval(exp, env)
+        elif l[0].val == 'lambda':         # (lambda (var*) exp)
+            (_, vars, exp) = l
+            w_f = W_function(exp, vars, env)
+            return w_f
+        elif l[0].val == 'begin':          # (begin exp*)
+            val = W_object()
+            for exp in l[1:]:
+                val = eval(exp, env)
+            return val
+        else:                          # (proc exp*)
+            exps = [eval(exp, env) for exp in l]
+            proc = exps.pop(0)
+            return proc.eval(exps)
 
 ################ parse, read, and user interaction
 
 
 def tokenize(s):
     "Convert a string into a list of tokens."
-    return s.replace('(',' ( ').replace(')',' ) ').split()
+    tokens = []
+    intoken = False
+    token = []
+    #import pdb; pdb.set_trace()
+    for c in s:
+        if c in ['(', ')', ' ', '\n']:
+            if len(token) > 0 and intoken:
+                tokens.append(''.join(token))
+                intoken = False
+            if c in ['(', ')']:
+                tokens.append(c)
+        else:
+            if not intoken:
+                token = []
+                intoken = True
+            token.append(c)
+
+    return tokens
 
 def read_from(tokens):
     "Read an expression from a sequence of tokens."
         raise SyntaxError('unexpected EOF while reading')
     token = tokens.pop(0)
     if '(' == token:
-        L = []
+        L = W_list([])
         while tokens[0] != ')':
-            L.append(read_from(tokens))
+            L.lval.append(read_from(tokens))
         tokens.pop(0) # pop off ')'
         return L
     elif ')' == token:
 
 def atom(token):
     "Numbers become numbers; every other token is a symbol."
-    try: return int(token)
+    try: return W_int(int(token))
     except ValueError:
-        try: return float(token)
+        try: return W_float(float(token))
         except ValueError:
-            return Symbol(token)
+            return W_symbol(token)
 
 def to_string(exp):
     "Convert a Python object back into a Lisp-readable string."
-    return '('+' '.join(map(to_string, exp))+')' if isa(exp, list) else str(exp)
+    return exp.to_str()
 
-def repl(prompt='lis.py> '):
+def repl(env, prompt='lis.py> '):
     "A prompt-read-eval-print loop."
     while True:
         os.write(2,prompt)
-        val = eval(parse(readline()))
-        if val is not None: print to_string(val)
+        r = readline()
+        if r == 'quit':
+            return
+        val = eval(parse(r), env)
+        if val is not None: os.write(2, to_string(val) + '\n')
 
 def readline():
     result = []
     return "".join(result)
 
 def main(args):
-    repl()
+    global_env = add_globals(Env())
+    repl(env = global_env)
+    return 0
 
 def target(*args):
     return main, None