def t_atomExpressionToString(expr, cont): """Converts an atomic expression (string, number) to a string. Written in CPS/trampolined form.""" if type(expr) is str and quoteStrings: return pogo.bounce(cont, "\"%s\"" % expr.replace('"', '\\"')) else: return pogo.bounce(cont, str(expr))
def teval(exp, env, cont): """Evaluates an expression 'exp' in an environment 'env'. Exercise 4.3 asks us to rewrite this in a more natural data-directed manner. Pychecker, also, doesn't like seeing so many 'return' statements in one function. *grin* """ if expressions.isSelfEvaluating(exp): return pogo.bounce(cont, exp) if expressions.isVariable(exp): return pogo.bounce(cont, environment.lookupVariableValue(exp, env)) if expressions.isQuoted(exp): return evalQuoted(exp, env, cont) if expressions.isAssignment(exp): return evalAssignment(exp, env, cont) if expressions.isDefinition(exp): return evalDefinition(exp, env, cont) if expressions.isIf(exp): return evalIf(exp, env, cont) if expressions.isLambda(exp): return pogo.bounce(cont, expressions.makeProcedure (expressions.lambdaParameters(exp), expressions.lambdaBody(exp), env)) if expressions.isBegin(exp): return evalSequence(expressions.beginActions(exp), env, cont) if expressions.isApplication(exp): return evalApplication(exp, env, cont) raise SchemeError, "Unknown expression type -- eval " + str(exp)
def teval(exp, env, cont): """Evaluates an expression 'exp' in an environment 'env'. Exercise 4.3 asks us to rewrite this in a more natural data-directed manner. Pychecker, also, doesn't like seeing so many 'return' statements in one function. *grin* """ if expressions.isSelfEvaluating(exp): return pogo.bounce(cont, exp) if expressions.isVariable(exp): return pogo.bounce(cont, environment.lookupVariableValue(exp, env)) if expressions.isQuoted(exp): return evalQuoted(exp, env, cont) if expressions.isAssignment(exp): return evalAssignment(exp, env, cont) if expressions.isDefinition(exp): return evalDefinition(exp, env, cont) if expressions.isIf(exp): return evalIf(exp, env, cont) if expressions.isLambda(exp): return pogo.bounce( cont, expressions.makeProcedure(expressions.lambdaParameters(exp), expressions.lambdaBody(exp), env)) if expressions.isBegin(exp): return evalSequence(expressions.beginActions(exp), env, cont) if expressions.isApplication(exp): return evalApplication(exp, env, cont) raise SchemeError, "Unknown expression type -- eval " + str(exp)
def c_listMap(c_f, p, cont, allow_improper_lists=False): """Maps a function f across p, but in a continuation-passed style. 'c_f' is a function that takes a 2-tuple (element, cont), the element and the continuation. 'cont' is the continutation we apply on the mapped list. If the optional keyword parameter 'allow_improper' is set to True, then we'll also allow mapping across improper lists. """ if isNull(p): return pogo.bounce(cont, NIL) if not isPair(p): if allow_improper_lists: return pogo.bounce(c_f, p, cont) else: raise SchemeError, "CMAP --- not a list" def c_head(head_val): def c_tail(tail_val): return pogo.bounce(cont, cons(head_val, tail_val)) return pogo.bounce(c_listMap, c_f, cdr(p), c_tail, allow_improper_lists) return pogo.bounce(c_f, car(p), c_head)
def c_appendTwo(front, back, cont): """Appends two lists together. Written in continuation passing style.""" if not isList(front): raise SchemeError, "MAP --- not a list" if not isList(back): raise SchemeError, "MAP --- not a list" if isNull(front): return pogo.bounce(cont, back) def c(appendedRest): return pogo.bounce(cont, cons(car(front), appendedRest)) return pogo.bounce(c_appendTwo, cdr(front), back, c)
def parseAtom(tokens, cont): """Returns an Atom, given a sequence of tokens. An atom is either a number, a symbol, or a string.""" if peek(tokens)[0] == 'number': return pogo.bounce(cont, toNumber(eat(tokens, 'number')[1])) elif peek(tokens)[0] == 'symbol': return pogo.bounce(cont, Symbol(eat(tokens, 'symbol')[1])) elif peek(tokens)[0] == 'string': return pogo.bounce(cont, eat(tokens, 'string')[1]) else: raise ParserError, "While parsing Atom: no alternatives."
def evalQuoted(exp, env, cont): """Returns a quoted expression, using deepQuotedEval to look for UNQUOTE. Consequently, quoted elements are properly turned into cons pairs. """ text = expressions.textOfQuotation(exp) if expressions.isQuasiquoted(exp): expandedExp = expressions.expandQuasiquotation(text) return pogo.bounce(teval, expandedExp, env, cont) else: return pogo.bounce(cont, text)
def t_expressionToString(expr, cont): """Helper function for toString: written in CPS/trampolined form to avoid growing control context.""" if id(expr) in seenExpressionIds: return pogo.bounce(cont, "[...]") if pair.isNull(expr): return pogo.bounce(cont, "()") if not pair.isPair(expr): return t_atomExpressionToString(expr, cont) elif isPrimitiveProcedure(expr) or isCompoundProcedure(expr): return t_procedureExpressionToString(expr, cont) else: return t_pairExpressionToString(expr, cont)
def t_expand(self, expr, cont): """Trampolined expander.""" if not pair.isList(expr): return pogo.bounce(cont, expr) handler = self._handlers.get(self.get_keyword_tag(expr), None) if handler: ## expand, and recursively call expansion again. return pogo.bounce(self.t_expand, handler(expr), cont) elif self.is_special_form(expr): return pogo.bounce(self.t_expand_special_form, expr, cont) else: ## We recursively expand all the subexpressions by mapping ## t_expand() across the elements. return pogo.bounce(pair.c_listMap, self.t_expand, expr, cont)
def parseExpressionStar(tokens, cont): """Tries to eat as many expressions as it can see.""" START_EXPR_SET = ('\'', '`', ',', '(', 'number', 'symbol', 'string') if peek(tokens) == ('symbol', '.'): ## Handle dotted pairs eat(tokens, "symbol") return pogo.bounce(parseExpression, tokens, cont) elif peek(tokens)[0] in START_EXPR_SET: def c_first_eaten(firstVal): def c_rest_eaten(restVal): return pogo.bounce(cont, pair.cons(firstVal, restVal)) return pogo.bounce(parseExpressionStar, tokens, c_rest_eaten) return pogo.bounce(parseExpression, tokens, c_first_eaten) else: return pogo.bounce(cont, pair.NIL)
def schemeDir(self, cont, env, args): """A quick function to inspect the first frame.""" if len(args) != 0: raise TypeError, ("dir expected at most 0 arguments, got %s" % len(args)) names = environment.firstFrame(env).keys() names.sort() return pogo.bounce(cont, pair.list(*names))
def parseList(tokens, cont): """Parses a parenthesized list expression.""" eat(tokens, "(") def c_expressionsEaten(val): eat(tokens, ")") return pogo.bounce(cont, val) return pogo.bounce(parseExpressionStar, tokens, c_expressionsEaten)
def t_expand_define(self, expr, cont): variable = expressions.definitionVariable(expr) value = expressions.definitionValue(expr) def c_expanded(expandedValue): return pogo.bounce( cont, expressions.makeDefinition(variable, expandedValue)) return pogo.bounce(self.t_expand, value, c_expanded)
def t_pairExpressionToString(expr, cont): """Converts a pair expression to a string.""" pieces = [] def loop(loop_exp, loop_cont): if pair.isNull(loop_exp): return pogo.bounce(loop_cont, pieces) elif pair.isDottedPair(loop_exp) or isLoopyPair(loop_exp): def c_car(carString): def c_cdr(cdrString): pieces.append(carString) pieces.append(".") pieces.append(cdrString) return pogo.bounce(loop_cont, pieces) return t_expressionToString(pair.cdr(loop_exp), c_cdr) return t_expressionToString(pair.car(loop_exp), c_car) else: def c_car(carString): pieces.append(carString) return pogo.bounce(loop, pair.cdr(loop_exp), loop_cont) return pogo.bounce(t_expressionToString, pair.car(loop_exp), c_car) markExprAsSeen(expr) return loop(expr, lambda pieces: pogo.bounce(cont, '(' + ' '.join(pieces) + ')'))
def t_expand_setbang(self, expr, cont): variable = expressions.assignmentVariable(expr) value = expressions.assignmentValue(expr) def c_expanded(expandedValue): return pogo.bounce( cont, expressions.makeAssignment(variable, expandedValue)) return pogo.bounce(self.t_expand, value, c_expanded)
def analyzed(env, cont): def c(predicateVal): if expressions.isTrue(predicateVal): return pogo.bounce(analyzedConsequent, env, cont) else: return pogo.bounce(analyzedAlternative, env, cont) return pogo.bounce(analyzedPredicate, env, c)
def t_pairExpressionToString(expr, cont): """Converts a pair expression to a string.""" pieces = [] def loop(loop_exp, loop_cont): if pair.isNull(loop_exp): return pogo.bounce(loop_cont, pieces) elif pair.isDottedPair(loop_exp) or isLoopyPair(loop_exp): def c_car(carString): def c_cdr(cdrString): pieces.append(carString) pieces.append(".") pieces.append(cdrString) return pogo.bounce(loop_cont, pieces) return t_expressionToString(pair.cdr(loop_exp), c_cdr) return t_expressionToString(pair.car(loop_exp), c_car) else: def c_car(carString): pieces.append(carString) return pogo.bounce(loop, pair.cdr(loop_exp), loop_cont) return pogo.bounce(t_expressionToString, pair.car(loop_exp), c_car) markExprAsSeen(expr) return loop( expr, lambda pieces: pogo.bounce(cont, '(' + ' '.join(pieces) + ')'))
def t_expand_lambda(self, expr, cont): parameters = expressions.lambdaParameters(expr) body = expressions.lambdaBody(expr) def c_expanded(expandedBody): return pogo.bounce(cont, expressions.makeLambda(parameters, expandedBody)) return pogo.bounce(self.t_expand, body, c_expanded)
def c_conseq(consequent_value): def c_altern(alternative_value): return pogo.bounce(cont, expressions.makeIf(pred_value, consequent_value, alternative_value)) return pogo.bounce(self.t_expand, altern, c_altern)
def analyzeQuoted(exp): text = expressions.textOfQuotation(exp) ## the common case is to handle simple quotation. if not expressions.isQuasiquoted(exp): return (lambda env, cont: pogo.bounce(cont, text)) else: return analyze(expressions.expandQuasiquotation(text))
def execRands(rands, env, cont): """Executes each operand and constructs a new list.""" def eval_first_cont(headVal): def eval_rest_cont(tailVal): return pogo.bounce(cont, pair.cons(headVal, tailVal)) return execRands(expressions.restOperands(rands), env, eval_rest_cont) if pair.isNull(rands): return pogo.bounce(cont, pair.NIL) return texec(expressions.firstOperand(rands), env, eval_first_cont)
def loop(loop_exp, loop_cont): if pair.isNull(loop_exp): return pogo.bounce(loop_cont, pieces) elif pair.isDottedPair(loop_exp) or isLoopyPair(loop_exp): def c_car(carString): def c_cdr(cdrString): pieces.append(carString) pieces.append(".") pieces.append(cdrString) return pogo.bounce(loop_cont, pieces) return t_expressionToString(pair.cdr(loop_exp), c_cdr) return t_expressionToString(pair.car(loop_exp), c_car) else: def c_car(carString): pieces.append(carString) return pogo.bounce(loop, pair.cdr(loop_exp), loop_cont) return pogo.bounce(t_expressionToString, pair.car(loop_exp), c_car)
def evalRands(exps, env, cont): """Given a list of expressions, returns a new list containing the values of evaluating each on of them. If the continuation is given, then calls cont() on the evaluated operands instead.""" def c1(head_val): def c2(tail_val): return pogo.bounce(cont, pair.cons(head_val, tail_val)) return evalRands(expressions.restOperands(exps), env, c2) if expressions.isNoOperands(exps): return pogo.bounce(cont, pair.list()) return teval(expressions.firstOperand(exps), env, c1)
def t_expand_if(self, expr, cont): pred = expressions.ifPredicate(expr) consq = expressions.ifConsequent(expr) altern = expressions.ifAlternative(expr) def c_pred(pred_value): def c_conseq(consequent_value): def c_altern(alternative_value): return pogo.bounce(cont, expressions.makeIf(pred_value, consequent_value, alternative_value)) return pogo.bounce(self.t_expand, altern, c_altern) return pogo.bounce(self.t_expand, consq, c_conseq) return pogo.bounce(self.t_expand, pred, c_pred)
def testContinuationMapping(self): def c_square(x, cont): return pogo.bounce(cont, x**2) self.assertEquals(cons(4, 9), pogo.pogo(c_listMap(c_square, cons(2, 3), pogo.land, allow_improper_lists=True))) self.assertRaises(SchemeError, pogo.pogo, pogo.bounce(c_listMap, c_square, cons(2, 3), pogo.land)) self.assertEquals(list(1, 4, 9, 16), pogo.pogo(c_listMap(c_square, list(1, 2, 3, 4), pogo.land)))
def t_procedureExpressionToString(expr, cont): """Converts a procedure expression to a string.""" if isPrimitiveProcedure(expr): return pogo.bounce(cont, ('(%s %s <procedure-env>)') % ( Symbol('primitive-procedure'), primitiveImplementation(expr))) elif isCompoundProcedure(expr): def c_parameters(parameterString): def c_body(bodyString): return pogo.bounce(cont, '(%s %s %s <procedure-env>)' % (Symbol('compound-procedure'), parameterString, bodyString)) return t_expressionToString(procedureBody(expr), c_body) return t_expressionToString(procedureParameters(expr), c_parameters)
def testContinuationMapping(self): def c_square(x, cont): return pogo.bounce(cont, x**2) self.assertEquals( cons(4, 9), pogo.pogo( c_listMap(c_square, cons(2, 3), pogo.land, allow_improper_lists=True))) self.assertRaises( SchemeError, pogo.pogo, pogo.bounce(c_listMap, c_square, cons(2, 3), pogo.land)) self.assertEquals( list(1, 4, 9, 16), pogo.pogo(c_listMap(c_square, list(1, 2, 3, 4), pogo.land)))
def t_procedureExpressionToString(expr, cont): """Converts a procedure expression to a string.""" if isPrimitiveProcedure(expr): return pogo.bounce( cont, ('(%s %s <procedure-env>)') % (Symbol('primitive-procedure'), primitiveImplementation(expr))) elif isCompoundProcedure(expr): def c_parameters(parameterString): def c_body(bodyString): return pogo.bounce( cont, '(%s %s %s <procedure-env>)' % (Symbol('compound-procedure'), parameterString, bodyString)) return t_expressionToString(procedureBody(expr), c_body) return t_expressionToString(procedureParameters(expr), c_parameters)
def c_expanded(expandedBody): return pogo.bounce(cont, expressions.makeLambda(parameters, expandedBody))
def c_expressionsEaten(val): eat(tokens, ")") return pogo.bounce(cont, val)
def c_expanded(expandedValue): return pogo.bounce( cont, expressions.makeAssignment(variable, expandedValue))
def t_expand_quote(self, expr, cont): if expressions.isQuasiquoted(expr): expandedExp = expressions.expandQuasiquotation(text) return pogo.bounce(self.t_expand, expandedExp, cont) else: return pogo.bounce(cont, expr)
def c(expr): return pogo.bounce(cont, pair.list(Symbol(quoteType), expr))
def c(expression): eat(tokens, None) return pogo.bounce(cont, expression)
def newPrimitive(cont, env, args): return pogo.bounce(cont, (f(*args)))
def wrapped(cont, env, args): if not shallow: args = [self.toscheme(arg) for arg in args] return pogo.bounce(cont, (meth(*args)))
def c_first_eaten(firstVal): def c_rest_eaten(restVal): return pogo.bounce(cont, pair.cons(firstVal, restVal)) return pogo.bounce(parseExpressionStar, tokens, c_rest_eaten)
def c_car(carString): pieces.append(carString) return pogo.bounce(loop, pair.cdr(loop_exp), loop_cont)
def c_cdr(cdrString): pieces.append(carString) pieces.append(".") pieces.append(cdrString) return pogo.bounce(loop_cont, pieces)
def c_expanded(expanded_actions): return pogo.bounce(cont, expressions.sequenceToExp(expanded_actions))
def c_body(bodyString): return pogo.bounce( cont, '(%s %s %s <procedure-env>)' % (Symbol('compound-procedure'), parameterString, bodyString))
def c_rest_eaten(restVal): return pogo.bounce(cont, pair.cons(firstVal, restVal))