Skip to content

Commit

Permalink
First real progress on #4, after extensive prep/refactoring.
Browse files Browse the repository at this point in the history
  • Loading branch information
eigenhombre committed Jul 22, 2022
1 parent d3bf45f commit 8663847
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 24 deletions.
29 changes: 15 additions & 14 deletions smallscheme/dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,27 @@ def value(x):
noop = 'nop', None

def printable_value(ast):
k, v = ast
if k == 'int' or k == 'float':
return str(v)
if k == 'bool':
typ, val = typeof(ast), value(ast)
if typ == 'int' or typ == 'float':
return str(val)
if typ == 'bool':
return {True: "#t",
False: "#f"}.get(v)
if k == 'intproc':
return "Internal procedure '%s'" % v
if k == 'atom':
return v
if k == 'list':
False: "#f"}.get(val)
if typ == 'intproc':
return "Internal procedure '%s'" % val
if typ == 'atom':
return val
if typ == 'list':
return '(' + ' '.join([printable_value(x)
for x in v]) + ')'
if k == 'nop':
for x in val]) + ')'
if typ == 'nop':
return ''
if k == 'fn':
(fn_name, _, _) = v
if typ == 'fn':
(fn_name, _, _) = val
if fn_name == 'lambda':
return "Anonymous-function"
return "Function-'%s'" % str(fn_name)

raise Exception('Unprintable ast "%s"' % str(ast))

QUOTE = atom('quote')
Expand Down
32 changes: 32 additions & 0 deletions smallscheme/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Env(object):
"""
Provide a nested series of environments to look things up in. If
it's not found in the current environment, look in the parent, or
its parent(s). The idea is explained well in SICP, Chapter 4.
"""
def __init__(self, parent=None):
self.__values = {}
self.__parent = parent

def __setitem__(self, k, v):
self.__values[k] = v

def __getitem__(self, k):
if k in self.__values:
return self.__values[k]
elif self.__parent is not None:
return self.__parent[k]

def copy(self):
ret = Env(self.__parent)
for k, v in self.__values.items():
ret[k] = v
return ret

def __contains__(self, k):
if k in self.__values:
return True
elif self.__parent:
return k in self.__parent
else:
return False
3 changes: 2 additions & 1 deletion smallscheme/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import sys
import argparse
from smallscheme.env import Env
from smallscheme.scheme import evalu, repl, parse_str

def run_file(filename):
env = {}
env = Env()
with open(filename) as f:
txt = f.read()
for p in parse_str(txt):
Expand Down
18 changes: 9 additions & 9 deletions smallscheme/scheme.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
import sys
from smallscheme.env import Env
from smallscheme.parse import parse_str
from smallscheme.dtypes import *
from smallscheme.builtin import dispatch_table
Expand All @@ -9,17 +10,16 @@ def intern(env, atom_name, item):

def apply(fn_form, args, env):
(maybe_fn, (fn_name, arg_names, body)) = fn_form
if maybe_fn != 'fn':
raise Exception('Malformed function definition "%s"!'
% env[fn_name])
# THIS IS WRONG. If env changes....
new_env = env.copy()
for i, x in enumerate(arg_names):
intern(new_env, x[1], args[i])
assert typeof(fn_form) == 'fn'
# FIXME: store env with lambda definition, for lexical closures.
new_env = Env(env)
for nam, arg in zip(arg_names, args):
assert typeof(nam) == 'atom'
intern(new_env, value(nam), arg)
ret = None
for form in body:
ret = evalu(form, new_env)
return ret # Last result is returned
return ret # Last result is returned, or None if none

def truthy(x):
return x != FALSE
Expand Down Expand Up @@ -135,7 +135,7 @@ def inp():
return raw_input("scheme> ")

def repl():
env = {}
env = Env()
while True:
try:
x = inp().strip()
Expand Down
32 changes: 32 additions & 0 deletions smallscheme/test_env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from smallscheme.dtypes import *
from smallscheme.env import Env

def test_env():
outer = Env()
outer['a'] = int_(0)
assert 'a' in outer
assert 'b' not in outer
assert outer['a'] == int_(0)

inner = Env(outer)
assert 'a' in inner
assert 'b' not in inner
assert inner['a'] == int_(0)

inner['c'] = int_(1)
assert 'c' in inner
assert 'c' not in outer
assert inner['c'] == int_(1)

outer['d'] = int_(2)
assert 'd' in outer
assert 'd' in inner
assert inner['d'] == int_(2)

# Overriding higher-level (global) env with
# inner scope:
inner['a'] = int_(3)
assert 'a' in outer
assert 'a' in inner
assert inner['a'] == int_(3)
assert outer['a'] == int_(0)

0 comments on commit 8663847

Please sign in to comment.