From b0ea96919787da6191d3e54bb4b865e6e64a076f Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Thu, 12 Jan 2017 15:02:13 +0000
Subject: [PATCH 1/2] Almost working lispops.

---
 src/consspaceobject.h |   1 +
 src/lispops.c         | 161 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+)
 create mode 100644 src/lispops.c

diff --git a/src/consspaceobject.h b/src/consspaceobject.h
index 0d92e25..a4553b7 100644
--- a/src/consspaceobject.h
+++ b/src/consspaceobject.h
@@ -25,6 +25,7 @@
  */
 #define CONSTAG  "CONS"
 #define FREETAG  "FREE"
+#define FUNCTIONTAG "FUNC"
 #define INTEGERTAG  "INTR"
 #define NILTAG  "NIL "
 #define READTAG  "READ"
diff --git a/src/lispops.c b/src/lispops.c
new file mode 100644
index 0000000..b59137d
--- /dev/null
+++ b/src/lispops.c
@@ -0,0 +1,161 @@
+/**
+ * lispops.c
+ *
+ * List processing operations.
+ *
+ * The general idea here is that a list processing operation is a
+ * function which takes two arguments, both cons_pointers:
+ *
+ * 1. args, the argument list to this function;
+ * 2. env, the environment in which this function should be evaluated;
+ *
+ * and returns a cons_pointer, the result.
+ *
+ * They must all have the same signature so that I can call them as
+ * function pointers.
+ *
+ *
+ * (c) 2017 Simon Brooke <simon@journeyman.cc>
+ * Licensed under GPL version 2.0, or, at your option, any later version.
+ */
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "consspaceobject.h"
+#include "conspage.h"
+#include "integer.h"
+#include "read.h"
+
+struct cons_pointer lisp_eval( struct cons_pointer args, struct cons_pointer env);
+struct cons_pointer lisp_cons( struct cons_pointer args, struct cons_pointer env);
+struct cons_pointer lisp_car( struct cons_pointer args, struct cons_pointer env);
+struct cons_pointer lisp_cdr( struct cons_pointer args, struct cons_pointer env);
+struct cons_pointer lisp_apply( struct cons_pointer args, struct cons_pointer env);
+struct cons_pointer lisp_throw( struct cons_pointer args, struct cons_pointer env);
+
+/**
+ * in the long run this becomes redundant because it's just (map eval
+ * args), but it helps bootstrapping.
+ */
+struct cons_pointer i_eval_args( struct cons_pointer args, struct cons_pointer tail, struct cons_pointer env) {
+  struct cons_pointer result = NIL;
+  
+  if ( ! nilp( args)) {
+    result = make_cons( lisp_eval( lisp_car( args)), i_eval_args( lisp_cdr( args), tail));
+  }
+
+  return result;
+}
+
+/**
+ * (apply fn args...)
+ * I'm assuming that the function should be protected from evaluation
+ * in apply because its name has already been resolved to the function
+ * object in read.
+ */
+struct cons_pointer lisp_apply( struct cons_pointer args, struct cons_pointer env) {
+  struct cons_pointer result = args;
+  
+  if ( consp( args)) {
+    lisp_eval( make_cons( lisp_car( args), i_eval_args( lisp_cdr( args), NIL)));
+  }
+
+  return result;
+}
+
+/**
+ * (eval args)
+ */
+struct cons_pointer lisp_eval( struct cons_pointer args, struct cons_pointer env) {
+  struct cons_pointer result = args;
+  
+  if ( consp( args)) {
+    /* the hard bit. Sort out what function is required and pass the
+     * args to it. */
+    struct cons_pointer fn_pointer lisp_car( args);
+    args = lisp_cdr( args);
+
+    if ( functionp( fn_pointer)) {
+      struct cons_space_object function = pointer2cell( fn_pointer);
+
+      /* the trick: pass the remaining arguments and environment to
+         the executable code which is the payload of the function
+         object. */
+      result = (*function.payload.function.executable)( args, env);
+    } else {
+      /* the Clojure practice of having a map serve in the function
+       * place of an s-expression is a good one and I should adopt it;
+       * also if the object is a consp it could be interpretable
+       * source code but in the long run I don't want an interpreter,
+       * and if I can get away without so much the better. */
+      result = lisp_throw( args, env)
+        }
+  }
+
+  return result;
+}
+
+/**
+ * Apply cons to this argsument list. Effectively, create a cons cell comprising
+ * (car args) (cadr args).
+ */ 
+struct cons_pointer lisp_cons( struct cons_pointer args, struct cons_pointer env) {
+  struct cons_pointer result = NIL;
+
+  if ( consp( args)) {
+    struct cons_space_object cell = pointer2cell( args);
+    struct cons_pointer a = cell.payload.cons.car;
+    struct cons_pointer d = pointer2cell( cell.payload.cons.cdr).payload.cons.car;
+    result = make_cons( a, d);
+  } else {
+    lisp_throw( args);
+  }
+
+  return result;
+}
+
+/**
+ * Apply car to this argsument list. Effectively, (car (car args))
+ */
+struct cons_pointer lisp_car( struct cons_pointer args, struct cons_pointer env) {
+  struct cons_pointer result = NIL;
+
+  if ( consp( args)) {
+    struct cons_space_object cell = pointer2cell( args);
+    result =  pointer2cell( cell.payload.cons.car).payload.cons.car;
+  } else {
+    lisp_throw( args);
+  }
+
+  return result;
+}
+
+
+/**
+ * Apply cdr to this argsument list. Effectively, (cdr (car args))
+ */
+struct cons_pointer lisp_cdr( struct cons_pointer args, struct cons_pointer env) {
+  struct cons_pointer result = NIL;
+
+  if ( consp( args)) {
+    struct cons_space_object cell = pointer2cell( args);
+    result =  pointer2cell( cell.payload.cons.cdr).payload.cons.car;
+  } else {
+    lisp_throw( args);
+  }
+
+  return result;
+}
+
+
+/**
+ * TODO: make this do something sensible somehow.
+ */
+struct cons_pointer lisp_throw( struct cons_pointer args, struct cons_pointer env) {
+  fprintf( stderr, "An exception was thrown and I've no idea what to do now\n");
+
+  return NIL;
+}
+

