import re import sys import traceback from io import StringIO from ucb import main, trace from scheme_tokens import * from scheme_utils import * from scheme_primitives import * class EnvironFrame: """An environment frame, representing a mapping from Scheme symbols to Scheme values, possibly enclosed within another frame.""" def __init__(self, enclosing): """An empty frame that is attached to the frame ENCLOSING.""" self.inner = {} self.enclosing = enclosing def __getitem__(self, sym): return self.find(sym).inner[sym] def __setitem__(self, sym, val): self.find(sym).inner[sym] = val def __repr__(self): if self.enclosing is None: return "".format(hex(id(self))) else: return " {1}>".format(hex(id(self)), repr(self.enclosing)) def find(self, sym): """The environment frame at or enclosing SELF that defined SYM. It is an error if it does not exist.""" e = self while e is not None: if sym in e.inner: return e e = e.enclosing raise SchemeError("unknown identifier: {0}".format(str(sym))) def define(self, sym, val): """Define Scheme symbol SYM to have value VAL in SELF.""" self.inner[sym] = val def call_with_input_file(filename, proc): """Temporarily set the current input port to the file named by FILENAME, (a string) and call PROC. Always restores the input port when done.""" with scheme_open(filename) as inp: call_with_input_source(inp, proc) def call_with_input_source(source, proc): """Temporarily set the current input port to read lines from the SOURCE (an iterator returning lines or a string). Always restores the input port when done.""" global input_port input_port0 = input_port try: input_port = Buffer(tokenize_lines(source)) proc() finally: input_port = input_port0 def read(): if input_port.current is None: return THE_EOF_OBJECT syntax, val = input_port.pop() if syntax == NUMERAL: return Number(val) elif syntax == BOOLEAN: return boolify(val) elif syntax == SYMBOL: return Symbol.string_to_symbol(val) elif syntax == "(": exprs = [] while input_port.current \ and input_port.current[0] not in [')', '.']: exprs.append(read()) if input_port.current is None: raise SchemeError("unexpected EOF") if input_port.current[0] == '.': input_port.pop() result = read() if result is THE_EOF_OBJECT: raise SchemeError("unexpected EOF") else: result = NULL if input_port.current is None: raise SchemeError("unexpected EOF") syntax, val = input_port.pop() if syntax != ')': raise SchemeError("unexpected token: {0} (expecting ')')"\ .format(val)) for i in range(1, len(exprs)+1): result = Pair(exprs[-i], result) return result else: raise SchemeError("unexpected token: {0}".format(repr(val))) input_port = None