def cond(self, scope, args): for i in xrange(len(args)): sexp = args[i] if not types.is_list(sexp): raise LispException("argument %d of cond must be list, is %s" % (i + 1, types.type_name(sexp))) if types.is_nil(sexp) or types.is_nil(sexp.cdr): raise LispException("argument %d of cond must have a length of >= 2" % (i + 1)) for rule in args: test = self.rt.eval(scope, rule.car) if test != types.true and test != types.false: raise LispException("expr %s does not evaluate to a boolean" % repr(rule.car)) if test == types.true: for sexp in rule.cdr: rv = self.rt.eval(scope, sexp) return rv return types.nil
def eval(self, scope, exp): """ If exp is a list, execute it as a function call. If exp is a symbol, resolve it. Else, return it as is. """ if types.is_list(exp) and not types.is_nil(exp): return self.execute(scope, exp) elif types.is_symbol(exp): return self.lookup(scope, exp) else: return exp
def _unquote(self, scope, sexp): if types.is_list(sexp) and not types.is_nil(sexp): if types.is_symbol(sexp.car) and sexp.car.value == "unquote": return self.rt.eval(scope, sexp.cdr.car) out = types.nil for el in sexp: if is_splice(el): for splice in self.rt.eval(scope, el.cdr.car): out = types.conj(out, splice) else: out = types.conj(out, self._unquote(scope, el)) return out else: return sexp
def execute(self, scope, sexp): if types.is_atomic(sexp): return self.eval(scope, sexp) if types.is_nil(sexp): return sexp func = self.eval(scope, sexp.car) args = list(sexp.cdr) if types.is_primitive(func): return self.invoke(scope, func, args) if types.is_macro(func): return self.eval(scope, self.invoke(scope, func, args)) if types.is_function(func): return self.invoke(scope, func, (self.eval(scope, arg) for arg in args)) raise LispException("%s is not callable" % repr(func), sexp)
def load(stream): stack = [] top = types.nil last = None lexer = Lexer(stream) for token in lexer: if token["type"] == "lparen": stack.append(top) if last and last["type"] in ["quote", "unquote", "unquote-splice", "deref"]: top = types.cons(last["type"], types.nil) else: top = types.nil elif token["type"] == "rparen": if len(stack) == 0: raise ParserError("rparen without matching lparen", token) if not types.is_nil(top) and top.car in ["quote", "unquote", "unquote-splice", "deref"]: func = types.mksymbol(top.car) sym = top.cdr sym = types.cons(sym, types.nil) top = types.cons(func, sym) top = types.conj(stack.pop(), top) elif token["type"] in ["quote", "unquote"]: pass elif token["type"] == "deref": if last and last["type"] == "unquote": token["type"] = "unquote-splice" else: if last and last["type"] in ["quote", "unquote", "unquote-splice", "deref"]: sexp = types.cons(types.token_to_type(token), types.nil) sexp = types.cons(types.mksymbol(last["type"]), sexp) top = types.conj(top, sexp) else: top = types.conj(top, types.token_to_type(token)) last = token if len(stack): raise ParserError("lparen without matching rparen", last) return top
def is_splice(sexp): return (not types.is_nil(sexp)) and types.is_list(sexp) and types.is_symbol(sexp.car) and sexp.car.value == "unquote-splice"
def cdr(self, scope, args): if types.is_nil(args[0]): return types.nil return args[0].cdr