From f64469235df66e1e67ab4dc5d17802dfeea4dd0d Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Thu, 12 Jan 2017 15:02:41 +0000
Subject: [PATCH 2/2] Argh!

---
 src/consspaceobject.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/consspaceobject.h b/src/consspaceobject.h
index a4553b7..e151fc4 100644
--- a/src/consspaceobject.h
+++ b/src/consspaceobject.h
@@ -63,6 +63,11 @@
  */
 #define consp(conspoint) (check_tag(conspoint,CONSTAG))
 
+/**
+ * true if conspointer points to a function cell, else false 
+ */
+#define functionp(conspoint) (check_tag(conspoint,FUNCTIONTAG))
+
 /**
  * true if conspointer points to a string cell, else false 
  */
@@ -114,6 +119,11 @@ struct cons_payload {
   struct cons_pointer cdr;
 };
 
+struct function_payload {
+  struct cons_pointer source;
+  struct cons_pointer (*executable)(struct cons_pointer, struct cons_pointer);
+};
+
 /**
  * payload of a free cell. For the time being identical to a cons cell,
  * but it may not be so in future.
@@ -165,6 +175,8 @@ struct cons_space_object {
     struct cons_payload cons;
     /* if tag == FREETAG */
     struct free_payload free;
+    /* if tag == FUNCTIONTAG */
+    struct function_payload function;
     /* if tag == INTEGERTAG */
     struct integer_payload integer;
     /* if tag == NILTAG; we'll treat the special cell NIL as just a cons */