~brenns10/funlisp

f158231fcfb537c1ca710c883d5127fdcd119551 — Stephen Brennan 2 years ago bca3850
Final grouping changes to docs!
2 files changed, 250 insertions(+), 218 deletions(-)

M doc/api.rst
M inc/funlisp.h
M doc/api.rst => doc/api.rst +20 -2
@@ 21,8 21,26 @@ Lisp Scopes
.. doxygengroup:: scope
   :content-only:

Miscellaneous API
Lisp Lists
----------

.. doxygengroup:: list
   :content-only:

Lisp Types
----------

.. doxygengroup:: types
   :content-only:

Builtin Functions
-----------------

.. doxygengroup:: misc
.. doxygengroup:: builtins
   :content-only:

Embedding Tools
---------------

.. doxygengroup:: embed
   :content-only:

M inc/funlisp.h => inc/funlisp.h +230 -216
@@ 65,7 65,7 @@ typedef struct lisp_value lisp_value;
 * to type check any ::lisp_value. Every type named lisp_X will have a
 * corresponding type_X object available.
 *
 * @sa lisp_is
 * @sa lisp_is()
 * @ingroup value
 */
typedef struct lisp_type lisp_type;


@@ 91,7 91,7 @@ typedef struct lisp_scope lisp_scope;
 *           x)))
 *
 * The symbols are: define, abs, lambda, x, if, and <.
 * @ingroup misc
 * @ingroup types
 */
typedef struct lisp_symbol lisp_symbol;



@@ 99,33 99,33 @@ typedef struct lisp_symbol lisp_symbol;
 * Error is a lisp type returned whenever (shockingly) an error occurs. This is
 * a bit of a hack to enable a base support for error handling. Errors may have
 * a string message.
 * @ingroup misc
 * @ingroup types
 */
typedef struct lisp_error lisp_error;

/**
 * ::lisp_integer contains an int object of whatever size the C implementation
 * supports.
 * @ingroup misc
 * @ingroup types
 */
typedef struct lisp_integer lisp_integer;

/**
 * This is a string (which occurs quoted in lisp source)
 * @ingroup misc
 * @ingroup types
 */
typedef struct lisp_string lisp_string;

/**
 * This data structure contains a native C function which may be called by
 * funlisp code. The C function must be of type ::lisp_builtin_func.
 * @ingroup misc
 * @ingroup types
 */
typedef struct lisp_builtin lisp_builtin;

/**
 * Data structure implementing a lisp lambda function.
 * @ingroup misc
 * @ingroup types
 */
typedef struct lisp_lambda lisp_lambda;



@@ 135,6 135,12 @@ typedef struct lisp_lambda lisp_lambda;
 */

/**
 * Type object of ::lisp_type, for type checking.
 * @sa lisp_is()
 */
extern lisp_type *type_type;

/**
 * Prints a string representing ``value`` to ``f``. This output is not meant to
 * contain all the information necessary to recreate ``value``, just enough to
 * give you an idea what it is.


@@ 281,16 287,82 @@ typedef struct lisp_list lisp_list;
extern lisp_type *type_list;

/**
 * @}
 * @defgroup misc Miscellaneous API
 * @{
 * Create a new list node with left and right value already specified. This
 * interface only allows you to create lists from end to beginning.
 * @param rt runtime
 * @param left item to go on the left side of the s-expression, usually a list
 * item
 * @param right item to go on the right side of the s-expression, usually the
 * next ::lisp_list instance
 * @return newly allocated ::lisp_list
 */
lisp_list *lisp_list_new(lisp_runtime *rt, lisp_value *left, lisp_value *right);

/**
 * Type object of ::lisp_type, for type checking.
 * @sa lisp_is()
 * Given a ::lisp_value, put it inside a list of size 0 and return it.
 * @param rt runtime
 * @param entry item to put inside a list
 * @return a singleton list
 */
lisp_value *lisp_singleton_list(lisp_runtime *rt, lisp_value *entry);

/**
 * Convert the array of strings into a lisp list of string objects.
 * @param rt runtime
 * @param list an array of strings
 * @param n length of the array
 * @param can_free Does the interpreter take ownership of the memory pointed at
 * by the strings? If so, can_free should be non-zero. If not, it should be 0.
 * @return ::lisp_list containing ::lisp_string objects
 */
lisp_value *lisp_list_of_strings(lisp_runtime *rt, char **list, size_t n, char can_free);

/**
 * Return the length of a list.
 * @param list list to find the length of
 * @return length of the list
 */
