Huge amount of work. Does not even nearly compile, but it's nearer.
This commit is contained in:
parent
1afb1b9fad
commit
cae27731b7
31 changed files with 407 additions and 96 deletions
86
src/c/payloads/cons.c
Normal file
86
src/c/payloads/cons.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* payloads/cons.h
|
||||
*
|
||||
* A cons cell.
|
||||
*
|
||||
* (c) 2026 Simon Brooke <simon@journeyman.cc>
|
||||
* Licensed under GPL version 2.0, or, at your option, any later version.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "memory/node.h"
|
||||
#include "memory/pointer.h"
|
||||
#include "memory/pso.h"
|
||||
#include "payloads/cons.h"
|
||||
|
||||
/**
|
||||
* @brief allocate a cons cell with this car and this cdr, and return a pointer
|
||||
* to it.
|
||||
*
|
||||
* @param car the pointer which should form the car of this cons cell;
|
||||
* @param cdr the pointer which should form the cdr of this cons cell.
|
||||
* @return struct pso_pointer a pointer to the newly allocated cons cell.
|
||||
*/
|
||||
struct pso_pointer cons( struct pso_pointer car, struct pso_pointer cdr) {
|
||||
struct pso_pointer result = allocate( CONSTAG, 2);
|
||||
|
||||
struct pso2 *object = pointer_to_object( result );
|
||||
object->payload.cons.car = car;
|
||||
object->payload.cons.cdr = cdr;
|
||||
|
||||
inc_ref( car);
|
||||
inc_ref( cdr);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return true if `ptr` indicates a cons cell, else false.
|
||||
*
|
||||
* @param ptr a pointer.
|
||||
* @return true if `ptr` indicates a cons cell.
|
||||
* @return false otherwise
|
||||
*/
|
||||
bool consp( struct pso_pointer ptr) {
|
||||
// TODO: make it actually work!
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return the car of this cons cell.
|
||||
*
|
||||
* @param cons a pointer to the cell.
|
||||
* @return the car of the indicated cell.
|
||||
* @exception if the pointer does not indicate a cons cell.
|
||||
*/
|
||||
struct pso_pointer car( struct pso_pointer cons) {
|
||||
struct pso_pointer result = nil;
|
||||
struct pso2 *object = pointer_to_object( result );
|
||||
|
||||
if ( consp( cons)) {
|
||||
result = object->payload.cons.car;
|
||||
}
|
||||
// TODO: else throw an exception
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief return the cdr of this cons cell.
|
||||
*
|
||||
* @param cons a pointer to the cell.
|
||||
* @return the cdr of the indicated cell.
|
||||
* @exception if the pointer does not indicate a cons cell.
|
||||
*/
|
||||
struct pso_pointer cdr( struct pso_pointer cons) {
|
||||
struct pso_pointer result = nil;
|
||||
struct pso2 *object = pointer_to_object( result );
|
||||
|
||||
if ( consp( cons)) {
|
||||
result = object->payload.cons.cdr;
|
||||
}
|
||||
// TODO: else throw an exception
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#ifndef __psse_payloads_cons_h
|
||||
#define __psse_payloads_cons_h
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "memory/pointer.h"
|
||||
|
||||
|
|
@ -16,6 +17,7 @@
|
|||
* An ordinary cons cell:
|
||||
*/
|
||||
#define CONSTAG "CNS"
|
||||
#define CONSTV 5459523
|
||||
|
||||
/**
|
||||
* @brief A cons cell.
|
||||
|
|
@ -28,5 +30,12 @@ struct cons_payload {
|
|||
struct pso_pointer cdr;
|
||||
};
|
||||
|
||||
struct pso_pointer car( struct pso_pointer cons);
|
||||
|
||||
struct pso_pointer cdr( struct pso_pointer cons);
|
||||
|
||||
struct pso_pointer cons( struct pso_pointer car, struct pso_pointer cdr);
|
||||
|
||||
bool consp( struct pso_pointer ptr);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
#include "memory/pointer.h"
|
||||
|
||||
#define EXCEPTIONTAG "EXP"
|
||||
#define EXCEPTIONTV 5265477
|
||||
|
||||
/**
|
||||
* @brief An exception; required three pointers, so use object of size class 3.
|
||||
*/
|
||||
|
|
@ -21,7 +24,7 @@ struct exception_payload {
|
|||
/** @brief the stack frame at which the exception was thrown. */
|
||||
struct pso_pointer stack;
|
||||
/** @brief the cause; expected to be another exception, or (usually) `nil`. */
|
||||
struct cons_pointer cause;
|
||||
struct pso_pointer cause;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* @brief Tag for an unassigned object; may be of any size class.
|
||||
*/
|
||||
#define FREETAG "FRE"
|
||||
#define FREETV 4543046
|
||||
|
||||
/**
|
||||
* @brief An unassigned object, on a freelist; may be of any size class.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#define __psse_payloads_function_h
|
||||
|
||||
#include "memory/pointer.h"
|
||||
#include "memory/pso.h"
|
||||
|
||||
/**
|
||||
* @brief Tag for an ordinary Lisp function - one whose arguments are pre-evaluated.
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
* \see SPECIALTAG for functions whose arguments are not pre-evaluated.
|
||||
*/
|
||||
#define FUNCTIONTAG "FUN"
|
||||
#define FUNCTIONTV 5133638
|
||||
|
||||
/**
|
||||
* @brief Payload of a function cell.
|
||||
|
|
@ -32,16 +34,16 @@ struct function_payload {
|
|||
/**
|
||||
* pointer to metadata (e.g. the source from which the function was compiled).
|
||||
*/
|
||||
struct cons_pointer meta;
|
||||
struct pso_pointer meta;
|
||||
/** pointer to a function which takes a cons pointer (representing
|
||||
* its argument list) and a cons pointer (representing its environment) and a
|
||||
* stack frame (representing the previous stack frame) as arguments and returns
|
||||
* a cons pointer (representing its result).
|
||||
* \todo check this documentation is current!
|
||||
*/
|
||||
struct cons_pointer ( *executable ) ( struct stack_frame *,
|
||||
struct cons_pointer,
|
||||
struct cons_pointer );
|
||||
struct pso_pointer ( *executable ) ( struct pso4 *,
|
||||
struct pso_pointer,
|
||||
struct pso_pointer );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,7 +3,25 @@
|
|||
*
|
||||
* an ordinary Lisp hashtable - one whose contents are immutable.
|
||||
*
|
||||
* Can sensibly sit in any pso from size class 6 upwards.
|
||||
* Can sensibly sit in any pso from size class 6 upwards. However, it's often
|
||||
* considered a good thing to have a prime number of buckets in a hash table.
|
||||
* Our total overhead on the full object size is two words header, and, for
|
||||
* hashtables, one word for the pointer to the (optional) hash function, and
|
||||
* one for the number of buckets, total four.
|
||||
*
|
||||
* | size class | words | less overhead | nearest prime | wasted |
|
||||
* | ---------- | ----- | ------------- | ------------- | ------ |
|
||||
* | 5 | 32 | 28 | 23 | 5 |
|
||||
* | 6 | 64 | 60 | 59 | 1 |
|
||||
* | 7 | 128 | 124 | 113 | 11 |
|
||||
* | 8 | 256 | 252 | 251 | 1 |
|
||||
* | 9 | 512 | 508 | 503 | 5 |
|
||||
* | 10 | 1024 | 1020 | 1019 | 1 |
|
||||
*
|
||||
* So we can fit 59 buckets into a 64 word class 6 pso, wasting one word;
|
||||
* 251 buckets in a 256 word class 8 again wasting one word; 1019 in a size
|
||||
* class 10, also wasting only one word. In a 32 word class 5, the best prime
|
||||
* we can do is 23 buckets, wasting five words.
|
||||
*
|
||||
* (c) 2026 Simon Brooke <simon@journeyman.cc>
|
||||
* Licensed under GPL version 2.0, or, at your option, any later version.
|
||||
|
|
@ -19,6 +37,8 @@
|
|||
* \see NAMESPACETAG for mutable hashtables.
|
||||
*/
|
||||
#define HASHTABLETAG "HTB"
|
||||
#define HASHTABLETV 4346952
|
||||
|
||||
/**
|
||||
* The payload of a hashtable. The number of buckets is assigned at run-time,
|
||||
* and is stored in n_buckets. Each bucket is something ASSOC can consume:
|
||||
|
|
@ -27,12 +47,7 @@
|
|||
struct hashtable_payload {
|
||||
struct cons_pointer hash_fn; /* function for hashing values in this hashtable, or `NIL` to use
|
||||
the default hashing function */
|
||||
struct cons_pointer write_acl; /* it seems to me that it is likely that the
|
||||
* principal difference between a hashtable and a
|
||||
* namespace is that a hashtable has a write ACL
|
||||
* of `NIL`, meaning not writeable by anyone */
|
||||
uint32_t n_buckets; /* number of hash buckets */
|
||||
uint32_t unused; /* for word alignment and possible later expansion */
|
||||
struct cons_pointer buckets[]; /* actual hash buckets, which should be `NIL`
|
||||
* or assoc lists or (possibly) further hashtables. */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define INTEGERTAG "INT"
|
||||
#define INTEGERTV 5525065
|
||||
|
||||
/**
|
||||
* @brief An integer .
|
||||
*
|
||||
|
|
@ -20,7 +23,7 @@
|
|||
* in the Lisp layer, not the substrate.
|
||||
*/
|
||||
struct integer_payload {
|
||||
int128_t value;
|
||||
__int128_t value;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* Tag for a keyword - an interned, self-evaluating string.
|
||||
*/
|
||||
#define KEYTAG "KEY"
|
||||
#define KEYTV 5850443
|
||||
|
||||
/* TODO: for now, Keyword shares a payload with String, but this may change.
|
||||
* Strings are of indefinite length, but keywords are really not, and might
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
* \see FUNCTIONTAG.
|
||||
*/
|
||||
#define LAMBDATAG "LMD"
|
||||
#define LAMBDATV 4345164
|
||||
|
||||
/**
|
||||
* @brief payload for lambda and nlambda cells.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
* \see FUNCTIONTAG.
|
||||
*/
|
||||
#define MUTEXTAG "MTX"
|
||||
#define MUTEXTV 5788749
|
||||
|
||||
/**
|
||||
* @brief payload for mutex objects.
|
||||
|
|
@ -29,7 +30,7 @@
|
|||
*/
|
||||
struct mutex_payload {
|
||||
pthread_mutex_t mutex;
|
||||
}
|
||||
};
|
||||
|
||||
struct pso_pointer make_mutex();
|
||||
|
||||
|
|
@ -63,4 +64,6 @@ struct pso_pointer with_lock( struct pso_pointer lock, struct pso_pointer forms)
|
|||
* @param forms a list of arbitrary Lisp forms.
|
||||
* @return struct pso_pointer the result.
|
||||
*/
|
||||
struct pso_pointer attempt_with_lock( struct pso_pointer lock, struct pso_pointer forms);
|
||||
struct pso_pointer attempt_with_lock( struct pso_pointer lock, struct pso_pointer forms);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3,7 +3,28 @@
|
|||
*
|
||||
* a Lisp namespace - a hashtable whose contents are mutable.
|
||||
*
|
||||
* Can sensibly sit in any pso from size class 6 upwards.
|
||||
* Can sensibly sit in any pso from size class 6 upwards. However, it's often
|
||||
* considered a good thing to have a prime number of buckets in a hash table.
|
||||
* Our total overhead on the full object size is two words header, and, for
|
||||
* namespaces, one word for the pointer to the (optional) hash function,
|
||||
* one for the number of buckets, one for the pointer to the write ACL, one
|
||||
* for the pointer to the mutex, total six.
|
||||
*
|
||||
* There are no really good fits until you get up to class 9, which might
|
||||
* make sense for some namespaces, but it's quite large!
|
||||
*
|
||||
* | size class | words | less overhead | nearest prime | wasted |
|
||||
* | ---------- | ----- | ------------- | ------------- | ------ |
|
||||
* | 5 | 32 | 26 | 23 | 3 |
|
||||
* | 6 | 64 | 58 | 53 | 5 |
|
||||
* | 7 | 128 | 122 | 113 | 9 |
|
||||
* | 8 | 256 | 250 | 241 | 9 |
|
||||
* | 9 | 512 | 506 | 503 | 3 |
|
||||
* | 10 | 1024 | 1018 | 1013 | 5 |
|
||||
*
|
||||
* Although it may be *better* to have prime numbers of buckets, how much
|
||||
* better is it? Is a bucket with 23 slots sufficiently better than one
|
||||
* with 26 slots to make up for its inevitably-longer hash buckets?
|
||||
*
|
||||
* (c) 2026 Simon Brooke <simon@journeyman.cc>
|
||||
* Licensed under GPL version 2.0, or, at your option, any later version.
|
||||
|
|
@ -19,6 +40,7 @@
|
|||
* \see HASHTABLETAG for mutable hashtables.
|
||||
*/
|
||||
#define NAMESPACETAG "NSP"
|
||||
#define NAMESPACETV 5264206
|
||||
|
||||
/**
|
||||
* The payload of a namespace. The number of buckets is assigned at run-time,
|
||||
|
|
@ -28,13 +50,13 @@
|
|||
struct namespace_payload {
|
||||
struct cons_pointer hash_fn; /* function for hashing values in this namespace, or
|
||||
* `NIL` to use the default hashing function */
|
||||
uint32_t n_buckets; /* number of hash buckets */
|
||||
uint32_t unused; /* for word alignment and possible later expansion */
|
||||
struct cons_pointer write_acl; /* it seems to me that it is likely that the
|
||||
* principal difference between a hashtable and a
|
||||
* namespace is that a hashtable has a write ACL
|
||||
* of `NIL`, meaning not writeable by anyone */
|
||||
struct cons_pointer mutex; /* the mutex to lock when modifying this namespace.*/
|
||||
uint32_t n_buckets; /* number of hash buckets */
|
||||
uint32_t unused; /* for word alignment and possible later expansion */
|
||||
struct cons_pointer buckets[]; /* actual hash buckets, which should be `NIL`
|
||||
* or assoc lists or (possibly) further hashtables. */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@
|
|||
/**
|
||||
* An ordinary nlambda cell:
|
||||
*/
|
||||
#define CONSTAG "CNS"
|
||||
#define NLAMBDATAG "NLM"
|
||||
#define NLAMBDATV 5065806
|
||||
|
||||
/* nlambda shares a payload with lambda */
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,15 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "memory/pointer.h"
|
||||
|
||||
/**
|
||||
* An open read stream.
|
||||
*/
|
||||
#define READTAG "REA"
|
||||
#define READTV 4277586
|
||||
|
||||
/**
|
||||
* payload of a read or write stream cell.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
* \see NLAMBDATAG.
|
||||
*/
|
||||
#define SPECIALTAG "SFM"
|
||||
#define SPECIALTV 5064275
|
||||
|
||||
/**
|
||||
* @brief Payload of a special form cell.
|
||||
|
|
@ -30,14 +31,14 @@ struct special_payload {
|
|||
* pointer to the source from which the special form was compiled, or NIL
|
||||
* if it is a primitive.
|
||||
*/
|
||||
struct cons_pointer meta;
|
||||
struct pso_pointer meta;
|
||||
/** pointer to a function which takes a cons pointer (representing
|
||||
* its argument list) and a cons pointer (representing its environment) and a
|
||||
* stack frame (representing the previous stack frame) as arguments and returns
|
||||
* a cons pointer (representing its result). */
|
||||
struct cons_pointer ( *executable ) ( struct stack_frame *,
|
||||
struct cons_pointer,
|
||||
struct cons_pointer );
|
||||
struct pso_pointer ( *executable ) ( struct pso4 *,
|
||||
struct pso_pointer,
|
||||
struct pso_pointer );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
41
src/c/payloads/stack.c
Normal file
41
src/c/payloads/stack.c
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* payloads/stack.c
|
||||
*
|
||||
* The execution stack.
|
||||
*
|
||||
* (c) 2026 Simon Brooke <simon@journeyman.cc>
|
||||
* Licensed under GPL version 2.0, or, at your option, any later version.
|
||||
*/
|
||||
|
||||
#include "memory/node.h"
|
||||
#include "memory/pso.h"
|
||||
#include "payloads/stack.h"
|
||||
|
||||
/**
|
||||
* @brief The maximum depth of stack before we throw an exception.
|
||||
*
|
||||
* `0` is interpeted as `unlimited`.
|
||||
*/
|
||||
uint32_t stack_limit = 0;
|
||||
|
||||
/**
|
||||
* Fetch a pointer to the value of the local variable at this index.
|
||||
*/
|
||||
struct pso_pointer fetch_arg( struct pso4 *frame, unsigned int index ) {
|
||||
struct pso_pointer result = nil;
|
||||
|
||||
// TODO check that the frame is indeed a frame!
|
||||
if ( index < args_in_frame ) {
|
||||
result = frame->payload.stack_frame.arg[index];
|
||||
} else {
|
||||
struct pso_pointer p = frame->payload.stack_frame.more;
|
||||
|
||||
for ( int i = args_in_frame; i < index; i++ ) {
|
||||
p = pointer_to_object( p)->payload.cons.cdr;
|
||||
}
|
||||
|
||||
result = pointer_to_object( p)->payload.cons.car;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
47
src/c/payloads/stack.h
Normal file
47
src/c/payloads/stack.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* payloads/stack.h
|
||||
*
|
||||
* a Lisp stack frame.
|
||||
*
|
||||
* Sits in a pso4.
|
||||
*
|
||||
* (c) 2026 Simon Brooke <simon@journeyman.cc>
|
||||
* Licensed under GPL version 2.0, or, at your option, any later version.
|
||||
*/
|
||||
|
||||
#ifndef __psse_payloads_stack_h
|
||||
#define __psse_payloads_stack_h
|
||||
|
||||
#include "memory/pointer.h"
|
||||
|
||||
/*
|
||||
* number of arguments stored in a stack frame
|
||||
*/
|
||||
#define args_in_frame 8
|
||||
|
||||
/**
|
||||
* @brief The maximum depth of stack before we throw an exception.
|
||||
*
|
||||
* `0` is interpeted as `unlimited`.
|
||||
*/
|
||||
extern uint32_t stack_limit;
|
||||
|
||||
/**
|
||||
* A stack frame.
|
||||
*/
|
||||
struct stack_frame_payload {
|
||||
/** the previous frame. */
|
||||
struct pso_pointer previous;
|
||||
/** first 8 arument bindings. */
|
||||
struct pso_pointer arg[args_in_frame];
|
||||
/** list of any further argument bindings. */
|
||||
struct pso_pointer more;
|
||||
/** the function to be called. */
|
||||
struct pso_pointer function;
|
||||
/** the number of arguments provided. */
|
||||
uint32_t args;
|
||||
/** the depth of the stack below this frame */
|
||||
uint32_t depth;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
* @brief Tag for string of characters, organised as a linked list.
|
||||
*/
|
||||
#define STRINGTAG "STR"
|
||||
#define STRINGTV 5395539
|
||||
|
||||
/**
|
||||
* @brief payload of a string cell.
|
||||
|
|
@ -36,7 +37,7 @@ struct string_payload {
|
|||
/** a hash of the string value, computed at store time. */
|
||||
uint32_t hash;
|
||||
/** the remainder of the string following this character. */
|
||||
struct cons_pointer cdr;
|
||||
struct pso_pointer cdr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
* Tag for a symbol: just like a keyword except not self-evaluating.
|
||||
*/
|
||||
#define SYMBOLTAG "SYM"
|
||||
#define SYMBOLTV 5069139
|
||||
|
||||
/* TODO: for now, Symbol shares a payload with String, but this may change.
|
||||
* Strings are of indefinite length, but symbols are really not, and might
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@
|
|||
/**
|
||||
* @brief Tag for a time stamp.
|
||||
*/
|
||||
#define TIMETAG "TIME"
|
||||
#define TIMETAG "TIM"
|
||||
#define TIMETV 5065044
|
||||
|
||||
/**
|
||||
* The payload of a time cell: an unsigned 128 bit value representing micro-
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* @brief Tag for an open write stream.
|
||||
*/
|
||||
#define WRITETAG "WRT"
|
||||
#define WRITETV 5264214
|
||||
|
||||
/* write stream shares a payload with /see read_streem.h */
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue