~brenns10/funlisp

8fbac21317688f560e093f13a73f2db15afb309f — Stephen Brennan 2 years ago 65b2539
Update documentation with error handling stuff
3 files changed, 39 insertions(+), 7 deletions(-)

M doc/api.rst
M doc/embedding.rst
M inc/funlisp.h
M doc/api.rst => doc/api.rst +2 -2
@@ 45,8 45,8 @@ Embedding Tools
.. doxygengroup:: embed
   :content-only:

Miscellaneous Functions
Error Handling
-----------------------

.. doxygengroup:: misc
.. doxygengroup:: error
   :content-only:

M doc/embedding.rst => doc/embedding.rst +16 -1
@@ 66,7 66,8 @@ steps:
3. Parse the input. Parsed code is simply a :c:type:`lisp_value` like any other
   language object.
4. Evaluate the input within the global scope.
5. Print the output, and a trailing newline.
5. If an error occurred, print it and continue. If nothing of interest is
   returned, do nothing. Otherwise, print the output, and a trailing newline.
6. Mark everything in scope, then sweep unreachable objects.
7. Repeat steps 2-7 for each line of input.
8. Destroy the language runtime to finish cleaning up memory.


@@ 78,6 79,11 @@ without any custom functions. It uses the ``editline`` implementation of the
.. literalinclude:: ../tools/repl.c
  :language: C

Notice here that :c:func:`lisp_eval()` returns NULL in case of an error. If that
happens, then you can use :c:func:`lisp_print_error()` to print a user-facing
error message, and :c:func:`lisp_clear_error()` to clear the error from the
interpreter state.

The Script Runner
-----------------



@@ 119,6 125,15 @@ can do this individually with the :c:func:`lisp_eval()` function, or just
evaluate the whole list of arguments with the :c:func:`lisp_eval_list()`
function.

.. warning::

  As we've noticed in the previous example programs, evaluating code can return
  ``NULL`` if an error (e.g. an exception of some sort) occurs. A well-behaved
  builtin will test the result of all calls to :c:func:`lisp_eval()` and
  :c:func:`lisp_call()` using the macro ``lisp_error_check()`` in order to
  propagate those errors back to the user. :c:func:`lisp_eval_list()` propagates
  errors back, and so it should be error checked as well.

The one exception to evaluating all of your arguments is if you're defining some
sort of syntactic construct. An example of this is the if-statement. The if
statement looks like ``(if condition expr-if-true expr-if-false)``. It is

M inc/funlisp.h => inc/funlisp.h +21 -4
@@ 168,9 168,15 @@ void lisp_print(FILE *f, lisp_value *value);
 * others.  For example, evaluating a scope will not work. However, evaluating a
 * symbol will look it up in the current scope, and evaluating list ``l`` will
 * attempt to call ``(car l)`` with arguments ``(cdr l)``.
 * @param rt runtime associated with scope and value @param scope the scope to
 * use for evaluation (used when looking up symbols) @param value the value
 * (code generally) to evaluate @return the result of evaluating value in scope
 *
 * When an error occurs during execution, this function returns NULL and sets
 * the internal error details within the runtime.
 *
 * @param rt runtime associated with scope and value
 * @param scope the scope to use for evaluation (used when looking up symbols)
 * @param value the value to evaluate
 * @return the result of evaluating @a value in @a scope
 * @retval NULL when an error occurs
 */
lisp_value *lisp_eval(lisp_runtime *rt, lisp_scope *scope, lisp_value *value);



@@ 183,6 189,9 @@ lisp_value *lisp_eval(lisp_runtime *rt, lisp_scope *scope, lisp_value *value);
 * @param callable value to call
 * @param arguments a ::lisp_list containing arguments (which *have not yet been
 * evaluated*)
 * @return the result of calling @a callable with args @a arguments in scope @a
 * scope.
 * @retval NULL when an error occurs
 */
lisp_value *lisp_call(lisp_runtime *rt, lisp_scope *scope, lisp_value *callable,
                      lisp_value *arguments);


@@ 543,6 552,7 @@ void lisp_scope_add_builtin(lisp_runtime *rt, lisp_scope *scope, char *name,
 * @param scope scope to evaluate within
 * @param list list of un-evaluated function arguments
 * @return list of evaluated function arguments
 * @retval NULL if an error occured during evaluation
 */
lisp_value *lisp_eval_list(lisp_runtime *rt, lisp_scope *scope, lisp_value *list);



@@ 671,7 681,7 @@ lisp_value *lisp_quote(lisp_runtime *rt, lisp_value *value);

/**
 * @}
 * @defgroup misc Miscellaneous Functions
 * @defgroup error Error Handling
 * @{
 */



@@ 690,6 700,13 @@ void lisp_dump_stack(lisp_runtime *rt, lisp_list *stack, FILE *file);
 * A macro for error checking the return value of a lisp_eval() or lisp_call()
 * function. This will return NULL when its argumnet is NULL, helping functions
 * short-circuit in the case of an error.
 *
 * @code
 * lisp_value *v = lisp_eval(rt, my_code, my_scope);
 * lisp_error_check(v);
 * // continue using v
 * @endcode
 *
 * @param value value to error check
 */
#define lisp_error_check(value) do { \