int lisp_list_length(lisp_list *list);

/**
 * Retrieve the left item of a list node / sexp.
 * @param l list to retrieve from
 * @return left item of list node
 */
lisp_value *lisp_list_get_left(lisp_list *l);

/**
 * Retrieve the right item of a list node / sexp
 * @param l list to retrieve from
 * @return right item of list node
 */
lisp_value *lisp_list_get_right(lisp_list *l);

/**
 * Return a nil instance. Nil is simply a "special" ::lisp_list, with left and
 * right both set to NULL. It is used to terminate lists. For example, the list
 * ``'(a b)`` is internally: ``lisp_list(a, lisp_list(b, lisp_list(NULL, NULL)))``
 * @note This function is named "new" for uniformity. However, it does't
 * actually allocate a "new" nil value every time. Instead, each ::lisp_runtime
 * has a singleton nil instance, which is never garbage collected.
 * @param rt runtime
 * @return the nil value
 */
lisp_value *lisp_nil_new(lisp_runtime *rt);

/**
 * Return true if the ::lisp_value is "nil" (an empty list).
 * @param l value to check
 * @retval 1 (true) if l is nil
 * @retval 0 (false) if l is non-nil
 */
int lisp_nil_p(lisp_value *l);

/**
 * @}
 * @defgroup types Lisp Types
 * @{
 */
extern lisp_type *type_type;

/**
 * Type object of ::lisp_symbol, for type checking.


@@ 329,95 401,99 @@ extern lisp_type *type_builtin;
extern lisp_type *type_lambda;

/**
 * Parse a *single* expression from a string, returning it as a ::lisp_value. If
 * there is no expression, return NULL
 * @param rt runtime to create language objects in
 * @param input string
 * @return parsed expression
 * @retval NULL on error or no expression available
 * Return a new, "un-owned" string. "Un-owned" means that ``str`` will not be
 * freed when the ::lisp_string is garbage collected. However, the ::lisp_string
 * will still contain the exact reference to ``str``, not a copy. So, your
 * application **must not** free ``str`` until the ::lisp_string containing it is
 * garbage collected. The safest approach here is if you are certain that your
 * string will not be freed until after the ::lisp_runtime is freed.
 *
 * @code
 *     lisp_value *v = (lisp_string *) lisp_string_new_unowned(rt, "hello");
 * @endcode
 *
 * @note This is the ideal function to use with string literals, since they are
 * statically allocated.
 * @param rt runtime
 * @param str string which will not be freed by the garbage collector
 * @return ::lisp_string object pointing to your string
 */
lisp_value *lisp_parse(lisp_runtime *rt, char *input);
lisp_string *lisp_string_new_unowned(lisp_runtime *rt, char *str);

/**
 *
 * Parse an entire file of input, evaluating it within a scope as we go. Return
 * the result of evaluating the last expression in the file. This is typically
 * useful for loading a file before running main.  See lisp_run_main_if_exists()
 * @warning This function performs garbage collection as it evaluates each
 * expression, marking only the scope which it evaluates within.
 * Return a new string. This function takes a "safe" approach, by copying your
 * string and using the copy. The pointer will be owned by the interpreter and
 * freed when the ::lisp_string object is garbage collected. This is roughly
 * equivalent to duplicating the string using strdup(), and then creating a new
 * owned string with that pointer.
 * @note This is also safe to use with string literals, but it is not the most
 * efficient way, since the string gets copied.
 * @param rt runtime
 * @param scope scope to evaluate within (usually a default scope)
 * @param input file to load as funlisp code
 * @return the parsed code
 * @retval NULL on empty file, or file read error
 * @param str string to copy and use in an owned string
 * @return a new ::lisp_string
 */
lisp_value *lisp_load_file(lisp_runtime *rt, lisp_scope *scope, FILE *input);
lisp_string *lisp_string_new(lisp_runtime *rt, char *str);

/**
 * Mark an object as still reachable or useful to the program (or you). This can
 * be called several times to mark many objects. Marking objects prevents the
 * garbage collector from freeing them. The garbage collector performs a breadth
 * first search starting from your marked objects to find all reachable language
 * objects. Thus, marking an object like a ::lisp_scope will save all symbols and
 * language objects contained within it, from being freed. Normal use is to mark
 * and sweep each time you've evaluated something:
 *
 *     lisp_value *result = lisp_eval(rt, scope, some_cool_code);
 *     lisp_mark(rt, (lisp_value*) scope);
 *     lisp_mark(rt, result);
 *     lisp_sweep(rt);
 *
 * @warning Be explicit about marking. If we had left out the third line of the
 * code sample above, there's a good chance that ``result`` would have been
 * freed when ``lisp_sweep()`` was called.
 * @param rt runtime
 * @param v value to mark as still needed. This value, and all values reachable
 * from it, are preserved on the next ``lisp_sweep()`` call.
 * Return a pointer to the string contained within a ::lisp_string. The
 * application must **not** modify or free the string.
 * @param s the lisp string to access
 * @return the contained string
 */
