Browse Source

Sol Part 44: The Words I Don't Know Could Fill A Dictionary!

Graham Northup 7 years ago
  1. 70
  2. 1
  3. 55
  4. 32


@ -0,0 +1,70 @@
API Conventions
This document is intended to be a quick rundown on the necessary information to
start extending and modifying Sol in its source form.
Reference Counting
Objects in Sol are *reference-counted* for memory management--that is, when
initially allocated (in `sol_alloc_object`), they are set to a reference count
(see the refcnt member) of 1. Every call to `sol_obj_free` will decrement the
reference count of that object, and, when that reference count reaches zero,
the memory is freed (on the assumption that no other references to that object
exist). This does *not* prevent the occurrence of cycles, and Sol has no
protection against this at the moment.
As a general rule, *all* functions that return object pointers return a *new
reference*--the *caller* is expected to `sol_obj_free` that reference when it
is no longer needed (including immediately, for example). It is also the rule
that functions that take object pointers will *borrow* those references as
needed; for example, data structures that store objects will hold a reference.
Sol State
The Sol state (type `sol_state_t`) is a structure that is passed to nearly all
functions in the API, and is responsible for managing all the global state of
the interpreter. Due to this separation, Sol is fully reentrant. Designers
looking to modify Sol in a way that requires the introduction of data across
scopes and call frames may add fields to the state; extenders may use or refer
to the state uniquely to determine context, or use objects stored within that
state to accomplish that task.
Names exported in `sol.h` should be safe to use publicly--that is, they should
have a low chance of conflicting with names used in other programs; the typical
convention is to prefix every such name with "sol_". Names in `ast.h` are not so
restricted, and are typically included in many of the internal C files. `ast.h`
includes `sol.h`, and so only one of the two headers needs to be used. Note that
some references in structures defined in `sol.h` refer to types in `ast.h`, and
these are intentionally left as void pointers; Comments and other documentation
should indicate their true type.
File Structure
This list represents the file structure at this time, and may not be kept up to
- object.c contains all routines for the runtime, including creation,
destruction, and manipulation of most objects.
- builtins.c contains the vast majority of built-in functionality, including
most of the type methods as included in the `sol_ops_t` structures.
- runtime.c contains the interpreter and related routines, including execution
and evaluation, ones defining the calling convention, and the manipulation of
- state.c contains state management routines, such as those for initializing
and finalizing a state, getting or setting errors, and resolving names in
scopes. Module, type method, and other initialization is done here.
- gc.c contains the memory management routines.
- astprint.c contains routines for displaying ASTs on stdout.
- solrun.c contains the main() function for the interpreter.
- cdata.c contains definitions of various CDATA (C interface) types--presently,
only the CStruct (a way for C code to specify struct layouts to Sol
- util.c contains utility routines--importantly, a safe call/return trampoline
for extension code.


@ -11,5 +11,6 @@ the documentation on "doxygenfile".
.. toctree::


@ -3,6 +3,11 @@
#include <time.h>
#include "sol.h"
/** Allocates and returns a new reference to a typeless object.
* This is an internal function. Users should use `sol_alloc_object` instead.
sol_object_t *_sol_gc_alloc_object(sol_state_t *state) {
sol_object_t *res = malloc(sizeof(sol_object_t));
if(!res) {
@ -14,6 +19,11 @@ sol_object_t *_sol_gc_alloc_object(sol_state_t *state) {
return sol_incref(res);
/** Frees a reference to an object.
* This is an internal function. Users should use `sol_obj_free` instead.
void _sol_gc_obj_free(sol_object_t *obj) {
if(!obj) {
printf("WARNING: Attempt to free NULL\n");
@ -28,6 +38,17 @@ void _sol_gc_obj_free(sol_object_t *obj) {
/** Increments the reference count of an object, and return it.
* This function is exactly an identity function, but it increments the
* object's reference count.
* It is intended for use in places where a function is required, such as
* assigning to a function pointer.
* Users with the ability to should use `sol_incref` instead.
sol_object_t *sol_obj_acquire(sol_object_t *obj) {
return sol_incref(obj);
@ -107,14 +128,36 @@ void _sol_gc_dsl_destructor(sol_object_t *obj) {
/** Allocates and returns a new reference to a typeless object.
* This function is intended to be called from object constructors that will
* ultimately set the type and operations on the object.
* The returned reference is initially the only reference to this object.
sol_object_t *sol_alloc_object(sol_state_t *state) {
return _sol_gc_alloc_object(state);
/** Frees a reference to an object.
* If the given reference is the last reference to this object, the memory is
* freed, after any type-specific destructors are called.
void sol_obj_free(sol_object_t *obj) {
/** Destroys an object.
* This function is called on an object whose last reference has been freed; it
* is responsible for implementing the destructor protocol (and so calling the
* necessary methods). In general, it should not be used by user code, as it
* may introduce use-after-free.
void sol_obj_release(sol_object_t *obj) {
if(obj->ops->free) {
obj->ops->free(NULL, obj);
@ -122,7 +165,19 @@ void sol_obj_release(sol_object_t *obj) {
/** Initialize the memory manager for a state.
* You normally do not need to call this; it is also done in `sol_state_init`.
void sol_mm_initialize(sol_state_t *state) {}
/** Finalize the memory manager for a state.
* You normally do not need to call this; it is also done in
* `sol_state_cleanup`.
void sol_mm_finalize(sol_state_t *state) {}


@ -9,14 +9,26 @@
#include <stdarg.h>
#include "dsl/dsl.h"
/** The version of the project, as made available through `debug.version`. */
#define VERSION "0.2a0"
/** The hexadecimal version of the project, formatted 0xAAIIRPP where:
* - AA is the two-digit major version
* - II is the two-digit minor version
* - R is 'A' for alpha, 'B' for beta, 'C' for candidate, and 'F' for final
* - PP is the two-digit patch
* This value is guaranteed to always increase by revision.
#define HEXVER 0x0002A00
/** The smallest integer to cache. */
#define SOL_ICACHE_MIN -128
/** The largest integer to cache. */
#define SOL_ICACHE_MAX 256
@ -31,8 +43,28 @@ typedef struct sol_tag_object_t sol_object_t;
struct sol_tag_state_t;
typedef struct sol_tag_state_t sol_state_t;
/** CFunction type.
* This is the essential type for most C interface routines. It receives two
* parameters:
* - The state under which the function is invoked, and
* - A list object containing a set of parameters, which are generally
* well-defined per location or operation.
* The function should return a new reference to an object. If the value is
* unimportant or otherwise ignored, the canonical return value is
* `sol_incref`(state->None).
typedef sol_object_t *(*sol_cfunc_t)(sol_state_t *, sol_object_t *);
/** Print function type.
* \deprecated This is not used anywhere and is likely to be removed in the
* near future.
typedef void (*sol_printfunc_t)(sol_object_t *);
typedef struct {