def expandQuasiquotation(exp, depth=1): """Takes a quasiquoted expression and constructs a new quoted expression. FIXME: this function is SO evil. *grin* Must clean this up. """ if not pair.isList(exp): return makeQuoted(exp) if isUnquoted(exp): if depth == 1: return textOfUnquotation(exp) else: return pair.list( Symbol("list"), makeQuoted(Symbol("unquote")), expandQuasiquotation(textOfUnquotation(exp), depth - 1)) if isQuasiquoted(exp): return pair.list( Symbol("list"), makeQuoted(Symbol("quasiquote")), expandQuasiquotation(textOfUnquotation(exp), depth + 1)) else: return pair.cons( Symbol("list"), pair.listMap(lambda subexp: expandQuasiquotation(subexp, depth), exp))
def testVarArgs(self): self.pe("(define (mylist . args) args)") self.assertEquals(parser.parse("(1 2 3)"), self.pe("(mylist 1 2 3)")) self.pe("""(define (list2 a b . c) (list a b c))""") self.assertEquals(pair.list(1, 2, pair.list()), self.pe("(list2 1 2)"))
def testAnotherQuasiquote(self): self.pe("(define x 42)") self.assertEquals(42, self.pe("x")) self.assertEquals( pair.list(Symbol("x"), pair.list(Symbol("quote"), pair.list(Symbol("x"), 42))), self.pe("`(x '(x ,x))"))
def OR_handler(exp): """We have to consider three cases: (OR) ===> #t (OR e1) ===> e1 (OR e1 e2 ...) ===> (let ((temp-val e1)) (IF temp-val temp-val (OR e2 ...))) ===> ((lambda (temp-val) (IF temp-val temp-val (OR e2 ...))) e1) """ clauses = and_clauses(exp) if pair.length(clauses) == 0: return symbol.true elif pair.length(clauses) == 1: return pair.car(clauses) else: temporarySymbol = symbol.makeUniqueTemporary() lambdaVal = expressions.makeLambda( pair.list(temporarySymbol), pair.list(expressions.makeIf(temporarySymbol, temporarySymbol, makeOr(pair.cdr(clauses))))) return expressions.makeApplication( lambdaVal, pair.list(pair.car(clauses)))
def testAnotherQuasiquote(self): self.pe("(define x 42)") self.assertEquals(42, self.pe("x")) self.assertEquals(pair.list (Symbol("x"), pair.list(Symbol("quote"), pair.list(Symbol("x"), 42))), self.pe("`(x '(x ,x))"))
def testQuotation(self): self.assertEquals(pair.list(Symbol("quote"), Symbol("atom-man")), parse("'atom-man")) self.assertEquals(pair.list(Symbol("quasiquote"), Symbol("istanbul")), parse("`istanbul")) self.assertEquals( pair.list(Symbol("unquote"), Symbol("constantinople")), parse(",constantinople"))
def testStressWithSuperNesting(self): ## An evil test to see if this raises bad errors. N = 1000 bigNestedList = pair.list() for ignored in xrange(N - 1): bigNestedList = pair.list(bigNestedList) try: self.assertEquals(bigNestedList, parse("(" * N + ")" * N)) except RuntimeError, e: self.fail(e)
def testQuotation(self): self.assertEquals(pair.list(Symbol("quote"), Symbol("atom-man")), parse("'atom-man")) self.assertEquals(pair.list(Symbol("quasiquote"), Symbol("istanbul")), parse("`istanbul")) self.assertEquals(pair.list(Symbol("unquote"), Symbol("constantinople")), parse(",constantinople"))
def testStressWithSuperNesting(self): ## An evil test to see if this raises bad errors. N = 1000 bigNestedList = pair.list() for ignored in xrange(N-1): bigNestedList = pair.list(bigNestedList) try: self.assertEquals(bigNestedList, parse( "(" * N + ")" * N)) except RuntimeError, e: self.fail(e)
def testQuasiquotation(self): self.pe("(define one 1)") self.pe("(define two 2)") self.pe("(define three 3)") self.assertEquals(pair.list(Symbol("one"), Symbol("two"), 3), self.pe("`(one two ,three)")) self.assertEquals( pair.list(Symbol("one"), Symbol("two"), (pair.list(Symbol("unquote"), Symbol("three")))), self.pe("'(one two ,three)")) ## this evil case occurs in R5RS self.assertEquals(parser.parse("(a `(b ,(+ 1 2) ,(foo 4 d) e) f)"), self.pe("`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)"))
def setUp(self): ## We set up a VERY minimal environment here for some tests. ## We also set the recursion limit to something dreadful to see that ## call/cc is doing the right thing. ## ## Note: these tests directly work with analyzer.eval, and not ## through the nicer scheme.AnalyzingInterpreter interface. self.env = extendEnvironment(pair.list(Symbol('pi')), pair.list(3.1415926), THE_EMPTY_ENVIRONMENT) defineVariable(Symbol("#t"), Symbol("#t"), self.env) defineVariable(Symbol("#f"), Symbol("#f"), self.env) self.old_recursion_limit = sys.getrecursionlimit() sys.setrecursionlimit(100)
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 __expr(self, *follow): ''' expr: head binexpr* : head binexpr* "." expr : head binexpr* ":" expr : head binexpr* ":" EOL block ''' head = self.__head(T.DOT, T.DOTS, *follow) args = self.match_loop(self.__binexpr, T.DOT, T.DOTS, *follow) body = head.append(args) if self.peek in follow: if len(body) == 1: return body.car() # remove extra parens return body if self.peek == T.DOT: self.match(T.DOT) more = self.__expr(*follow) elif self.peek == T.DOTS: self.match(T.DOTS) if self.try_match(T.EOL): more = self.__block() else: more = list(self.__expr(*follow)) else: raise RuntimeError('internal error') return body.append(more)
def schemeCallcc(self, cont, env, args): analyzedLambdaBody = args[0] def c2(val): return pogo.bounce(cont, val) cont_procedure = expressions.makeContinuationProcedure(c2) return analyzer.apply(analyzedLambdaBody, pair.list(cont_procedure), env, cont)
def __unexpr(self): ''' unexpr: atom UNOP* ''' expr = self.__atom() while self.peek == T.UNOP: expr = list(expr, lx.S(self.match(T.UNOP))) return expr
def testQuasiquotation(self): self.pe("(define one 1)") self.pe("(define two 2)") self.pe("(define three 3)") self.assertEquals(pair.list(Symbol("one"), Symbol("two"), 3), self.pe("`(one two ,three)")) self.assertEquals(pair.list(Symbol("one"), Symbol("two"), (pair.list (Symbol("unquote"), Symbol("three")))), self.pe("'(one two ,three)")) ## this evil case occurs in R5RS self.assertEquals(parser.parse("(a `(b ,(+ 1 2) ,(foo 4 d) e) f)"), self.pe("`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)"))
def __atom(self, *extra): ''' atom : NAME : DEC : DECF : HEX : STR : HEREDOC : "(" expr ")" : "[" expr "]" : "'" atom ''' if self.peek == T.LPAR: self.match(T.LPAR) expr = self.__expr(T.RPAR) self.match(T.RPAR) return expr if self.peek == T.LSQU: self.match(T.LSQU) expr = self.__expr(T.RSQU) self.match(T.RSQU) return list(lx.S('bracket'), expr) if self.peek == T.QUOTE: self.match(T.QUOTE) atom = self.__atom() return list(lx.S('quote'), atom) type, lexeme, pos = self.xmatch(T.DEC, T.DECF, T.HEX, T.NAME, T.STR, T.HEREDOC, *extra) if type == T.DEC: return lx.Integer(lexeme) if type == T.HEX: return lx.Integer(lexeme, 16) if type == T.NAME: return lx.S(lexeme) if type == T.STR: return lx.String(unescape(lexeme[1:-1], pos)).setpos(pos) if type == T.DECF: return lx.Decimal(lexeme) if type == T.HEREDOC: return lx.ForeignString(lexeme).setpos(pos) return lx.S(lexeme)
def __head(self, *follow): ''' head: : BINOP UNOP* [BINOP] : atom UNOP* [BINOP] ''' if self.peek in follow: return nil head = self.__atom(T.BINOP) if self.peek not in (T.BINOP, T.UNOP): return list(head) while self.peek in (T.UNOP): head = list(head, lx.S(self.match(T.UNOP))) if self.peek in (T.BINOP): head = list(head, lx.S(self.match(T.BINOP))) return head
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 __binexpr(self): ''' binexpr: unexpr : unexpr BINOP binexpr ''' left = self.__unexpr() if self.peek != T.BINOP: return left message = lx.S(self.match(T.BINOP)) right = self.__binexpr() return list(left, message, right)
def makeIf(predicate, consequent, alternative): return pair.list(Symbol("if"), predicate, consequent, alternative)
def testNullList(self): self.assertEquals("()", toString(pair.list())) self.assertEquals("(() ())", toString(pair.list(pair.list(), pair.list())))
def testSimpleListExpressionToString(self): self.assertEquals("(x)", toString(pair.list(Symbol("x")))) self.assertEquals("(1 2)", toString(pair.list(1, 2))) self.assertEquals("(1 (2) 3)", toString(pair.list(1, pair.list(2), 3)))
def makeContinuationProcedure(proc): """Procedure is defined to be a function that takes a single 'val' argument.""" return pair.list(Symbol("continuation"), proc)
def makeProcedure(parameters, body, env): return pair.list(Symbol("procedure"), parameters, body, env)
def makeLambda(parameters, body): return pair.append(pair.list(Symbol("lambda"), parameters), body)
def testDir(self): self.assertEquals(pair.list(), self.pe("((lambda () (dir)))")) self.assertEquals(pair.list(Symbol("x")), self.pe("((lambda (x) (dir)) 42)"))
def testNullList(self): self.assertEquals("()", toString(pair.list())) self.assertEquals("(() ())", toString( pair.list(pair.list(), pair.list())))
def runNonInteractive(interp, args): """Executes the interpreter on args[0].""" interp.eval(pair.list(symbol.Symbol("load"), args[0]))
def testQuotedList(self): self.assertEquals( pair.list(Symbol("quote"), pair.list(Symbol("foo"), Symbol("bar"))), parse("'(foo bar)"))
def testQuotation(self): self.assertEquals(pair.list(Symbol("foo"), Symbol("bar")), self.pe("'(foo bar)"))
def testLists(self): self.assertEquals(pair.list(1, 2), parse("(1 2)")) self.assertEquals(pair.list(1, 2, pair.list(3), 4), parse("(1 2 (3) 4)")) self.assertEquals(pair.list(pair.list(pair.list())), parse("((()))"))
def testQuotedList(self): self.assertEquals(pair.list(Symbol("quote"), pair.list(Symbol("foo"), Symbol("bar"))), parse("'(foo bar)"))
def testSimpleListExpressionToString(self): self.assertEquals("(x)", toString(pair.list(Symbol("x")))) self.assertEquals("(1 2)", toString(pair.list(1, 2))) self.assertEquals("(1 (2) 3)", toString( pair.list(1, pair.list(2), 3)))
def makeDefinition(var, val): return pair.list(Symbol("define"), var, val)
def testSelfEvaluating(self): self.assertEquals(42, self.pe("42")) self.assertEquals(pair.list(), self.pe("()"))
def testQuotation(self): self.assertEquals(Symbol("foobar"), self.pe("'foobar")) self.assertEquals(Symbol("foobar"), self.pe("'foobar")) self.assertEquals(pair.list(1, 2, 3), self.pe("'(1 2 3)"))
def makePrimitiveProcedure(proc): return pair.list(Symbol("primitive"), proc)
def makeQuoted(exp): return pair.list(Symbol("quote"), exp)
def constructEvilNestedExpression(self, n): result = pair.list() for i in xrange(n - 1): result = pair.list(result) return result
def constructEvilNestedExpression(self, n): result = pair.list() for i in xrange(n-1): result = pair.list(result) return result
def c(expr): return pogo.bounce(cont, pair.list(Symbol(quoteType), expr))
def letBindingValues(bindings): if pair.isNull(bindings): return pair.list() return pair.cons(pair.cadr(pair.car(bindings)), letBindingValues(pair.cdr(bindings)))
def makeAssignment(var, val): return pair.list(Symbol("set!"), var, val)
def get_environment(self): return environment.extendEnvironment(pair.list(), pair.list(), environment.THE_EMPTY_ENVIRONMENT)