void lisp_mark(lisp_runtime *rt, lisp_value *v);
char *lisp_string_get(lisp_string *s);

/**
 * Free every object associated with the runtime, which is not marked or
 * reachable from a marked object.
 * Return a new symbol. This function will copy the ``string`` and free the copy
 * it on garbage collection (much like lisp_string_new()).
 * @param rt runtime
 * @param string the symbol to create
 * @return the resulting symbol
 */
void lisp_sweep(lisp_runtime *rt);

lisp_symbol *lisp_symbol_new(lisp_runtime *rt, char *string);

/* UTILITIES */
/**
 * Return the string contained in the symbol.
 * @param s the symbol to retrieve the string from
 * @return the string contained in the symbol
 */
char *lisp_symbol_get(lisp_symbol *s);

/**
 * Convert the array of strings into a lisp list of string objects.
 * Return a new error. This function will copy the ``message`` and free the copy
 * on garbage collection (much like lisp_string_new()).
 * @param rt runtime
 * @param list an array of strings
 * @param n length of the array
 * @param can_free Does the interpreter take ownership of the memory pointed at
 * by the strings? If so, can_free should be non-zero. If not, it should be 0.
 * @return ::lisp_list containing ::lisp_string objects
 * @param message message to use for creating the error
 * @return a new error
 */
lisp_value *lisp_list_of_strings(lisp_runtime *rt, char **list, size_t n, char can_free);
lisp_error  *lisp_error_new(lisp_runtime *rt, char *message);

/**
 * Given a ::lisp_value, put it inside a list of size 0 and return it.
 * @param rt runtime
 * @param entry item to put inside a list
 * @return a singleton list
 * Return the message from an error.
 * @param e the error to retrieve the message from
 * @return the message contained in the error
 */
lisp_value *lisp_singleton_list(lisp_runtime *rt, lisp_value *entry);
char *lisp_error_get(lisp_error *e);

/**
 * Lookup the symbol ``main`` in the scope, and run it if it exists. Calls the
 * function with a single argument, a ::lisp_list of program arguments. argc and
 * argv should not include the main executable (just the script name and args).
 * Create a new integer.
 * @param rt runtime
 * @param scope scope to find main in
 * @param argc number of arguments
 * @param argv NULL-terminated argument list
 * @returns result of evaluation
 * @retval NULL if no main function existed
 * @param n the integer value
 * @return newly allocated integer
 */
lisp_integer *lisp_integer_new(lisp_runtime *rt, int n);

/**
 * Retrieve the integer value from a ::lisp_integer.
 * @param integer ::lisp_integer to return from
 * @return the int value
 */
int lisp_integer_get(lisp_integer *integer);

/**
 * @}
 * @defgroup builtins Builtin Functions
 * @{
 */
lisp_value *lisp_run_main_if_exists(lisp_runtime *rt, lisp_scope *scope,
                                    int argc, char **argv);

/**
 * A built-in function. Takes a runtime, scope of evaluation, and a list of


@@ 426,6 502,19 @@ lisp_value *lisp_run_main_if_exists(lisp_runtime *rt, lisp_scope *scope,
typedef lisp_value * (*lisp_builtin_func)(lisp_runtime*, lisp_scope*,lisp_value*);

/**
 * Create a new ::lisp_builtin from a function pointer, with a given name.
 * @warning Namse of builtins are not garbage collected, since they are almost
 * always static. If you need your name to be dynamically allocated, you'll have
 * to free it after you free the runtime.
 * @param rt runtime
 * @param name name of the builtin. the interpreter will never free the name!
 * @param call function pointer of the builtin
 * @return new builtin object
 */
lisp_builtin *lisp_builtin_new(lisp_runtime *rt, char *name,
                               lisp_builtin_func call);

