------------------------------------------------------------------------------
MC logo
Pairs
[^] Tom's Lisp Code
------------------------------------------------------------------------------
[Classes for Lisp Atoms] [Functions for Lisp Built-Ins] [Classes for Closures] [Context] [Base For Evaluable Objects] [Callable Objects] [Interrupt Utility] [Main Program] [Pairs] [Code Reader] [Reference Counting]
The Pair class is the result of a cons operation. The object has two pointers to Evaluable objects, the car and the cdr, and methods to extract them.
//*****************************************************************************
//***  Pair
//*** 
//***    The only Lisp compound data structure.  It's a car and cdr pointer,
//***    with needed methods.  The list is evaluable, which means to treat
//***    as a function call.
//*****************************************************************************

#include <iostream>

using namespace std;

#include "refct.h"
#include "atoms.h"
#include "context.h"
#include "evaluable.h"

#ifndef _pair_h_
#define _pair_h_

/* This is the pair (result of cons).  It represents a non-empty list. */
class Pair: public Evaluable {
        // The contents of a pair are pointers to two other things.
        Ptr<Evaluable> _car, _cdr;

private:
        // Create.  The public alloc() provides defaults of nil.
        Pair(Ptr<Evaluable> cd, Ptr<Evaluable> cr):
                _car(cd), _cdr(cr) { }
public:
        // Allocate a pair, return a (smart) pointer.
        static RefPtr alloc(Ptr<Evaluable> cd = the_nil, 
                            Ptr<Evaluable> cr = the_nil) {
                return RefCtObj::newRefPtr(new Pair(cd, cr));
        }

        // This evaluates the pair as a (func args), if possible.  Will
        // return an error atom if something goes wrong.
        Ptr<Evaluable> eval(Ptr<Context> c);

        // Print the list.  The two-argument form is essentially a helper
        // function for the regular print.  Listmode indicates the pair
        // should be printed as a list, otherwise it may be printed as a
        // dotted pair, though this can change to listmode.
        virtual void print(ostream &s, bool listmode);
        virtual void print(ostream &s) { print(s, false); }

        // Names should be short, even when printing is long.
        virtual string name() { return "A Pair"; }

        // The parts of the pair.
        virtual Ptr<Evaluable> car() { return _car; }
        virtual Ptr<Evaluable> cdr() { return _cdr; }

        // Equality means both sub-pointers point to equal things.
        virtual bool equal_same(RefCtObj& other) { 
                return _car.same_value(((Pair *)&other)->_car) && 
                        _cdr.same_value(((Pair *)&other)->_cdr);
        }
};

#endif
#include "func.h"
#include "pair.h"

/* Function evaluation.  Pair must be a function and an argument list.  This
   takes a list like (f x1 x2 x3 ... ), separates f, then applies 
   (x1 x2 x3 ... ) to f.  Note that if eval gets an error from any of the
   evaluations or applies, it returns that error, but it adds trace information
   to its history.  */
Ptr<Evaluable> Pair::eval(Ptr<Context> c) 
{
        // Eval the car (the function to run).  If this fails, add the
        // form which we were trying to evaluate, and pass the error on
        // up the stack.
        Ptr<Evaluable> func = car()->eval(c);
        if(func.points_to(typeid(Error)))
                return Ptr<Error>(func)->hist(this->newref());

        // Check that the function is really an applyable thing (such as the
        // the car builtin or a Closure, rather than a string or integer.)
        // If not, create an error here to reaturn.
        if(!func->applyable()) 
                return Error::alloc(BADOP, 
                                    "Attempt to apply on " + func->name(),
                                    newref());

        // Apply the arguments to the function.  If this fails, we use 
        // histinc() to add the name of whatever we were were applying
        // to the history.  We add that here because closures don't know
        // their own names (they're bound in the context, not contained
        // in the objects).  We let apply add the arguments themselves to
        // the history so we can get the evaluated versions.  That makes
        // a more useful trace, usually.
        Ptr<Evaluable> e = Ptr<Applyable>(func)->apply(cdr(), c);
        if(e.points_to(typeid(Error)))
                Ptr<Error>(e)->histinc(car());
        return e;
}