/**
 * Shortcut to declare a builtin function. Simply takes a function pointer and a
 * string name, and it will internally create the ::lisp_builtin object with the
 * correct name, and bind it in the given scope.


@@ 481,168 570,93 @@ lisp_value *lisp_eval_list(lisp_runtime *rt, lisp_scope *scope, lisp_value *list
int lisp_get_args(lisp_list *list, char *format, ...);

/**
 * Return value, but inside a list containing the symbol ``quote``. When this
 * evaluated, it will return its contents (``value``) un-evaluated.
 * @param rt runtime
 * @param value value to return quoted
 * @return value but quoted
 */
lisp_value *lisp_quote(lisp_runtime *rt, lisp_value *value);

/**
 * Return the length of a list.
 * @param list list to find the length of
 * @return length of the list
 */
int lisp_list_length(lisp_list *list);

/**
 * Return true if the ::lisp_value is "nil" (an empty list).
 * @param l value to check
 * @retval 1 (true) if l is nil
 * @retval 0 (false) if l is non-nil
 */
int lisp_nil_p(lisp_value *l);

/**
 * Return a new, "un-owned" string. "Un-owned" means that ``str`` will not be
 * freed when the ::lisp_string is garbage collected. However, the ::lisp_string
 * will still contain the exact reference to ``str``, not a copy. So, your
 * application **must not** free ``str`` until the ::lisp_string containing it is
 * garbage collected. The safest approach here is if you are certain that your
 * string will not be freed until after the ::lisp_runtime is freed.
 *
 * @code
 *     lisp_value *v = (lisp_string *) lisp_string_new_unowned(rt, "hello");
 * @endcode
 *
 * @note This is the ideal function to use with string literals, since they are
 * statically allocated.
 * @param rt runtime
 * @param str string which will not be freed by the garbage collector
 * @return ::lisp_string object pointing to your string
 */
lisp_string *lisp_string_new_unowned(lisp_runtime *rt, char *str);

/**
 * Return a new string. This function takes a "safe" approach, by copying your
 * string and using the copy. The pointer will be owned by the interpreter and
 * freed when the ::lisp_string object is garbage collected. This is roughly
 * equivalent to duplicating the string using strdup(), and then creating a new
 * owned string with that pointer.
 * @note This is also safe to use with string literals, but it is not the most
 * efficient way, since the string gets copied.
 * @param rt runtime
 * @param str string to copy and use in an owned string
 * @return a new ::lisp_string
 */
lisp_string *lisp_string_new(lisp_runtime *rt, char *str);

/**
 * Return a pointer to the string contained within a ::lisp_string. The
 * application must **not** modify or free the string.
 * @param s the lisp string to access
 * @return the contained string
 */
char *lisp_string_get(lisp_string *s);

/**
 * Return a new symbol. This function will copy the ``string`` and free the copy
 * it on garbage collection (much like lisp_string_new()).
 * @param rt runtime
 * @param string the symbol to create
 * @return the resulting symbol
 * @}
 * @defgroup embed Embedding API
 * @{
 */
lisp_symbol *lisp_symbol_new(lisp_runtime *rt, char *string);

/**
 * Return the string contained in the symbol.
 * @param s the symbol to retrieve the string from
 * @return the string contained in the symbol
 * Parse a *single* expression from a string, returning it as a ::lisp_value. If
 * there is no expression, return NULL
 * @param rt runtime to create language objects in
 * @param input string
 * @return parsed expression
 * @retval NULL on error or no expression available
 */
char *lisp_symbol_get(lisp_symbol *s);
lisp_value *lisp_parse(lisp_runtime *rt, char *input);

/**
 * Return a new error. This function will copy the ``message`` and free the copy
 * on garbage collection (much like lisp_string_new()).
 * Parse an entire file of input, evaluating it within a scope as we go. Return
 * the result of evaluating the last expression in the file. This is typically
 * useful for loading a file before running main.  See lisp_run_main_if_exists()
 * @warning This function performs garbage collection as it evaluates each
 * expression, marking only the scope which it evaluates within.
 * @param rt runtime
 * @param message message to use for creating the error
 * @return a new error
 */
lisp_error  *lisp_error_new(lisp_runtime *rt, char *message);

/**
 * Return the message from an error.
 * @param e the error to retrieve the message from
 * @return the message contained in the error
 * @param scope scope to evaluate within (usually a default scope)
 * @param input file to load as funlisp code
 * @return the parsed code
 * @retval NULL on empty file, or file read error
 */
char *lisp_error_get(lisp_error *e);
lisp_value *lisp_load_file(lisp_runtime *rt, lisp_scope *scope, FILE *input);

/**
 * Create a new list node with left and right value already specified. This
 * interface only allows you to create lists from end to beginning.
 * Lookup the symbol ``main`` in the scope, and run it if it exists. Calls the
 * function with a single argument, a ::lisp_list of program arguments. argc and
 * argv should not include the main executable (just the script name and args).
 * @param rt runtime
 * @param left item to go on the left side of the s-expression, usually a list
 * item
 * @param right item to go on the right side of the s-expression, usually the
 * next ::lisp_list instance
 * @return newly allocated ::lisp_list
 */
lisp_list *lisp_list_new(lisp_runtime *rt, lisp_value *left, lisp_value *right);

/**
 * Retrieve the left item of a list node / sexp.
 * @param l list to retrieve from
 * @return left item of list node
 */
lisp_value *lisp_list_get_left(lisp_list *l);

/**
 * Retrieve the right item of a list node / sexp
 * @param l list to retrieve from
 * @return right item of list node
 * @param scope scope to find main in
 * @param argc number of arguments
 * @param argv NULL-terminated argument list
 * @returns result of evaluation
 * @retval NULL if no main function existed
 */
lisp_value *lisp_list_get_right(lisp_list *l);
lisp_value *lisp_run_main_if_exists(lisp_runtime *rt, lisp_scope *scope,
                                    int argc, char **argv);

/**
 * Create a new integer.
 * Mark an object as still reachable or useful to the program (or you). This can
 * be called several times to mark many objects. Marking objects prevents the
 * garbage collector from freeing them. The garbage collector performs a breadth
 * first search starting from your marked objects to find all reachable language
 * objects. Thus, marking an object like a ::lisp_scope will save all symbols and
 * language objects contained within it, from being freed. Normal use is to mark
 * and sweep each time you've evaluated something:
 *
 *     lisp_value *result = lisp_eval(rt, scope, some_cool_code);
 *     lisp_mark(rt, (lisp_value*) scope);
 *     lisp_mark(rt, result);
 *     lisp_sweep(rt);
 *
 * @warning Be explicit about marking. If we had left out the third line of the
 * code sample above, there's a good chance that ``result`` would have been
 * freed when ``lisp_sweep()`` was called.
 * @param rt runtime
 * @param n the integer value
 * @return newly allocated integer
 */
lisp_integer *lisp_integer_new(lisp_runtime *rt, int n);

/**
 * Retrieve the integer value from a ::lisp_integer.
 * @param integer ::lisp_integer to return from
 * @return the int value
 * @param v value to mark as still needed. This value, and all values reachable
 * from it, are preserved on the next ``lisp_sweep()`` call.
 */
int lisp_integer_get(lisp_integer *integer);
void lisp_mark(lisp_runtime *rt, lisp_value *v);

/**
 * Create a new ::lisp_builtin from a function pointer, with a given name.
 * @warning Builtin names are not garbage collected, since they are almost
 * always static. If you need your name to be dynamically allocated, you'll have
 * to free it after you free the runtime.
 * Free every object associated with the runtime, which is not marked or
 * reachable from a marked object.
 * @param rt runtime
 * @param name name of the builtin. the interpreter will never free the name!
 * @param call function pointer of the builtin
 * @return new builtin object
 */
lisp_builtin *lisp_builtin_new(lisp_runtime *rt, char *name,
                               lisp_builtin_func call);
void lisp_sweep(lisp_runtime *rt);

/**
 * Return a nil instance. Nil is simply a "special" ::lisp_list, with left and
 * right both set to NULL. It is used to terminate lists. For example, the list
 * ``'(a b)`` is internally: ``lisp_list(a, lisp_list(b, lisp_list(NULL, NULL)))``
 * @note This function is named "new" for uniformity. However, it does't
 * actually allocate a "new" nil value every time. Instead, each ::lisp_runtime
 * has a singleton nil instance, which is never garbage collected.
 * Return @a value, but inside a list containing the symbol ``quote``. When this
 * evaluated, it will return its contents (@a value) un-evaluated.
 *
 * This function is used during parsing, to implement the single-quote syntax
 * feature. For example ``'(a b c)``, evaluates to the list containing a, b,
 * and c, rather than calling a on b and c. This is because the expression is
 * transparently converted to the more verbose ``(quote (a b c))``.
 *
 * @param rt runtime
 * @return the nil value
 * @param value value to return quoted
 * @return value but quoted
 */
lisp_value *lisp_nil_new(lisp_runtime *rt);
lisp_value *lisp_quote(lisp_runtime *rt, lisp_value *value);

/**
 * @}