~octaspire/dern

51df041d1b6d0a731a6f31b565e531e0f5a0ec98 — octaspire 5 years ago 095670e v0.487.0
Add initial macro and template implementation

* Add initial implementation for macros and
  templates into Dern.

* Fix few things.
R .builds/freebsd.yml => .builds/freebsd_latest.yml +1 -1
@@ 1,4 1,4 @@
image: freebsd
image: freebsd/latest
packages:
    - devel/gmake
    - devel/ncurses

M dev/doc/book/dern-manual.htm => dev/doc/book/dern-manual.htm +34 -0
@@ 839,10 839,38 @@
    Values can be selected from collections using <code>ln@</code> and
    copied with <code>cp@</code>. <code>ln@</code> is pronounced
    <b>link at</b> and <code>cp@</code> is pronounced <b>copy at</b>.
    <code>cp@</code> can be used to copy either a single value or
    a range of values. As usual the index or indices can be
    given either as negative or non-negative. Negative indices
    count from the end; this means that <code>-1</code> is the
    last value in a collection.
  </p>

  .INCLUDE: dev/doc/book/examples/dern/selectingFromCollection.dern

  <h2>Macros and templates</h2>

  <p>
    Above was discussion about selecting values from collections.
    You might be wondering whether Dern has functions <code>car</code>
    (also known as <code>first</code>) and <code>cdr</code> (also known
    as <code>rest</code>). These functions are implemented using
    <i>macros</i> and <i>templates</i> and use <code>cp@</code>
    to copy either the first or the rest of the values.
  </p>

  .INCLUDE: dev/doc/book/examples/dern/macrosAndTemplates.dern

  <p>
    Below is an example of using these macros. Please note,
    that if the macros are not defined in the same directory
    with the Dern REPL executable, you must add the directory
    containing the macro definitions into the include path
    using <code>-I</code> command line switch:
  </p>

  .INCLUDE: dev/doc/book/examples/dern/macrosAndTemplatesUsage.dern

  <h2>Accessing and manipulating command line arguments and environment variables</h2>

  <p>


@@ 876,6 904,12 @@

  .INCLUDE: dev/doc/book/examples/dern/varArgs.dern

  <p>
    As can be seen from the examples above, the last formal parameter
    name before <code>...</code> will contain all the additional
    arguments.
  </p>

  <h2>Environments</h2>

  <p>

A dev/doc/book/examples/dern/macrosAndTemplates.dern => dev/doc/book/examples/dern/macrosAndTemplates.dern +57 -0
@@ 0,0 1,57 @@
(define first as (macro (container)
  (if (== (len container) {D+0}) (return nil))
  (define tmp as (cp@ container {D+0}) [tmp])
  (quote tmp))
  [Return a copy of the first value in a container]
  '(container [container])
  howto-ok)

(define car as (macro (container)
  (define tmp as `(first ,container) [tmp])
  (quote tmp))
  [Return a copy of the first value in a container]
  '(container [container])
  howto-ok)

(define rest as (macro (container)
  (if (<= (len container) {D+1})
    nil
    (do
      (define tmp as (cp@ container {D+1} {D-1}) [tmp])
      (quote tmp))))
  [Return a vector holding copies of all but the first value of a container]
  '(container [container])
  howto-ok)

(define cdr as (macro (container)
  (define tmp as `(rest ,container) [tmp])
  (quote tmp))
  [Return a vector holding copies of all but the first value of a container]
  '(container [container])
  howto-ok)

(define when as (macro (cond action)
  `(if ,cond ,action nil))
  [if without else branch] '(cond [cond] action [action]) howto-ok)

(define ensure-vector as (macro (v)
   (if (vector? v) (return (quote v)))
   (define tmp as `(vector ,v) [vector to be returned])
   (quote tmp))
  [ensure given value is a vector] '(v [value]) howto-ok)

(define ->> as (macro (x forms ...)
  (if (== forms nil) (return x))
  (define num-forms as (len forms) [number of forms])
  (if (== {D+0} num-forms) (return (quote x)))
  (define first-form as `(ensure-vector (car ,forms)) [currently first form])
  (= first-form (eval first-form))
  (+= first-form (template ,x))
  (= first-form (eval first-form))
  (define rest-forms as `(cdr ,forms) [forms without the first])
  (= rest-forms (eval rest-forms))
  (if (== rest-forms nil) (return first-form))
  `(->> ,first-form ,@ rest-forms))
  [Threads the expr through the forms]
  '(x [expression] forms [forms to thread through] ... [varargs])
  howto-ok)

A dev/doc/book/examples/dern/macrosAndTemplatesUsage.dern => dev/doc/book/examples/dern/macrosAndTemplatesUsage.dern +28 -0
@@ 0,0 1,28 @@
; Run these examples with command:
;
;   ./octaspire-dern-repl -I release/examples
;
; or
;
;   ./octaspire-dern-repl -I examples
;
; depending the directory you are in.

(require 'dern_util)

(when true  (println [you should see this]))
(when false (println [you should NOT see this]))

(first (|a| |b| |c|))                     ; |a|
(car   (|a| |b| |c|))

(first ((|a| |b|) (|c| |d|) (|e| |f|)))   ; (|a| |b|)
(car   ((|a| |b|) (|c| |d|) (|e| |f|)))

(rest  (|a| |b| |c|))                     ; (|b| |c|)
(cdr   (|a| |b| |c|))

(rest  ((|a| |b|) (|c| |d|) (|e| |f|)))   ; ((|c| |d|) (|e| |f|))
(cdr   ((|a| |b|) (|c| |d|) (|e| |f|)))

(->> |a| (+ |b|) (+ |c|) (+ |d|))         ; [dcba]

M dev/doc/book/examples/dern/selectingFromCollection.dern => dev/doc/book/examples/dern/selectingFromCollection.dern +4 -0
@@ 19,3 19,7 @@

(cp@ (vector |a| |b| |c|) {D+1})        ; |b|
(cp@ (hash-map |a| [abc]) {D+0} 'index) ; [abc]

; Ranges

(cp@ '(|a| |b| |c| |d|) {D+1} {D-1})    ; (|b| |c| |d|)

M dev/external/octaspire_core => dev/external/octaspire_core +1 -1
@@ 1,1 1,1 @@
Subproject commit 5554612e099397a4063d19b533dede7b558dcced
Subproject commit 9261d6c0d0e12f83a6bde87b1719fa1236929e38

M dev/include/octaspire/dern/octaspire_dern_config.h => dev/include/octaspire/dern/octaspire_dern_config.h +1 -1
@@ 18,7 18,7 @@ limitations under the License.
#define OCTASPIRE_DERN_CONFIG_H

#define OCTASPIRE_DERN_CONFIG_VERSION_MAJOR "0"
#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "486"
#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "487"
#define OCTASPIRE_DERN_CONFIG_VERSION_PATCH "0"

#define OCTASPIRE_DERN_CONFIG_VERSION_STR "Octaspire Dern version " \

M dev/include/octaspire/dern/octaspire_dern_lexer.h => dev/include/octaspire/dern/octaspire_dern_lexer.h +1 -0
@@ 36,6 36,7 @@ typedef enum
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL,

M dev/include/octaspire/dern/octaspire_dern_stdlib.h => dev/include/octaspire/dern/octaspire_dern_stdlib.h +10 -0
@@ 419,11 419,21 @@ octaspire_dern_value_t *octaspire_dern_vm_special_greater_than_or_equal(
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_special_template(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_special_fn(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_special_macro(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_builtin_uid(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,

M dev/include/octaspire/dern/octaspire_dern_value.h => dev/include/octaspire/dern/octaspire_dern_value.h +14 -0
@@ 55,6 55,7 @@ typedef enum
    OCTASPIRE_DERN_VALUE_TAG_LIST,
    OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT,
    OCTASPIRE_DERN_VALUE_TAG_FUNCTION,
    OCTASPIRE_DERN_VALUE_TAG_MACRO,
    OCTASPIRE_DERN_VALUE_TAG_SPECIAL,
    OCTASPIRE_DERN_VALUE_TAG_BUILTIN,
    OCTASPIRE_DERN_VALUE_TAG_PORT,


@@ 373,6 374,9 @@ struct octaspire_dern_environment_t const *octaspire_dern_value_as_environment_g
bool octaspire_dern_value_is_function(
    octaspire_dern_value_t const * const self);

bool octaspire_dern_value_is_macro(
    octaspire_dern_value_t const * const self);

bool octaspire_dern_value_is_builtin(
    octaspire_dern_value_t const * const self);



@@ 429,6 433,9 @@ double octaspire_dern_value_as_number_get_value(
octaspire_dern_function_t *octaspire_dern_value_as_function(
    octaspire_dern_value_t * const self);

octaspire_dern_function_t *octaspire_dern_value_as_macro(
    octaspire_dern_value_t * const self);

bool octaspire_dern_value_as_hash_map_add(
    octaspire_dern_value_t * const self,
    octaspire_dern_value_t * const toBeAdded1,


@@ 564,6 571,10 @@ bool octaspire_dern_value_is_symbol_and_equal_to_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str);

bool octaspire_dern_value_is_symbol_and_starts_with_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str);

bool octaspire_dern_value_as_symbol_is_equal_to_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str);


@@ 588,6 599,9 @@ octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
size_t octaspire_dern_value_as_text_get_length_in_octets(
    octaspire_dern_value_t const * const self);

size_t octaspire_dern_value_as_text_get_length_in_ucs_characters(
    octaspire_dern_value_t const * const self);

bool octaspire_dern_value_as_vector_is_index_valid(
    octaspire_dern_value_t const * const self,
    ptrdiff_t const possiblyNegativeIndex);

M dev/include/octaspire/dern/octaspire_dern_vm.h => dev/include/octaspire/dern/octaspire_dern_vm.h +6 -0
@@ 191,6 191,12 @@ struct octaspire_dern_value_t *octaspire_dern_vm_create_new_value_function(
    char const * const docstr,
    octaspire_vector_t *docVec);

struct octaspire_dern_value_t *octaspire_dern_vm_create_new_value_macro(
    octaspire_dern_vm_t *self,
    octaspire_dern_function_t * const value,
    char const * const docstr,
    octaspire_vector_t *docVec);

struct octaspire_dern_value_t *octaspire_dern_vm_create_new_value_special(
    octaspire_dern_vm_t *self,
    octaspire_dern_special_t * const value,

M dev/src/octaspire_dern_lexer.c => dev/src/octaspire_dern_lexer.c +103 -0
@@ 60,6 60,7 @@ static char const * const octaspire_dern_lexer_private_token_tag_types_as_c_stri
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL",


@@ 108,6 109,13 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_quote(
    size_t const startColumn,
    size_t const startIndexInInput);

octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_back_quote(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,
    size_t const startLine,
    size_t const startColumn,
    size_t const startIndexInInput);

octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_integer_or_real_number(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,


@@ 208,6 216,7 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_token_new(
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL:


@@ 449,6 458,7 @@ void octaspire_dern_lexer_token_release(
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL:


@@ 653,6 663,7 @@ bool octaspire_dern_lexer_token_is_equal(
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL:


@@ 710,6 721,16 @@ octaspire_string_t *octaspire_dern_lexer_token_to_string(
            return result;
        }

        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        {
            if (!octaspire_string_concatenate_c_string(result, "back quote"))
            {
                return 0;
            }

            return result;
        }

        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        {
            if (!octaspire_string_concatenate_c_string(result, "true"))


@@ 1336,6 1357,78 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_quote(
    }
}

octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_back_quote(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,
    size_t const startLine,
    size_t const startColumn,
    size_t const startIndexInInput)
{
    size_t endIndexInInput = startIndexInInput;

    if (octaspire_input_is_good(input))
    {
        endIndexInInput  = octaspire_input_get_ucs_character_index(input);
        uint32_t const c = octaspire_input_peek_next_ucs_character(input);

        if (c == '`')
        {
            octaspire_dern_lexer_token_t *result = octaspire_dern_lexer_token_new(
                OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE,
                0,
                octaspire_dern_lexer_token_position_init(
                    startLine,
                    octaspire_input_get_line_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startColumn,
                    octaspire_input_get_column_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startIndexInInput,
                    endIndexInInput),
                allocator);

            if (!octaspire_input_pop_next_ucs_character(input))
            {
                abort();
            }

            return result;
        }
        else
        {
            return octaspire_dern_lexer_token_new(
                OCTASPIRE_DERN_LEXER_TOKEN_TAG_ERROR,
                "Back quote ` expected",
                octaspire_dern_lexer_token_position_init(
                    startLine,
                    octaspire_input_get_line_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startColumn,
                    octaspire_input_get_column_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startIndexInInput,
                    endIndexInInput),
                allocator);
        }
    }
    else
    {
        return octaspire_dern_lexer_token_new(
            OCTASPIRE_DERN_LEXER_TOKEN_TAG_ERROR,
            "Back quote ` expected",
            octaspire_dern_lexer_token_position_init(
                startLine,
                octaspire_input_get_line_number(input)),
            octaspire_dern_lexer_token_position_init(
                startColumn,
                octaspire_input_get_column_number(input)),
            octaspire_dern_lexer_token_position_init(
                startIndexInInput,
                endIndexInInput),
            allocator);
    }
}

static octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_expect_octet(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,


@@ 2876,6 2969,16 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_pop_next_token(
                    startIndexInInput);
            }

            case '`':
            {
                return octaspire_dern_lexer_private_pop_back_quote(
                    input,
                    allocator,
                    startLine,
                    startColumn,
                    startIndexInInput);
            }

            case '-':
            {
                return octaspire_dern_lexer_private_pop_true_or_false_or_nil_or_symbol(

M dev/src/octaspire_dern_stdlib.c => dev/src/octaspire_dern_stdlib.c +842 -68
@@ 1164,7 1164,8 @@ octaspire_dern_value_t *octaspire_dern_vm_special_define(
    }
    else if (numArgs == 6)
    {
        if (octaspire_dern_value_is_function(evaluatedThirdArg))
        if (octaspire_dern_value_is_function(evaluatedThirdArg) ||
            octaspire_dern_value_is_macro(evaluatedThirdArg))
        {
            octaspire_dern_value_t *result =
                octaspire_dern_vm_special_private_define_fun_no_env(


@@ 3181,6 3182,405 @@ octaspire_dern_value_t *octaspire_dern_vm_special_greater_than_or_equal(
    return octaspire_dern_vm_get_value_true(vm);
}

static size_t octaspire_dern_vm_private_template_helper(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t * arguments,
    size_t * currentIndex,
    octaspire_dern_value_t *environment,
    octaspire_dern_value_t **result)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
    char   const * const dernFuncName = "template";
    size_t const numArgs = octaspire_dern_value_get_length(arguments);

    octaspire_dern_value_t * value =
        octaspire_dern_value_as_vector_get_element_at(arguments, *currentIndex);

    octaspire_helpers_verify_not_null(value);

    if (octaspire_dern_value_is_symbol_and_equal_to_c_string(
            value,
            ","))
    {
        if (*currentIndex == (numArgs - 1))
        {
            octaspire_dern_value_t * tmpVal =
                octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Special '%s' expects a value after %zu. argument ','.",
                    dernFuncName,
                    (*currentIndex + 1));

            octaspire_helpers_verify_true(
                octaspire_dern_vm_push_value(vm, tmpVal));


            if (*result == 0)
            {
                *result = tmpVal;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &tmpVal));
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, tmpVal));

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }

        ++(*currentIndex);

        value = octaspire_dern_value_as_vector_get_element_at(
            arguments,
            *currentIndex);

        octaspire_helpers_verify_not_null(value);

        octaspire_dern_value_t * tmpVal =
            octaspire_dern_vm_eval(vm, value, environment);

        octaspire_helpers_verify_not_null(tmpVal);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, tmpVal));

        if (*result == 0)
        {
            *result = tmpVal;
        }
        else
        {
            octaspire_helpers_verify_true(
                octaspire_dern_value_as_vector_push_back_element(
                    *result,
                    &tmpVal));
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, tmpVal));

        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        ++(*currentIndex);
        return 2;
    }
    else if (octaspire_dern_value_is_symbol_and_equal_to_c_string(
                 value,
                 ",@"))
    {
        if (*currentIndex == (numArgs - 1))
        {
            octaspire_dern_value_t * tmpVal =
                octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Special '%s' expects a value after %zu. argument ',@'.",
                    dernFuncName,
                    (*currentIndex + 1));

            octaspire_helpers_verify_true(
                octaspire_dern_vm_push_value(vm, tmpVal));

            if (*result == 0)
            {
                *result = tmpVal;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &tmpVal));
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, tmpVal));

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }

        ++(*currentIndex);

        value = octaspire_dern_value_as_vector_get_element_at(
            arguments,
            *currentIndex);

        octaspire_helpers_verify_not_null(value);

        octaspire_dern_value_t * tmpVal =
            octaspire_dern_vm_eval(vm, value, environment);

        octaspire_helpers_verify_not_null(tmpVal);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, tmpVal));

        if (octaspire_dern_value_is_vector(tmpVal))
        {
            if (*result == 0)
            {
                *result = tmpVal;
            }
            else
            {
                for (size_t i = 0;
                     i < octaspire_dern_value_as_vector_get_length(tmpVal);
                     ++i)
                {
                    octaspire_dern_value_t * const valueFromVector =
                        octaspire_dern_value_as_vector_get_element_at(
                            tmpVal,
                            i);

                    octaspire_helpers_verify_true(
                        octaspire_dern_value_as_vector_push_back_element(
                            *result,
                            &valueFromVector));
                }
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, tmpVal));

            ++(*currentIndex);
            return 2;
        }

        if (*result == 0)
        {
            *result = tmpVal;
        }
        else
        {
            octaspire_helpers_verify_true(
                octaspire_dern_value_as_vector_push_back_element(
                    *result,
                    &tmpVal));
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, tmpVal));

        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        ++(*currentIndex);
        return 2;
    }
    else if (octaspire_dern_value_is_symbol_and_starts_with_c_string(
                 value,
                 ","))
    {
        octaspire_string_t * renamedStr =
            octaspire_string_new(
                octaspire_dern_value_as_symbol_get_c_string(value),
                octaspire_dern_vm_get_allocator(vm));

        octaspire_helpers_verify_not_null(renamedStr);

        octaspire_helpers_verify_true(
            octaspire_string_pop_front_ucs_character(renamedStr));

        octaspire_dern_value_t * const renamedVal =
            octaspire_dern_vm_create_new_value_symbol_from_c_string(
                vm,
                octaspire_string_get_c_string(renamedStr));

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, renamedVal));

        octaspire_string_release(renamedStr);
        renamedStr = 0;

        octaspire_dern_value_t * const tmpVal =
            octaspire_dern_vm_eval(vm, renamedVal, environment);

        octaspire_helpers_verify_not_null(tmpVal);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, tmpVal));

        if (*result == 0)
        {
            *result = tmpVal;
        }
        else
        {
            octaspire_helpers_verify_true(
                octaspire_dern_value_as_vector_push_back_element(
                    *result,
                    &tmpVal));
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, tmpVal));

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, renamedVal));

        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        ++(*currentIndex);
        return 1;
    }
    else
    {
        if (octaspire_dern_value_is_vector(value))
        {
            octaspire_dern_value_t * innerVecVal =
                octaspire_dern_vm_create_new_value_vector(vm);

            octaspire_helpers_verify_not_null(innerVecVal);

            octaspire_helpers_verify_true(
                octaspire_dern_vm_push_value(vm, innerVecVal));


            size_t currentIndex2 = 0;

            size_t const numArgs2 =
                octaspire_dern_value_as_vector_get_length(value);

            while (true)
            {
                // Recursive step.
                octaspire_dern_vm_private_template_helper(
                    vm,
                    value,
                    &currentIndex2,
                    environment,
                    &innerVecVal);

                if (currentIndex2 >= numArgs2)
                {
                    break;
                }
            }

            if (*result == 0)
            {
                *result = innerVecVal;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &innerVecVal));
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, innerVecVal));

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }
        else
        {
            if (*result == 0)
            {
                *result = value;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &value));
            }

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }
    }
}

octaspire_dern_value_t *octaspire_dern_vm_special_template(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);

    octaspire_helpers_verify_true(
        arguments->typeTag == OCTASPIRE_DERN_VALUE_TAG_VECTOR);

    octaspire_helpers_verify_true(
        environment->typeTag == OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT);

    size_t const numArgs = octaspire_dern_value_get_length(arguments);

    octaspire_helpers_verify_true(
        octaspire_dern_vm_push_value(vm, arguments));

    octaspire_dern_value_t * result = 0;

    if (numArgs > 1)
    {
        result = octaspire_dern_vm_create_new_value_vector(vm);
        octaspire_helpers_verify_not_null(result);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, result));
    }

    size_t i = 0;

    while (true)
    {
        size_t const prevI = i;

        size_t const delta = octaspire_dern_vm_private_template_helper(
            vm,
            arguments,
            &i,
            environment,
            &result);

        octaspire_helpers_verify_true(delta >= 1 && delta <= 2);
        octaspire_helpers_verify_true((prevI + delta) == i);

        if (i >= numArgs)
        {
            break;
        }
    }

    if (numArgs > 1)
    {
        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, result));
    }

    octaspire_helpers_verify_true(
        octaspire_dern_vm_pop_value(vm, arguments));

    octaspire_helpers_verify_true(
        stackLength == octaspire_dern_vm_get_stack_length(vm));

    return result;
}

octaspire_dern_value_t *octaspire_dern_stdlib_private_validate_function(
    octaspire_dern_vm_t* vm,
    octaspire_dern_function_t *function)


@@ 3259,37 3659,156 @@ octaspire_dern_value_t *octaspire_dern_stdlib_private_validate_function(
    if (numNormalArgsAfterDot > 1)
    {
        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_format(
        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "Function can have only one formal argument after . "
            "for varargs. Now %zu formals were given after dot.",
            numNormalArgsAfterDot);
    }

    if (numDotArgs == 0 && numNormalArgs != numFormalArgs)
    {
        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "Number of formal and actual arguments must be equal for functions without "
            "varargs using the dot-formal. Now %zu formal and %zu actual arguments were given.",
            numFormalArgs,
            numNormalArgs);
    }

    octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
    return 0;
}

octaspire_dern_value_t *octaspire_dern_vm_special_fn(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);

    octaspire_helpers_verify_true(arguments->typeTag   == OCTASPIRE_DERN_VALUE_TAG_VECTOR);
    octaspire_helpers_verify_true(environment->typeTag == OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT);

    octaspire_dern_vm_push_value(vm, arguments);
    octaspire_dern_vm_push_value(vm, environment);

    octaspire_vector_t * const vec = arguments->value.vector;

    if (octaspire_vector_get_length(vec) < 2)
    {
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "Special 'fn' expects at least two arguments. %zu arguments were given.",
            octaspire_vector_get_length(vec));
    }

    octaspire_dern_value_t *formals = octaspire_vector_get_element_at(vec, 0);

    if (formals->typeTag != OCTASPIRE_DERN_VALUE_TAG_VECTOR)
    {
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "First argument to special 'fn' must be vector (formals). Type '%s' was given.",
            octaspire_dern_value_helper_get_type_as_c_string(formals->typeTag));
    }

    octaspire_dern_value_t *body = octaspire_dern_vm_create_new_value_vector(vm);

    octaspire_dern_vm_push_value(vm, body);

    for (size_t i = 1; i < octaspire_vector_get_length(vec); ++i)
    {
        octaspire_dern_value_t *tmpPtr =
            octaspire_vector_get_element_at(
                vec,
                (ptrdiff_t)i);

        if (tmpPtr->typeTag == OCTASPIRE_DERN_VALUE_TAG_ERROR)
        {
            octaspire_dern_vm_pop_value(vm, body);
            octaspire_dern_vm_pop_value(vm, environment);
            octaspire_dern_vm_pop_value(vm, arguments);

            octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
            return tmpPtr;
        }

        if (!octaspire_dern_value_as_vector_push_back_element(
            body,
            &tmpPtr))
        {
            abort();
        }
    }

    octaspire_dern_function_t *function = octaspire_dern_function_new(
        formals,
        body,
        environment,
        octaspire_dern_vm_get_allocator(vm));

    if (!function)
    {
        octaspire_dern_vm_pop_value(vm, body);
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_from_c_string(
            vm,
            "Function can have only one formal argument after . "
            "for varargs. Now %zu formals were given after dot.",
            numNormalArgsAfterDot);
            "Allocation failure when creating function.");
    }

    if (numDotArgs == 0 && numNormalArgs != numFormalArgs)
    octaspire_dern_value_t *error = octaspire_dern_stdlib_private_validate_function(vm, function);

    if (error)
    {
        octaspire_dern_vm_pop_value(vm, body);
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_dern_function_release(function);
        function = 0;

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "Number of formal and actual arguments must be equal for functions without "
            "varargs using the dot-formal. Now %zu formal and %zu actual arguments were given.",
            numFormalArgs,
            numNormalArgs);
        return error;
    }

    // Real docstring is set by define
    octaspire_dern_value_t * result =
        octaspire_dern_vm_create_new_value_function(vm, function, "", 0);

    octaspire_dern_vm_pop_value(vm, body);
    octaspire_dern_vm_pop_value(vm, environment);
    octaspire_dern_vm_pop_value(vm, arguments);

    octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
    return 0;
    return result;
}

octaspire_dern_value_t *octaspire_dern_vm_special_fn(
octaspire_dern_value_t *octaspire_dern_vm_special_macro(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
    char   const * const dernFuncName = "macro";

    octaspire_helpers_verify_true(arguments->typeTag   == OCTASPIRE_DERN_VALUE_TAG_VECTOR);
    octaspire_helpers_verify_true(environment->typeTag == OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT);
    octaspire_helpers_verify_true(
        arguments->typeTag == OCTASPIRE_DERN_VALUE_TAG_VECTOR);

    octaspire_helpers_verify_true(
        environment->typeTag == OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT);

    octaspire_dern_vm_push_value(vm, arguments);
    octaspire_dern_vm_push_value(vm, environment);


@@ 3301,10 3820,13 @@ octaspire_dern_value_t *octaspire_dern_vm_special_fn(
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "Special 'fn' expects at least two arguments. %zu arguments were given.",
            "Special '%s' expects at least two arguments. %zu arguments were given.",
            dernFuncName,
            octaspire_vector_get_length(vec));
    }



@@ 3315,10 3837,13 @@ octaspire_dern_value_t *octaspire_dern_vm_special_fn(
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "First argument to special 'fn' must be vector (formals). Type '%s' was given.",
            "First argument to special '%s' must be vector (formals). Type '%s' was given.",
            dernFuncName,
            octaspire_dern_value_helper_get_type_as_c_string(formals->typeTag));
    }



@@ 3339,7 3864,9 @@ octaspire_dern_value_t *octaspire_dern_vm_special_fn(
            octaspire_dern_vm_pop_value(vm, environment);
            octaspire_dern_vm_pop_value(vm, arguments);

            octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            return tmpPtr;
        }



@@ 3363,13 3890,16 @@ octaspire_dern_value_t *octaspire_dern_vm_special_fn(
        octaspire_dern_vm_pop_value(vm, environment);
        octaspire_dern_vm_pop_value(vm, arguments);

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        return octaspire_dern_vm_create_new_value_error_from_c_string(
            vm,
            "Allocation failure when creating function.");
            "Allocation failure when creating macro.");
    }

    octaspire_dern_value_t *error = octaspire_dern_stdlib_private_validate_function(vm, function);
    octaspire_dern_value_t *error =
        octaspire_dern_stdlib_private_validate_function(vm, function);

    if (error)
    {


@@ 3380,19 3910,23 @@ octaspire_dern_value_t *octaspire_dern_vm_special_fn(
        octaspire_dern_function_release(function);
        function = 0;

        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        return error;
    }

    // Real docstring is set by define
    octaspire_dern_value_t * result =
        octaspire_dern_vm_create_new_value_function(vm, function, "", 0);
        octaspire_dern_vm_create_new_value_macro(vm, function, "", 0);

    octaspire_dern_vm_pop_value(vm, body);
    octaspire_dern_vm_pop_value(vm, environment);
    octaspire_dern_vm_pop_value(vm, arguments);

    octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
    octaspire_helpers_verify_true(
        stackLength == octaspire_dern_vm_get_stack_length(vm));

    return result;
}



@@ 5562,6 6096,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_minus_equals(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 5619,6 6154,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_minus_equals_equals(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 5763,6 6299,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_pop_back(
        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:


@@ 5866,6 6403,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_pop_front(
        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:


@@ 6851,6 7389,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_plus_equals(
        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:


@@ 7179,6 7718,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_slash(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7249,6 7789,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_slash(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7361,6 7902,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_times(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7458,6 8000,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_plus_numerical(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7566,6 8109,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_plus_textual_string(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7666,6 8210,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_plus_textual_char(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7773,6 8318,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_plus_textual_symbol(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7866,6 8412,7 @@ static octaspire_dern_value_t *octaspire_dern_vm_builtin_private_plus_semver(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 7958,6 8505,7 @@ static octaspire_dern_value_t *octaspire_dern_vm_builtin_private_minus_semver(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 8045,6 8593,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_plus_vector(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 8258,6 8807,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_minus_numerical(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 8359,6 8909,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_private_minus_textual(
            case OCTASPIRE_DERN_VALUE_TAG_LIST:
            case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
            case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 8493,6 9044,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_plus(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 8562,6 9114,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_minus(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 8761,6 9314,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_split(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 9570,6 10124,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_ln_at_sign(
        case OCTASPIRE_DERN_VALUE_TAG_ERROR:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 9595,6 10150,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_cp_at_sign(
    octaspire_dern_value_t *environment)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
    char   const * const dernFuncName = "cp@";

    octaspire_helpers_verify_true(arguments->typeTag   == OCTASPIRE_DERN_VALUE_TAG_VECTOR);
    octaspire_helpers_verify_true(environment->typeTag == OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT);


@@ 9603,10 10159,13 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_cp_at_sign(

    if (numArgs < 2)
    {
        octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
        return octaspire_dern_vm_create_new_value_error_from_c_string(
        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        return octaspire_dern_vm_create_new_value_error_format(
            vm,
            "Builtin 'cp@' expects at least two arguments.");
            "Builtin '%s' expects at least two arguments.",
            dernFuncName);
    }

    octaspire_dern_value_t * const collectionVal =


@@ 9624,104 10183,317 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_cp_at_sign(
        case OCTASPIRE_DERN_VALUE_TAG_STRING:
        case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
        {
            if (numArgs > 2)
            if (numArgs > 3)
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return octaspire_dern_vm_create_new_value_error_from_c_string(
                return octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Builtin 'cp@' expects exactly two arguments when used "
                    "with text (string or symbol).");
                    "Builtin '%s' expects two or three arguments when used "
                    "with text (string or symbol).",
                    dernFuncName);
            }

            octaspire_dern_value_t const * const indexVal =
                octaspire_dern_value_as_vector_get_element_at_const(arguments, 1);
            // First index

            octaspire_helpers_verify_not_null(indexVal);
            octaspire_dern_number_or_unpushed_error_const_t numberOrError =
                octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
                    arguments,
                    1,
                    dernFuncName);

            if (!octaspire_dern_value_is_integer(indexVal))
            if (numberOrError.unpushedError)
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return numberOrError.unpushedError;
            }

            ptrdiff_t index1 = numberOrError.number;
            ptrdiff_t index2 = index1;

            if (numArgs == 3)
            {
                // Second index

                numberOrError =
                    octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
                        arguments,
                        2,
                        dernFuncName);

                if (numberOrError.unpushedError)
                {
                    octaspire_helpers_verify_true(
                        stackLength == octaspire_dern_vm_get_stack_length(vm));

                    return numberOrError.unpushedError;
                }

                index2 = numberOrError.number;
            }

            if (!octaspire_dern_value_as_text_is_index_valid(
                    collectionVal,
                    index1))
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Builtin 'cp@' expects integer as second argument when "
                    "indexing a text value (string or symbol). "
                    "Now type '%s' was given.",
                    octaspire_dern_value_helper_get_type_as_c_string(
                        indexVal->typeTag));
                    "First index to builtin '%s' is not valid for the given text "
                    "value (string or symbol). "
#ifdef __AROS__
                    "Index '%ld' was given.",
#else
                    "Index '%td' was given.",
#endif
                    dernFuncName,
                    index1);
            }

            ptrdiff_t const index =
                (ptrdiff_t)octaspire_dern_value_as_integer_get_value(indexVal);

            if (!octaspire_dern_value_as_text_is_index_valid(
                    collectionVal,
                    index))
                    index2))
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Index to builtin 'cp@' is not valid for the given text "
                    "Second index to builtin '%s' is not valid for the given text "
                    "value (string or symbol). "
#ifdef __AROS__
                    "Index '%ld' was given.",
#else
                    "Index '%td' was given.",
#endif
                    index);
                    dernFuncName,
                    index2);
            }

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            return octaspire_dern_vm_create_new_value_character_from_uint32t(
                vm,
                octaspire_dern_value_as_text_get_ucs_character_at_index(
                    collectionVal,
                    index));
            if (index1 == index2)
            {
                return octaspire_dern_vm_create_new_value_character_from_uint32t(
                    vm,
                    octaspire_dern_value_as_text_get_ucs_character_at_index(
                        collectionVal,
                        index1));
            }

            octaspire_dern_value_t * const result =
                octaspire_dern_vm_create_new_value_vector(vm);

            octaspire_helpers_verify_not_null(result);

            if (index1 < 0)
            {
                index1 =
                    octaspire_dern_value_as_text_get_length_in_ucs_characters(
                        collectionVal) +
                    index1;
            }

            if (index2 < 0)
            {
                index2 =
                    octaspire_dern_value_as_text_get_length_in_ucs_characters(
                        collectionVal) +
                    index2;
            }

            ptrdiff_t index = index1;

            octaspire_helpers_verify_true(index <= index2);

            while (true)
            {
                octaspire_dern_value_t * const charVal =
                    octaspire_dern_vm_create_new_value_character_from_uint32t(
                        vm,
                        octaspire_dern_value_as_text_get_ucs_character_at_index(
                            collectionVal,
                            index));

                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        result,
                        &charVal));

                if (index == index2)
                {
                    break;
                }

                ++index;
            }

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            return result;
        }

        case OCTASPIRE_DERN_VALUE_TAG_VECTOR:
        {
            if (numArgs > 2)
            if (numArgs > 3)
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return octaspire_dern_vm_create_new_value_error_from_c_string(
                return octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Builtin 'cp@' expects exactly two arguments when used with vector.");
                    "Builtin '%s' expects two or three arguments when used with vector.",
                    dernFuncName);
            }

            octaspire_dern_value_t const * const indexVal =
                octaspire_dern_value_as_vector_get_element_at_const(arguments, 1);
            // First index

            octaspire_helpers_verify_not_null(indexVal);
            octaspire_dern_number_or_unpushed_error_const_t numberOrError =
                octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
                    arguments,
                    1,
                    dernFuncName);

            if (!octaspire_dern_value_is_integer(indexVal))
            if (numberOrError.unpushedError)
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return numberOrError.unpushedError;
            }

            ptrdiff_t index1 = numberOrError.number;
            ptrdiff_t index2 = index1;

            if (!octaspire_dern_value_as_vector_is_index_valid(
                    collectionVal,
                    index1))
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Builtin 'cp@' expects integer as second argument when indexing a vector. "
                    "Now type '%s' was given.",
                    octaspire_dern_value_helper_get_type_as_c_string(
                        indexVal->typeTag));
                    "First index to builtin '%s' is not valid for the given vector "
                    "value. "
#ifdef __AROS__
                    "Index '%ld' was given.",
#else
                    "Index '%td' was given.",
#endif
                    dernFuncName,
                    index1);
            }

            octaspire_helpers_verify_true(stackLength == octaspire_dern_vm_get_stack_length(vm));
            return octaspire_dern_vm_create_new_value_copy(
            if (numArgs == 3)
            {
                // Second index

                numberOrError =
                    octaspire_dern_value_as_vector_get_element_at_as_number_or_unpushed_error_const(
                        arguments,
                        2,
                        dernFuncName);

                if (numberOrError.unpushedError)
                {
                    octaspire_helpers_verify_true(
                        stackLength == octaspire_dern_vm_get_stack_length(vm));

                    return numberOrError.unpushedError;
                }

                index2 = numberOrError.number;

                if (!octaspire_dern_value_as_vector_is_index_valid(
                        collectionVal,
                        index2))
                {
                    octaspire_helpers_verify_true(
                        stackLength == octaspire_dern_vm_get_stack_length(vm));

                    return octaspire_dern_vm_create_new_value_error_format(
                        vm,
                        "Second index to builtin '%s' is not valid for the given vector "
                        "value. "
#ifdef __AROS__
                        "Index '%ld' was given.",
#else
                        "Index '%td' was given.",
#endif
                        dernFuncName,
                        index2);
                }
            }

            if (index1 == index2)
            {
                octaspire_helpers_verify_true(
                    stackLength == octaspire_dern_vm_get_stack_length(vm));

                return octaspire_dern_vm_create_new_value_copy(
                    vm,
                    octaspire_dern_value_as_vector_get_element_at(
                        collectionVal,
                        octaspire_dern_value_as_integer_get_value(indexVal)));
                        index1));
            }

            octaspire_dern_value_t * const result =
                octaspire_dern_vm_create_new_value_vector(vm);

            octaspire_helpers_verify_not_null(result);

            if (index1 < 0)
            {
                index1 =
                    octaspire_dern_value_as_vector_get_length(
                        collectionVal) +
                    index1;
            }

            if (index2 < 0)
            {
                index2 =
                    octaspire_dern_value_as_vector_get_length(
                        collectionVal) +
                    index2;
            }

            ptrdiff_t index = index1;

            while (true)
            {
                octaspire_dern_value_t * const copiedVal =
                    octaspire_dern_vm_create_new_value_copy(
                        vm,
                        octaspire_dern_value_as_vector_get_element_at(
                            collectionVal,
                            index));

                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        result,
                        &copiedVal));

                if (index == index2)
                {
                    break;
                }

                ++index;
            }

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            return result;
        }

        case OCTASPIRE_DERN_VALUE_TAG_HASH_MAP:


@@ 10008,6 10780,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_cp_at_sign(
        case OCTASPIRE_DERN_VALUE_TAG_ERROR:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 10684,6 11457,7 @@ octaspire_dern_value_t *octaspire_dern_vm_builtin_copy(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:

M dev/src/octaspire_dern_value.c => dev/src/octaspire_dern_value.c +133 -4
@@ 49,6 49,7 @@ static char const * const octaspire_dern_value_helper_type_tags_as_c_strings[] =
    "list",
    "environment",
    "function",
    "macro",
    "special",
    "builtin",
    "port",


@@ 992,6 993,7 @@ bool octaspire_dern_value_set(

        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 1216,6 1218,9 @@ uint32_t octaspire_dern_value_get_hash(
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
            return octaspire_helpers_calculate_hash_for_void_pointer_argument(self->value.function);

        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            return octaspire_helpers_calculate_hash_for_void_pointer_argument(self->value.function);

        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
            return octaspire_helpers_calculate_hash_for_void_pointer_argument(self->value.special);



@@ 1611,6 1616,26 @@ octaspire_string_t *octaspire_dern_private_value_to_string(
                return octaspire_dern_function_to_string(self->value.function, allocator);
            }

            case OCTASPIRE_DERN_VALUE_TAG_MACRO:
            {
                octaspire_string_t * tmpStr =
                    octaspire_dern_function_to_string(self->value.function, allocator);

                octaspire_helpers_verify_not_null(tmpStr);

                octaspire_string_t * const result = octaspire_string_new_format(
                    allocator,
                    "macro %s",
                    octaspire_string_get_c_string(tmpStr));

                octaspire_helpers_verify_not_null(result);

                octaspire_string_release(tmpStr);
                tmpStr = 0;

                return result;
            }

            case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
            {
                return octaspire_dern_builtin_to_string(self->value.builtin, allocator);


@@ 1795,6 1820,12 @@ bool octaspire_dern_value_is_function(
    return self->typeTag == OCTASPIRE_DERN_VALUE_TAG_FUNCTION;
}

bool octaspire_dern_value_is_macro(
    octaspire_dern_value_t const * const self)
{
    return self->typeTag == OCTASPIRE_DERN_VALUE_TAG_MACRO;
}

bool octaspire_dern_value_is_builtin(
    octaspire_dern_value_t const * const self)
{


@@ 1813,9 1844,10 @@ bool octaspire_dern_value_is_howto_allowed(
    // TODO XXX make user functions to support setting
    // howto
    octaspire_helpers_verify_true(
        octaspire_dern_value_is_builtin(self) ||
        octaspire_dern_value_is_special(self) ||
        octaspire_dern_value_is_function(self));
        octaspire_dern_value_is_builtin(self)  ||
        octaspire_dern_value_is_special(self)  ||
        octaspire_dern_value_is_function(self) ||
        octaspire_dern_value_is_macro(self));

    return self->howtoAllowed;
}


@@ 1950,6 1982,13 @@ octaspire_dern_function_t *octaspire_dern_value_as_function(
    return self->value.function;
}

octaspire_dern_function_t *octaspire_dern_value_as_macro(
    octaspire_dern_value_t * const self)
{
    octaspire_helpers_verify_true(self->typeTag == OCTASPIRE_DERN_VALUE_TAG_MACRO);
    return self->value.function;
}

bool octaspire_dern_value_as_hash_map_add(
    octaspire_dern_value_t * const self,
    octaspire_dern_value_t * const toBeAdded1,


@@ 2024,6 2063,7 @@ bool octaspire_dern_value_as_hash_map_add(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2179,6 2219,7 @@ bool octaspire_dern_value_as_character_add(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2253,6 2294,7 @@ bool octaspire_dern_value_as_character_subtract(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2359,6 2401,7 @@ bool octaspire_dern_value_as_integer_add(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2465,6 2508,7 @@ bool octaspire_dern_value_as_integer_subtract(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2514,6 2558,7 @@ bool octaspire_dern_value_as_semver_add_or_subtract(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2628,6 2673,7 @@ bool octaspire_dern_value_as_real_add(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2729,6 2775,7 @@ bool octaspire_dern_value_as_real_subtract(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2812,6 2859,7 @@ bool octaspire_dern_value_as_string_push_back(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 2895,6 2943,7 @@ bool octaspire_dern_value_as_symbol_push_back(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 3011,6 3060,7 @@ bool octaspire_dern_value_as_string_remove_all_substrings(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 3131,6 3181,18 @@ bool octaspire_dern_value_is_symbol_and_equal_to_c_string(
    return octaspire_string_is_equal_to_c_string(self->value.symbol, str);
}

bool octaspire_dern_value_is_symbol_and_starts_with_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str)
{
    if (self->typeTag != OCTASPIRE_DERN_VALUE_TAG_SYMBOL)
    {
        return false;
    }

    return octaspire_string_starts_with_c_string(self->value.symbol, str);
}

bool octaspire_dern_value_as_symbol_is_equal_to_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str)


@@ 3181,6 3243,7 @@ bool octaspire_dern_value_as_text_is_equal_to_c_string(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 3230,6 3293,7 @@ char const *octaspire_dern_value_as_text_get_c_string(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 3279,6 3343,7 @@ bool octaspire_dern_value_as_text_set_c_string(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 3329,6 3394,7 @@ octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 3389,6 3455,61 @@ size_t octaspire_dern_value_as_text_get_length_in_octets(
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:
        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:
        case OCTASPIRE_DERN_VALUE_TAG_SEMVER:
        {
            octaspire_helpers_verify_true(false);
        }
        break;
    }

    return 0;
}

size_t octaspire_dern_value_as_text_get_length_in_ucs_characters(
    octaspire_dern_value_t const * const self)
{
    switch (self->typeTag)
    {
        case OCTASPIRE_DERN_VALUE_TAG_ILLEGAL:
        {
            abort();
        }

        case OCTASPIRE_DERN_VALUE_TAG_CHARACTER:
        {
            return octaspire_string_get_length_in_ucs_characters(
                self->value.character);
        }

        case OCTASPIRE_DERN_VALUE_TAG_STRING:
        {
            return octaspire_string_get_length_in_ucs_characters(
                self->value.string);
        }

        case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
        {
            return octaspire_string_get_length_in_ucs_characters(
                self->value.symbol);
        }

        case OCTASPIRE_DERN_VALUE_TAG_NIL:
        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
        case OCTASPIRE_DERN_VALUE_TAG_INTEGER:
        case OCTASPIRE_DERN_VALUE_TAG_REAL:
        case OCTASPIRE_DERN_VALUE_TAG_ERROR:
        case OCTASPIRE_DERN_VALUE_TAG_VECTOR:
        case OCTASPIRE_DERN_VALUE_TAG_HASH_MAP:
        case OCTASPIRE_DERN_VALUE_TAG_QUEUE:
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:


@@ 4106,6 4227,10 @@ size_t octaspire_dern_value_get_length(
        }

        case OCTASPIRE_DERN_VALUE_TAG_NIL:
        {
            return 0;
        }

        case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
        case OCTASPIRE_DERN_VALUE_TAG_INTEGER:
        case OCTASPIRE_DERN_VALUE_TAG_REAL:


@@ 4151,6 4276,7 @@ size_t octaspire_dern_value_get_length(
        {
            return octaspire_dern_environment_get_length(self->value.environment);
        }
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        {
            return octaspire_dern_function_get_number_of_required_arguments(


@@ 4276,7 4402,8 @@ bool octaspire_dern_value_mark(octaspire_dern_value_t *self)
            }
        }
    }
    else if (self->typeTag == OCTASPIRE_DERN_VALUE_TAG_FUNCTION)
    else if (self->typeTag == OCTASPIRE_DERN_VALUE_TAG_FUNCTION ||
             self->typeTag == OCTASPIRE_DERN_VALUE_TAG_MACRO)
    {
        bool status = true;



@@ 4560,6 4687,7 @@ int octaspire_dern_value_compare(
                    self->value.environment,
                    other->value.environment);
        }
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        {
            return octaspire_dern_function_compare(


@@ 4621,6 4749,7 @@ bool octaspire_dern_value_is_atom(octaspire_dern_value_t const * const self)
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_C_DATA:

M dev/src/octaspire_dern_vm.c => dev/src/octaspire_dern_vm.c +256 -26
@@ 1444,6 1444,19 @@ octaspire_dern_vm_t *octaspire_dern_vm_new_with_config(
        abort();
    }

    // template
    if (!octaspire_dern_vm_create_and_register_new_special(
        self,
        "template",
        octaspire_dern_vm_special_template,
        1,
        "TODO",
        true,
        env))
    {
        abort();
    }

    // fn
    if (!octaspire_dern_vm_create_and_register_new_special(
        self,


@@ 1457,6 1470,19 @@ octaspire_dern_vm_t *octaspire_dern_vm_new_with_config(
        abort();
    }

    // macro
    if (!octaspire_dern_vm_create_and_register_new_special(
        self,
        "macro",
        octaspire_dern_vm_special_macro,
        2,
        "Create new anonymous macro",
        true,
        env))
    {
        abort();
    }

    // uid
    if (!octaspire_dern_vm_create_and_register_new_builtin(
        self,


@@ 1988,6 2014,7 @@ octaspire_dern_value_t *octaspire_dern_vm_create_new_value_copy(
        }
        break;

        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        {
            result->value.function = octaspire_dern_function_new_copy(


@@ 2594,6 2621,38 @@ octaspire_dern_value_t *octaspire_dern_vm_create_new_value_function(
    return result;
}

octaspire_dern_value_t *octaspire_dern_vm_create_new_value_macro(
    octaspire_dern_vm_t *self,
    octaspire_dern_function_t * const value,
    char const * const docstr,
    octaspire_vector_t *docVec)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(self);

    octaspire_dern_value_t *result =
        octaspire_dern_vm_private_create_new_value_struct(
            self,
            OCTASPIRE_DERN_VALUE_TAG_MACRO);

    octaspire_dern_vm_push_value(self, result);

    result->value.function = value;

    result->docstr = octaspire_dern_vm_create_new_value_string_from_c_string(
        self,
        docstr);

    result->docvec =
        docVec ? octaspire_dern_vm_create_new_value_vector_from_vector(self, docVec) : 0;

    octaspire_dern_vm_pop_value(self, result);

    octaspire_helpers_verify_true(
        stackLength == octaspire_dern_vm_get_stack_length(self));

    return result;
}

octaspire_dern_value_t *octaspire_dern_vm_create_new_value_special(
    octaspire_dern_vm_t *self,
    octaspire_dern_special_t * const value,


@@ 2801,6 2860,7 @@ void octaspire_dern_vm_clear_value_to_nil(
        }
        break;

        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        {
            octaspire_dern_function_release(value->value.function);


@@ 3171,6 3231,78 @@ octaspire_dern_value_t *octaspire_dern_vm_parse_token(
        }
        break;

        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        {
            octaspire_dern_value_t *templateValue = octaspire_dern_vm_parse(
                self,
                input);

            octaspire_dern_vm_push_value(self, templateValue);

            if (!templateValue || templateValue->typeTag == OCTASPIRE_DERN_VALUE_TAG_ERROR)
            {
                result = templateValue; // report error to caller
            }
            else
            {
                octaspire_dern_value_t *templateSym =
                    octaspire_dern_vm_create_new_value_symbol_from_c_string(
                        self,
                        "template");

                octaspire_helpers_verify_not_null(templateSym);
                octaspire_dern_vm_push_value(self, templateSym);

                if (octaspire_dern_value_is_vector(templateValue))
                {
                    if (!octaspire_dern_value_as_vector_push_front_element(
                            templateValue,
                            &templateSym))
                    {
                        abort();
                    }

                    result = templateValue;
                }
                else
                {
                    result = octaspire_dern_vm_create_new_value_vector(self);

                    if (!result)
                    {
                        result = octaspire_dern_vm_create_new_value_error_from_c_string(
                            self,
                            "Allocation failure");
                    }
                    else
                    {
                        octaspire_dern_vm_push_value(self, result);

                        if (!octaspire_dern_value_as_vector_push_back_element(
                                result,
                                &templateSym))
                        {
                            abort();
                        }

                        if (!octaspire_dern_value_as_vector_push_back_element(
                                result,
                                &templateValue))
                        {
                            abort();
                        }

                        octaspire_dern_vm_pop_value(self, result);
                    }
                }

                octaspire_dern_vm_pop_value(self, templateSym);
            }

            octaspire_dern_vm_pop_value(self, templateValue);
        }
        break;

        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        {
            result = octaspire_dern_vm_get_value_true(self);


@@ 3410,10 3542,11 @@ octaspire_dern_value_t *octaspire_dern_vm_call_lambda(
    return result;
}

octaspire_dern_value_t *octaspire_dern_vm_eval(
    octaspire_dern_vm_t *self,
    octaspire_dern_value_t *value,
    octaspire_dern_value_t *environment)
static octaspire_dern_value_t *octaspire_dern_vm_private_eval_impl(
    octaspire_dern_vm_t    * self,
    octaspire_dern_value_t * value,
    octaspire_dern_value_t * environment,
    bool                   * wasMacroCall)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(self);



@@ 3477,6 3610,7 @@ octaspire_dern_value_t *octaspire_dern_vm_eval(
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        {
            result = value;
        }


@@ 3808,8 3942,13 @@ octaspire_dern_value_t *octaspire_dern_vm_eval(
                }
                break;

                case OCTASPIRE_DERN_VALUE_TAG_MACRO:
                case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
                {
                    // wasMacroCall should NOT be made false; only true.
                    if (operator->typeTag == OCTASPIRE_DERN_VALUE_TAG_MACRO)
                        *wasMacroCall = true;

                    octaspire_vector_t *argVec =
                        octaspire_vector_new_with_preallocated_elements(
                            sizeof(octaspire_dern_value_t*),


@@ 3827,36 3966,52 @@ octaspire_dern_value_t *octaspire_dern_vm_eval(
                         i < octaspire_vector_get_length(vec);
                         ++i)
                    {
                        octaspire_dern_value_t *evaluated = octaspire_dern_vm_eval(
                            self,
                            octaspire_vector_get_element_at(
                                vec,
                                (ptrdiff_t)i),
                            environment);
                        if (operator->typeTag != OCTASPIRE_DERN_VALUE_TAG_MACRO)
                        {
                            octaspire_dern_value_t *evaluated = octaspire_dern_vm_eval(
                                self,
                                octaspire_vector_get_element_at(
                                    vec,
                                    (ptrdiff_t)i),
                                environment);


                        if (evaluated->typeTag == OCTASPIRE_DERN_VALUE_TAG_ERROR)
                        {
                            result = evaluated;
                            if (evaluated->typeTag == OCTASPIRE_DERN_VALUE_TAG_ERROR)
                            {
                                result = evaluated;

                            // TODO XXX add this error annotation to other places too
                            // (for example builtin and function calls)
                            octaspire_string_t *tmpStr =
                                octaspire_dern_value_to_string(value, self->allocator);
                                // TODO XXX add this error annotation to other places too
                                // (for example builtin and function calls)
                                octaspire_string_t *tmpStr =
                                    octaspire_dern_value_to_string(value, self->allocator);

                            octaspire_string_concatenate_format(
                                result->value.error->message,
                                "\n\tAt form: >>>>>>>>>>%s<<<<<<<<<<\n",
                                octaspire_string_get_c_string(tmpStr));
                                octaspire_string_concatenate_format(
                                    result->value.error->message,
                                    "\n\tAt form: >>>>>>>>>>%s<<<<<<<<<<\n",
                                    octaspire_string_get_c_string(tmpStr));

                            octaspire_string_release(tmpStr);
                            tmpStr = 0;
                                octaspire_string_release(tmpStr);
                                tmpStr = 0;


                            break;
                        }
                                break;
                            }

                        octaspire_dern_value_as_vector_push_back_element(arguments, &evaluated);
                            octaspire_dern_value_as_vector_push_back_element(
                                arguments,
                                &evaluated);
                        }
                        else
                        {
                            octaspire_dern_value_t * const tmpVal =
                                octaspire_vector_get_element_at(
                                    vec,
                                    (ptrdiff_t)i);

                            octaspire_dern_value_as_vector_push_back_element(
                                arguments,
                                &tmpVal);
                        }
                    }

                    if (!result)


@@ 3957,6 4112,23 @@ octaspire_dern_value_t *octaspire_dern_vm_eval(
                                    break;
                                }
                            }

                            if (*wasMacroCall)
                            {
                                octaspire_dern_value_t * const toBeEvaluated =
                                    result;

                                octaspire_helpers_verify_true(
                                    octaspire_dern_vm_push_value(self, toBeEvaluated));

                                result = octaspire_dern_vm_eval(
                                    self,
                                    toBeEvaluated,
                                    extendedEnvVal);

                                octaspire_helpers_verify_true(
                                    octaspire_dern_vm_pop_value(self, toBeEvaluated));
                            }
                        }

                        // TODO pop function->body?


@@ 4037,6 4209,63 @@ octaspire_dern_value_t *octaspire_dern_vm_eval(
    return result;
}

octaspire_dern_value_t *octaspire_dern_vm_eval(
    octaspire_dern_vm_t *self,
    octaspire_dern_value_t *value,
    octaspire_dern_value_t *environment)
{
    bool wasMacroCall = false;
    octaspire_dern_value_t * result = 0;

    while (true)
    {
        result = octaspire_dern_vm_private_eval_impl(self, value, environment, &wasMacroCall);

        if (!wasMacroCall)
        {
            return result;
        }

        if (!octaspire_dern_value_is_vector(result))
        {
            return result;
        }

        if (octaspire_dern_value_as_vector_get_length(result) == 0)
        {
            return result;
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(self, result));

        octaspire_dern_value_t const * const operator =
            octaspire_dern_vm_private_eval_impl(
                self,
                octaspire_dern_value_as_vector_get_element_at(
                    result,
                    0),
                environment,
                &wasMacroCall);

        octaspire_helpers_verify_not_null(operator);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(self, result));

        if (!octaspire_dern_value_is_macro(operator))
        {
            return result;
        }
        else
        {
            wasMacroCall = true;
        }

        value = result;
    }
}

octaspire_dern_value_t *octaspire_dern_vm_read_from_octaspire_input_and_eval_in_global_environment(
    octaspire_dern_vm_t *self,
    octaspire_input_t * const input)


@@ 4814,6 5043,7 @@ octaspire_dern_value_t *octaspire_dern_vm_find_from_value(
        case OCTASPIRE_DERN_VALUE_TAG_QUEUE:
        case OCTASPIRE_DERN_VALUE_TAG_LIST:
        case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:
        case OCTASPIRE_DERN_VALUE_TAG_MACRO:
        case OCTASPIRE_DERN_VALUE_TAG_SPECIAL:
        case OCTASPIRE_DERN_VALUE_TAG_BUILTIN:
        case OCTASPIRE_DERN_VALUE_TAG_PORT:

M dev/test/test_dern_lexer.c => dev/test/test_dern_lexer.c +28 -25
@@ 2526,7 2526,7 @@ TEST octaspire_dern_lexer_pop_next_token_illegal_character_empty_character_test(

TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(void)
{
    octaspire_dern_lexer_token_t *expected[12];
    octaspire_dern_lexer_token_t *expected[13];

    uint32_t const     integerVal = 123;
    double const       realVal    = 987.456;


@@ 2535,7 2535,7 @@ TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(vo
    char const * const symbolVal  = "here_is_a_symbol";
    char const * const errorVal   = "Decimal number can contain only digits '0' - '9'.";

    void const * const values[12] =
    void const * const values[13] =
    {
        0,
        0,


@@ 2543,6 2543,7 @@ TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(vo
        0,
        0,
        0,
        0,
        &integerVal,
        &realVal,
        strVal,


@@ 2551,7 2552,7 @@ TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(vo
        errorVal
    };

    octaspire_dern_lexer_token_position_t linePositions[12] =
    octaspire_dern_lexer_token_position_t linePositions[13] =
    {
        {1, 1},
        {1, 1},


@@ 2564,40 2565,43 @@ TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(vo
        {1, 1},
        {1, 1},
        {1, 1},
        {1, 1},
        {1, 1}
    };

    octaspire_dern_lexer_token_position_t columnPositions[12] =
    octaspire_dern_lexer_token_position_t columnPositions[13] =
    {
        {1, 1},
        {3, 3},
        {5, 5},
        {7, 10},
        {12, 16},
        {18, 20},
        {22, 28},
        {30, 40},
        {42, 59},
        {61, 63},
        {65, 80},
        {82, 87}
        {7, 7},
        {9, 12},
        {14, 18},
        {20, 22},
        {24, 30},
        {32, 42},
        {44, 61},
        {63, 65},
        {67, 82},
        {84, 89}
    };

    // + 6
    octaspire_dern_lexer_token_position_t ucsIndexPositions[12] =
    octaspire_dern_lexer_token_position_t ucsIndexPositions[13] =
    {
        {0, 0},
        {2, 2},
        {4, 4},
        {6, 9},
        {11, 15},
        {17, 19},
        {21, 27},
        {29, 39},
        {41, 58},
        {60, 62},
        {64, 79},
        {81, 86}
        {6, 6},
        {8, 11},
        {13, 17},
        {19, 21},
        {23, 29},
        {31, 41},
        {43, 60},
        {62, 64},
        {66, 81},
        {83, 88}
    };

    ASSERT((sizeof(expected) / sizeof(expected[0])) == (sizeof(values) / sizeof(values[0])));


@@ 2621,7 2625,7 @@ TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(vo
    }

    octaspire_input_t *input = octaspire_input_new_from_c_string(
        "( ) ' true false nil {D+123} {D+987.456} [here is a string] |+| here_is_a_symbol {D+12a}",
        "( ) ' ` true false nil {D+123} {D+987.456} [here is a string] |+| here_is_a_symbol {D+12a}",
        octaspireDernLexerTestAllocator);

    ASSERT(input);


@@ 2630,7 2634,6 @@ TEST octaspire_dern_lexer_pop_next_token_all_token_types_amid_whitespace_test(vo
    {
        octaspire_dern_lexer_token_t *token = octaspire_dern_lexer_pop_next_token(input, octaspireDernLexerTestAllocator);
        ASSERT(token);

        ASSERT(octaspire_dern_lexer_token_is_equal(expected[i], token));

        octaspire_dern_lexer_token_release(token);

M dev/test/test_dern_vm.c => dev/test/test_dern_vm.c +94 -5
@@ 8643,6 8643,96 @@ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_symbol_abc_test(void
    PASS();
}

TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_minus1_symbol_xabcy_test(void)
{
    octaspire_dern_vm_t *vm = octaspire_dern_vm_new(octaspireDernVmTestAllocator, octaspireDernVmTestStdio);

    octaspire_dern_value_t *evaluatedValue =
        octaspire_dern_vm_read_from_c_string_and_eval_in_global_environment(
            vm,
            "(cp@ 'xabcy {D+1} {D-1})");

    ASSERT(evaluatedValue);
    ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_VECTOR, evaluatedValue->typeTag);

    char * expected[] =
    {
        "a",
        "b",
        "c",
        "y"
    };

    size_t const numExpected = sizeof(expected) / sizeof(expected[0]);

    ASSERT_EQ(
        numExpected,
        octaspire_dern_value_as_vector_get_length(evaluatedValue));

    for (size_t i = 0; i < numExpected; ++i)
    {
        octaspire_dern_value_t const * const tmpVal =
            octaspire_dern_value_as_vector_get_element_at_const(evaluatedValue, i);

        ASSERT(tmpVal);
        ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_CHARACTER, tmpVal->typeTag);

        ASSERT_STR_EQ(
            expected[i],
            octaspire_dern_value_as_character_get_c_string(tmpVal));
    }

    octaspire_dern_vm_release(vm);
    vm = 0;

    PASS();
}

TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_minus1_vector_with_chars_xabcy_test(void)
{
    octaspire_dern_vm_t *vm = octaspire_dern_vm_new(octaspireDernVmTestAllocator, octaspireDernVmTestStdio);

    octaspire_dern_value_t *evaluatedValue =
        octaspire_dern_vm_read_from_c_string_and_eval_in_global_environment(
            vm,
            "(cp@ '(|x| |a| |b| |c| |y|) {D+1} {D-1})");

    ASSERT(evaluatedValue);
    ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_VECTOR, evaluatedValue->typeTag);

    char * expected[] =
    {
        "a",
        "b",
        "c",
        "y"
    };

    size_t const numExpected = sizeof(expected) / sizeof(expected[0]);

    ASSERT_EQ(
        numExpected,
        octaspire_dern_value_as_vector_get_length(evaluatedValue));

    for (size_t i = 0; i < numExpected; ++i)
    {
        octaspire_dern_value_t const * const tmpVal =
            octaspire_dern_value_as_vector_get_element_at_const(evaluatedValue, i);

        ASSERT(tmpVal);
        ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_CHARACTER, tmpVal->typeTag);

        ASSERT_STR_EQ(
            expected[i],
            octaspire_dern_value_as_character_get_c_string(tmpVal));
    }

    octaspire_dern_vm_release(vm);
    vm = 0;

    PASS();
}

TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_string_abc_failure_test(void)
{
    octaspire_dern_vm_t *vm = octaspire_dern_vm_new(octaspireDernVmTestAllocator, octaspireDernVmTestStdio);


@@ 8656,7 8746,7 @@ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_string_abc_failure_t
    ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_ERROR, evaluatedValue->typeTag);

    ASSERT_STR_EQ(
        "Index to builtin 'cp@' is not valid for the given text value "
        "First index to builtin 'cp@' is not valid for the given text value "
        "(string or symbol). Index '3' was given.\n"
        "\tAt form: >>>>>>>>>>(cp@ [abc] {D+3})<<<<<<<<<<\n",
        octaspire_string_get_c_string(evaluatedValue->value.error->message));


@@ 15318,9 15408,6 @@ TEST octaspire_dern_vm_split_called_with_string_and_char_test(void)
    PASS();
}




TEST octaspire_dern_vm_cp_at_sign_with_vector_test(void)
{
    octaspire_dern_vm_t *vm =


@@ 17840,13 17927,14 @@ GREATEST_SUITE(octaspire_dern_vm_suite)
    RUN_TEST(octaspire_dern_vm_special_for_second_argument_not_symbol_failure_test);
    RUN_TEST(octaspire_dern_vm_special_for_called_with_integer_as_first_argument_failure_test);


    RUN_TEST(octaspire_dern_vm_error_in_function_body_is_reported_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_1_2_3_and_integers_0_and_1_and_2_and_3_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_0_and_string_abc_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_string_abc_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_string_abc_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_symbol_abc_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_minus1_symbol_xabcy_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_minus1_vector_with_chars_xabcy_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_string_abc_failure_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_nil_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_minus1_and_integer_with_only_MSB_on_test);


@@ 17858,6 17946,7 @@ GREATEST_SUITE(octaspire_dern_vm_suite)
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_4_and_integer_Bplus_1000_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_31_and_integer_Bplus_1000_test);
    RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_32_and_integer_Bplus_1000_failure_test);

    RUN_TEST(octaspire_dern_vm_builtin_ln_at_sign_called_with_0_and_vector_1_2_3_test);
    RUN_TEST(octaspire_dern_vm_builtin_ln_at_sign_called_with_1_and_vector_1_2_3_test);
    RUN_TEST(octaspire_dern_vm_builtin_ln_at_sign_called_with_2_and_vector_1_2_3_test);

M release/documentation/dern-manual.html => release/documentation/dern-manual.html +218 -86
@@ 368,22 368,23 @@
<a href="#11">Removing the last value from a vector</a><br/>
<a href="#12">Branching and selection</a><br/>
<a href="#13">Selecting values from collections</a><br/>
<a href="#14">Accessing and manipulating command line arguments and environment variables</a><br/>
<a href="#15">Formatted and regular printing</a><br/>
<a href="#16">Formatted string creation</a><br/>
<a href="#17">Functions with variable number of arguments</a><br/>
<a href="#18">Environments</a><br/>
<a href="#19">Getting help with <code>howto</code></a><br/>
<a href="#20">Returning from functions early</a><br/>
<a href="#21">Evaluating values</a><br/>
<a href="#22">Input and output ports</a><br/>
<a href="#23">Converting between types</a><br/>
<a href="#24">Searching and indexing</a><br/>
<a href="#25">Loading libraries with <code>require</code></a><br/>
<a href="#26">Using custom library loader with <code>require</code></a><br/>
<a href="#27">Embedding in C programs</a><br/>
<a href="#28">Tool support</a><br/>
<a href="#29">Using the development repository</a><br/>
<a href="#14">Macros and templates</a><br/>
<a href="#15">Accessing and manipulating command line arguments and environment variables</a><br/>
<a href="#16">Formatted and regular printing</a><br/>
<a href="#17">Formatted string creation</a><br/>
<a href="#18">Functions with variable number of arguments</a><br/>
<a href="#19">Environments</a><br/>
<a href="#20">Getting help with <code>howto</code></a><br/>
<a href="#21">Returning from functions early</a><br/>
<a href="#22">Evaluating values</a><br/>
<a href="#23">Input and output ports</a><br/>
<a href="#24">Converting between types</a><br/>
<a href="#25">Searching and indexing</a><br/>
<a href="#26">Loading libraries with <code>require</code></a><br/>
<a href="#27">Using custom library loader with <code>require</code></a><br/>
<a href="#28">Embedding in C programs</a><br/>
<a href="#29">Tool support</a><br/>
<a href="#30">Using the development repository</a><br/>

  <h2><a id="1"></a>1. About</h2>



@@ 726,9 727,9 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">println</span><span class="cbracket">)</span>

<span class="normal">  </span><span class="comment">; 6. Define new function to greet people and use it</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> greeter </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">greet</span><span class="keyword">in</span><span class="normal">g name</span><span class="cbracket">)</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[{}, {}!]</span><span class="normal"> greet</span><span class="keyword">in</span><span class="normal">g name</span><span class="cbracket">))</span>
<span class="normal">    </span><span class="string">[My greeter function]</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">greet</span><span class="keyword">in</span><span class="normal">g </span><span class="string">[the greeting]</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> greeter </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">greeting name</span><span class="cbracket">)</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[{}, {}!]</span><span class="normal"> greeting name</span><span class="cbracket">))</span>
<span class="normal">    </span><span class="string">[My greeter function]</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">greeting </span><span class="string">[the greeting]</span>
<span class="normal">                            name </span><span class="string">[who to greet]</span><span class="cbracket">)</span>
<span class="normal">                            </span><span class="keyword">howto-no</span><span class="cbracket">)</span>



@@ 738,11 739,11 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">  </span><span class="comment">; using 'return'</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> grumpy </span><span class="keyword">as</span><span class="normal"> </span><span class="type">true</span><span class="normal"> </span><span class="string">[is our hero grumpy, or not]</span><span class="cbracket">)</span>

<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> greeter </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">greet</span><span class="keyword">in</span><span class="normal">g name</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> greeter </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">greeting name</span><span class="cbracket">)</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> grumpy </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="string">[I'm grumpy and don't greet]</span><span class="cbracket">))</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[{}, {}!]</span><span class="normal"> greet</span><span class="keyword">in</span><span class="normal">g name</span><span class="cbracket">)</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[{}, {}!]</span><span class="normal"> greeting name</span><span class="cbracket">)</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">string-format</span><span class="normal"> </span><span class="string">[I greeted "{}", as asked]</span><span class="normal"> name</span><span class="cbracket">))</span>
<span class="normal">    </span><span class="string">[My greeter function]</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">greet</span><span class="keyword">in</span><span class="normal">g </span><span class="string">[the greeting]</span>
<span class="normal">    </span><span class="string">[My greeter function]</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">greeting </span><span class="string">[the greeting]</span>
<span class="normal">                            name </span><span class="string">[who to greet]</span><span class="cbracket">)</span>
<span class="normal">                            </span><span class="keyword">howto-no</span><span class="cbracket">)</span>



@@ 798,11 799,11 @@ http://www.gnu.org/software/src-highlite -->
<span class="string">[Hello</span><span class="specialchar">|newline|</span><span class="string">]</span><span class="normal">  </span><span class="comment">; Hello and newline</span>
<span class="string">[Я могу есть стекло, оно мне не вредит]</span>
<span class="normal">|a|               </span><span class="comment">; These are characters (utf-8)</span>
<span class="normal">|newl</span><span class="keyword">in</span><span class="normal">e|         </span><span class="comment">; \n</span>
<span class="normal">|newline|         </span><span class="comment">; \n</span>
<span class="normal">|tab|             </span><span class="comment">; \t</span>
<span class="normal">|bar|             </span><span class="comment">; |</span>
<span class="normal">|str</span><span class="keyword">in</span><span class="normal">g</span><span class="keyword">-</span><span class="normal">start|    </span><span class="comment">; [</span>
<span class="normal">|str</span><span class="keyword">in</span><span class="normal">g</span><span class="keyword">-</span><span class="normal">end|      </span><span class="comment">; ]</span>
<span class="normal">|string-start|    </span><span class="comment">; [</span>
<span class="normal">|string-end|      </span><span class="comment">; ]</span>
<span class="normal">|61|              </span><span class="comment">; a in hexadecimal notation</span>
<span class="normal">|7A|              </span><span class="comment">; z in hexadecimal notation</span>
<span class="normal">|44F|             </span><span class="comment">; я in hexadecimal notation</span>


@@ 884,7 885,7 @@ http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> pi </span><span class="keyword">as</span><span class="normal"> </span><span class="number">{D+3.14}</span><span class="normal"> </span><span class="string">[value for pi]</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> names </span><span class="keyword">as</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">John Lisa Mark</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[names list]</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">do</span><span class="normal">uble </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">x</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">*</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> x</span><span class="cbracket">))</span><span class="normal"> </span><span class="string">[doubles nums]</span>
<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> double </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">x</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">*</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> x</span><span class="cbracket">))</span><span class="normal"> </span><span class="string">[doubles nums]</span>
<span class="normal">    '</span><span class="cbracket">(</span><span class="normal">x </span><span class="string">[this is doubled]</span><span class="cbracket">)</span><span class="normal"> </span><span class="keyword">howto-ok</span><span class="cbracket">)</span></pre>

  <p>


@@ 899,7 900,7 @@ http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="normal">pi</span>
<span class="normal">names</span>
<span class="cbracket">(</span><span class="keyword">do</span><span class="normal">uble </span><span class="number">{D+1}</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">double </span><span class="number">{D+1}</span><span class="cbracket">)</span></pre>

  <p>
    And to see the documentation for these values:


@@ 911,7 912,7 @@ http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">doc</span><span class="normal"> pi</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">doc</span><span class="normal"> names</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">doc</span><span class="normal"> </span><span class="keyword">do</span><span class="normal">uble</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="keyword">doc</span><span class="normal"> double</span><span class="cbracket">)</span></pre>

  <p>
    The documentation of the function contains also documentation for


@@ 1017,14 1018,14 @@ http://www.gnu.org/software/src-highlite -->
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="normal">m</span><span class="keyword">in</span><span class="normal">  </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; {D+1}</span>
<span class="cbracket">(</span><span class="normal">m</span><span class="keyword">in</span><span class="normal">  </span><span class="string">[abc]</span><span class="normal"> </span><span class="string">[abd]</span><span class="normal"> </span><span class="string">[abe]</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; [abc]</span>
<span class="cbracket">(</span><span class="normal">max  </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; {D+3}</span>
<span class="cbracket">(</span><span class="normal">max  </span><span class="string">[abc]</span><span class="normal"> </span><span class="string">[abd]</span><span class="normal"> </span><span class="string">[abe]</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; [abe]</span>
<pre><span class="cbracket">(</span><span class="keyword">min</span><span class="normal">  </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; {D+1}</span>
<span class="cbracket">(</span><span class="keyword">min</span><span class="normal">  </span><span class="string">[abc]</span><span class="normal"> </span><span class="string">[abd]</span><span class="normal"> </span><span class="string">[abe]</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; [abc]</span>
<span class="cbracket">(</span><span class="keyword">max</span><span class="normal">  </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; {D+3}</span>
<span class="cbracket">(</span><span class="keyword">max</span><span class="normal">  </span><span class="string">[abc]</span><span class="normal"> </span><span class="string">[abd]</span><span class="normal"> </span><span class="string">[abe]</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; [abe]</span>

<span class="cbracket">(</span><span class="keyword">distance</span><span class="normal"> </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+1.1}</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; {D+0.1}</span>
<span class="cbracket">(</span><span class="keyword">distance</span><span class="normal"> </span><span class="string">[lawn]</span><span class="normal"> </span><span class="string">[flaw]</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; {D+2}</span>
<span class="cbracket">(</span><span class="keyword">distance</span><span class="normal"> 'kitten 'sitt</span><span class="keyword">in</span><span class="normal">g</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; {D+3}</span>
<span class="cbracket">(</span><span class="keyword">distance</span><span class="normal"> 'kitten 'sitting</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; {D+3}</span>
</pre>

  <p>


@@ 1098,9 1099,9 @@ http://www.gnu.org/software/src-highlite -->

<span class="cbracket">(</span><span class="keyword">+</span><span class="normal"> </span><span class="string">[Hello]</span><span class="normal"> </span><span class="string">[ ]</span><span class="normal"> </span><span class="string">[World.]</span><span class="normal"> </span><span class="string">[ Bye.]</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; Hello World. Bye.</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> greet</span><span class="keyword">in</span><span class="normal">g </span><span class="keyword">as</span><span class="normal"> </span><span class="string">[Hello]</span><span class="normal"> </span><span class="string">[my greeting]</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> greet</span><span class="keyword">in</span><span class="normal">g </span><span class="string">[ World!]</span><span class="cbracket">)</span><span class="normal">          </span><span class="comment">; Hello World!</span>
<span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> greet</span><span class="keyword">in</span><span class="normal">g |!|</span><span class="cbracket">)</span><span class="normal">                </span><span class="comment">; Hello World!!</span>
<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> greeting </span><span class="keyword">as</span><span class="normal"> </span><span class="string">[Hello]</span><span class="normal"> </span><span class="string">[my greeting]</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> greeting </span><span class="string">[ World!]</span><span class="cbracket">)</span><span class="normal">          </span><span class="comment">; Hello World!</span>
<span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> greeting |!|</span><span class="cbracket">)</span><span class="normal">                </span><span class="comment">; Hello World!!</span>

<span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> '</span><span class="cbracket">(</span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal"> '</span><span class="cbracket">(</span><span class="number">{D+4}</span><span class="normal"> </span><span class="number">{D+5}</span><span class="normal"> </span><span class="number">{D+6}</span><span class="cbracket">))</span>
<span class="comment">; (1 2 3 (4 5 6))</span>


@@ 1258,6 1259,11 @@ http://www.gnu.org/software/src-highlite -->
    Values can be selected from collections using <code>ln@</code> and
    copied with <code>cp@</code>. <code>ln@</code> is pronounced
    <b>link at</b> and <code>cp@</code> is pronounced <b>copy at</b>.
    <code>cp@</code> can be used to copy either a single value or
    a range of values. As usual the index or indices can be
    given either as negative or non-negative. Negative indices
    count from the end; this means that <code>-1</code> is the
    last value in a collection.
  </p>

<!-- Generator: GNU source-highlight 3.1.8


@@ 1266,8 1272,8 @@ http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">++</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">ln@</span><span class="normal"> '</span><span class="cbracket">(</span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+1}</span><span class="cbracket">))</span><span class="normal">   </span><span class="comment">; 3</span>
<span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="string">[abc]</span><span class="normal"> </span><span class="number">{D+1}</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+2}</span><span class="cbracket">))</span><span class="normal">           </span><span class="comment">; |d|</span>
<span class="cbracket">(</span><span class="keyword">ln@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">hash-map</span><span class="normal"> |a| </span><span class="string">[abc]</span><span class="cbracket">)</span><span class="normal"> |a|   'h</span><span class="keyword">as</span><span class="normal">h</span><span class="cbracket">)</span><span class="normal">  </span><span class="comment">; [abc]</span>
<span class="cbracket">(</span><span class="keyword">ln@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">hash-map</span><span class="normal"> |a| </span><span class="string">[abc]</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+0}</span><span class="normal"> '</span><span class="keyword">in</span><span class="normal">dex</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; [abc]</span>
<span class="cbracket">(</span><span class="keyword">ln@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">hash-map</span><span class="normal"> |a| </span><span class="string">[abc]</span><span class="cbracket">)</span><span class="normal"> |a|   'hash</span><span class="cbracket">)</span><span class="normal">  </span><span class="comment">; [abc]</span>
<span class="cbracket">(</span><span class="keyword">ln@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">hash-map</span><span class="normal"> |a| </span><span class="string">[abc]</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+0}</span><span class="normal"> 'index</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; [abc]</span>

<span class="comment">; Copy characters from text (string and symbol)</span>



@@ 1284,10 1290,130 @@ http://www.gnu.org/software/src-highlite -->
<span class="comment">; Copy values from containers</span>

<span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">vector</span><span class="normal"> |a| |b| |c|</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+1}</span><span class="cbracket">)</span><span class="normal">        </span><span class="comment">; |b|</span>
<span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">hash-map</span><span class="normal"> |a| </span><span class="string">[abc]</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+0}</span><span class="normal"> '</span><span class="keyword">in</span><span class="normal">dex</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; [abc]</span>
<span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">hash-map</span><span class="normal"> |a| </span><span class="string">[abc]</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+0}</span><span class="normal"> 'index</span><span class="cbracket">)</span><span class="normal"> </span><span class="comment">; [abc]</span>

<span class="comment">; Ranges</span>

<span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">|a| |b| |c| |d|</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D-1}</span><span class="cbracket">)</span><span class="normal">    </span><span class="comment">; (|b| |c| |d|)</span>
</pre>

  <h2><a id="14"></a>14. Accessing and manipulating command line arguments and environment variables</h2>
  <h2><a id="14"></a>14. Macros and templates</h2>

  <p>
    Above was discussion about selecting values from collections.
    You might be wondering whether Dern has functions <code>car</code>
    (also known as <code>first</code>) and <code>cdr</code> (also known
    as <code>rest</code>). These functions are implemented using
    <i>macros</i> and <i>templates</i> and use <code>cp@</code>
    to copy either the first or the rest of the values.
  </p>

<!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">first</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">container</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">==</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">len</span><span class="normal"> container</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+0}</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="type">nil</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> tmp </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> container </span><span class="number">{D+0}</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[tmp]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> tmp</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="string">[Return a copy of the first value in a container]</span>
<span class="normal">  '</span><span class="cbracket">(</span><span class="normal">container </span><span class="string">[container]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">car</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">container</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> tmp </span><span class="keyword">as</span><span class="normal"> `</span><span class="cbracket">(</span><span class="keyword">first</span><span class="normal"> ,container</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[tmp]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> tmp</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="string">[Return a copy of the first value in a container]</span>
<span class="normal">  '</span><span class="cbracket">(</span><span class="normal">container </span><span class="string">[container]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">rest</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">container</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">&lt;=</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">len</span><span class="normal"> container</span><span class="cbracket">)</span><span class="normal"> </span><span class="number">{D+1}</span><span class="cbracket">)</span>
<span class="normal">    </span><span class="type">nil</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">do</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> tmp </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> container </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D-1}</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[tmp]</span><span class="cbracket">)</span>
<span class="normal">      </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> tmp</span><span class="cbracket">))))</span>
<span class="normal">  </span><span class="string">[Return a vector holding copies of all but the first value of a container]</span>
<span class="normal">  '</span><span class="cbracket">(</span><span class="normal">container </span><span class="string">[container]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">cdr</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">container</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> tmp </span><span class="keyword">as</span><span class="normal"> `</span><span class="cbracket">(</span><span class="keyword">rest</span><span class="normal"> ,container</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[tmp]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> tmp</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="string">[Return a vector holding copies of all but the first value of a container]</span>
<span class="normal">  '</span><span class="cbracket">(</span><span class="normal">container </span><span class="string">[container]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">when</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">cond action</span><span class="cbracket">)</span>
<span class="normal">  `</span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> ,cond ,action </span><span class="type">nil</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="string">[if without else branch]</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">cond </span><span class="string">[cond]</span><span class="normal"> action </span><span class="string">[action]</span><span class="cbracket">)</span><span class="normal"> </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">ensure-vector</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">v</span><span class="cbracket">)</span>
<span class="normal">   </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">vector?</span><span class="normal"> v</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> v</span><span class="cbracket">)))</span>
<span class="normal">   </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> tmp </span><span class="keyword">as</span><span class="normal"> `</span><span class="cbracket">(</span><span class="keyword">vector</span><span class="normal"> ,v</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[vector to be returned]</span><span class="cbracket">)</span>
<span class="normal">   </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> tmp</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="string">[ensure given value is a vector]</span><span class="normal"> '</span><span class="cbracket">(</span><span class="normal">v </span><span class="string">[value]</span><span class="cbracket">)</span><span class="normal"> </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> </span><span class="keyword">-&gt;&gt;</span><span class="normal"> </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">macro</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">x forms ...</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">==</span><span class="normal"> forms </span><span class="type">nil</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> x</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> num-forms </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">len</span><span class="normal"> forms</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[number of forms]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">==</span><span class="normal"> </span><span class="number">{D+0}</span><span class="normal"> num-forms</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">quote</span><span class="normal"> x</span><span class="cbracket">)))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> first-form </span><span class="keyword">as</span><span class="normal"> `</span><span class="cbracket">(</span><span class="keyword">ensure-vector</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">car</span><span class="normal"> ,forms</span><span class="cbracket">))</span><span class="normal"> </span><span class="string">[currently first form]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">=</span><span class="normal"> first-form </span><span class="cbracket">(</span><span class="keyword">eval</span><span class="normal"> first-form</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> first-form </span><span class="cbracket">(</span><span class="keyword">template</span><span class="normal"> ,x</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">=</span><span class="normal"> first-form </span><span class="cbracket">(</span><span class="keyword">eval</span><span class="normal"> first-form</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> rest-forms </span><span class="keyword">as</span><span class="normal"> `</span><span class="cbracket">(</span><span class="keyword">cdr</span><span class="normal"> ,forms</span><span class="cbracket">)</span><span class="normal"> </span><span class="string">[forms without the first]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">=</span><span class="normal"> rest-forms </span><span class="cbracket">(</span><span class="keyword">eval</span><span class="normal"> rest-forms</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">==</span><span class="normal"> rest-forms </span><span class="type">nil</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> first-form</span><span class="cbracket">))</span>
<span class="normal">  `</span><span class="cbracket">(</span><span class="keyword">-&gt;&gt;</span><span class="normal"> ,first-form </span><span class="keyword">,@</span><span class="normal"> rest-forms</span><span class="cbracket">))</span>
<span class="normal">  </span><span class="string">[Threads the expr through the forms]</span>
<span class="normal">  '</span><span class="cbracket">(</span><span class="normal">x </span><span class="string">[expression]</span><span class="normal"> forms </span><span class="string">[forms to thread through]</span><span class="normal"> ... </span><span class="string">[varargs]</span><span class="cbracket">)</span>
<span class="normal">  </span><span class="keyword">howto-ok</span><span class="cbracket">)</span>
</pre>

  <p>
    Below is an example of using these macros. Please note,
    that if the macros are not defined in the same directory
    with the Dern REPL executable, you must add the directory
    containing the macro definitions into the include path
    using <code>-I</code> command line switch:
  </p>

<!-- Generator: GNU source-highlight 3.1.8
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="comment">; Run these examples with command:</span>
<span class="comment">;</span>
<span class="comment">;   ./octaspire-dern-repl -I release/examples</span>
<span class="comment">;</span>
<span class="comment">; or</span>
<span class="comment">;</span>
<span class="comment">;   ./octaspire-dern-repl -I examples</span>
<span class="comment">;</span>
<span class="comment">; depending the directory you are in.</span>

<span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'dern_util</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">when</span><span class="normal"> </span><span class="type">true</span><span class="normal">  </span><span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[you should see this]</span><span class="cbracket">))</span>
<span class="cbracket">(</span><span class="keyword">when</span><span class="normal"> </span><span class="type">false</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[you should NOT see this]</span><span class="cbracket">))</span>

<span class="cbracket">(</span><span class="keyword">first</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|a| |b| |c|</span><span class="cbracket">))</span><span class="normal">                     </span><span class="comment">; |a|</span>
<span class="cbracket">(</span><span class="keyword">car</span><span class="normal">   </span><span class="cbracket">(</span><span class="normal">|a| |b| |c|</span><span class="cbracket">))</span>

<span class="cbracket">(</span><span class="keyword">first</span><span class="normal"> </span><span class="cbracket">((</span><span class="normal">|a| |b|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|c| |d|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|e| |f|</span><span class="cbracket">)))</span><span class="normal">   </span><span class="comment">; (|a| |b|)</span>
<span class="cbracket">(</span><span class="keyword">car</span><span class="normal">   </span><span class="cbracket">((</span><span class="normal">|a| |b|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|c| |d|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|e| |f|</span><span class="cbracket">)))</span>

<span class="cbracket">(</span><span class="keyword">rest</span><span class="normal">  </span><span class="cbracket">(</span><span class="normal">|a| |b| |c|</span><span class="cbracket">))</span><span class="normal">                     </span><span class="comment">; (|b| |c|)</span>
<span class="cbracket">(</span><span class="keyword">cdr</span><span class="normal">   </span><span class="cbracket">(</span><span class="normal">|a| |b| |c|</span><span class="cbracket">))</span>

<span class="cbracket">(</span><span class="keyword">rest</span><span class="normal">  </span><span class="cbracket">((</span><span class="normal">|a| |b|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|c| |d|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|e| |f|</span><span class="cbracket">)))</span><span class="normal">   </span><span class="comment">; ((|c| |d|) (|e| |f|))</span>
<span class="cbracket">(</span><span class="keyword">cdr</span><span class="normal">   </span><span class="cbracket">((</span><span class="normal">|a| |b|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|c| |d|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="normal">|e| |f|</span><span class="cbracket">)))</span>

<span class="cbracket">(</span><span class="keyword">-&gt;&gt;</span><span class="normal"> |a| </span><span class="cbracket">(</span><span class="keyword">+</span><span class="normal"> |b|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">+</span><span class="normal"> |c|</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">+</span><span class="normal"> |d|</span><span class="cbracket">))</span><span class="normal">         </span><span class="comment">; [dcba]</span>
</pre>

  <h2><a id="15"></a>15. Accessing and manipulating command line arguments and environment variables</h2>

  <p>
    This section is not ready yet. See the example below. More information will


@@ 1298,10 1424,10 @@ http://www.gnu.org/software/src-highlite -->
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="normal">host</span><span class="keyword">-</span><span class="normal">get</span><span class="keyword">-</span><span class="normal">comm</span><span class="keyword">and-</span><span class="normal">l</span><span class="keyword">in</span><span class="normal">e</span><span class="keyword">-</span><span class="normal">arguments</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">host</span><span class="keyword">-</span><span class="normal">get</span><span class="keyword">-</span><span class="normal">environment</span><span class="keyword">-</span><span class="normal">variables</span><span class="cbracket">)</span></pre>
<pre><span class="cbracket">(</span><span class="keyword">host-get-command-line-arguments</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">host-get-environment-variables</span><span class="cbracket">)</span></pre>

  <h2><a id="15"></a>15. Formatted and regular printing</h2>
  <h2><a id="16"></a>16. Formatted and regular printing</h2>

  <p>
    Here are few examples:


@@ 1322,7 1448,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="string">[Hi {} and {}! It is {} degrees outside.]</span>
<span class="normal">    name1 name2 number</span><span class="cbracket">)</span></pre>

  <h2><a id="16"></a>16. Formatted string creation</h2>
  <h2><a id="17"></a>17. Formatted string creation</h2>

  <p>
    Here are few examples:


@@ 1342,7 1468,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">  </span><span class="string">[Hi {} and {}! It is {} degrees outside]</span>
<span class="normal">  name1 name2 number</span><span class="cbracket">)</span></pre>

  <h2><a id="17"></a>17. Functions with variable number of arguments</h2>
  <h2><a id="18"></a>18. Functions with variable number of arguments</h2>

  <p>
    Here are few examples:


@@ 1364,7 1490,13 @@ http://www.gnu.org/software/src-highlite -->

<span class="cbracket">(</span><span class="normal">f </span><span class="number">{D+1}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="normal"> </span><span class="number">{D+3}</span><span class="cbracket">)</span><span class="normal">   </span><span class="comment">; Prints 1|newline|(2 3)</span></pre>

  <h2><a id="18"></a>18. Environments</h2>
  <p>
    As can be seen from the examples above, the last formal parameter
    name before <code>...</code> will contain all the additional
    arguments.
  </p>

  <h2><a id="19"></a>19. Environments</h2>

  <p>
    Here are few examples:


@@ 1378,7 1510,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="cbracket">(</span><span class="keyword">env-current</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">env-new</span><span class="cbracket">)</span></pre>

  <h2><a id="19"></a>19. Getting help with <code>howto</code></h2>
  <h2><a id="20"></a>20. Getting help with <code>howto</code></h2>

  <p>
    Function <code>howto</code> can be used for asking howto do something.


@@ 1427,7 1559,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="comment">; prints ((find (quote (John Mike Alice Lola))</span>
<span class="comment">;               (quote Lola)))</span></pre>

  <h2><a id="20"></a>20. Returning from functions early</h2>
  <h2><a id="21"></a>21. Returning from functions early</h2>

  <p>
    The value of the last expression of function is usually the return value


@@ 1439,10 1571,10 @@ http://www.gnu.org/software/src-highlite -->
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> err</span><span class="keyword">or</span><span class="normal">Code </span><span class="keyword">as</span><span class="normal"> </span><span class="number">{D+1}</span><span class="normal"> </span><span class="string">[0 means no error.]</span><span class="cbracket">)</span>
<pre><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> errorCode </span><span class="keyword">as</span><span class="normal"> </span><span class="number">{D+1}</span><span class="normal"> </span><span class="string">[0 means no error.]</span><span class="cbracket">)</span>

<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> start</span><span class="keyword">-</span><span class="normal">eng</span><span class="keyword">in</span><span class="normal">e </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">()</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">!=</span><span class="normal"> err</span><span class="keyword">or</span><span class="normal">Code </span><span class="number">{D+0}</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="string">[Cannot start]</span><span class="cbracket">))</span>
<span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> start-engine </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">()</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">!=</span><span class="normal"> errorCode </span><span class="number">{D+0}</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="string">[Cannot start]</span><span class="cbracket">))</span>
<span class="normal">    </span><span class="comment">; .... Start the engine here...</span>
<span class="normal">    </span><span class="string">[Start engine if all OK]</span><span class="normal"> '</span><span class="cbracket">()</span><span class="normal"> </span><span class="keyword">howto-no</span><span class="cbracket">))</span></pre>



@@ 1459,7 1591,7 @@ http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">((</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">()</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="normal"> </span><span class="type">nil</span><span class="cbracket">)))</span><span class="normal">   </span><span class="comment">; Evaluates into 'nil'.</span>
<span class="cbracket">((</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">()</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">return</span><span class="cbracket">)))</span><span class="normal">       </span><span class="comment">; Evaluates into 'nil'.</span></pre>

  <h2><a id="21"></a>21. Evaluating values</h2>
  <h2><a id="22"></a>22. Evaluating values</h2>

  <p>
    Special <code>eval</code> can be used to evaluate a given value. It can


@@ 1477,21 1609,21 @@ http://www.gnu.org/software/src-highlite -->
by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> level</span><span class="keyword">-</span><span class="normal">next </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">()</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="normal">level</span><span class="keyword">-</span><span class="normal">reset</span><span class="cbracket">)</span>
<pre><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> level-next </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">fn</span><span class="normal"> </span><span class="cbracket">()</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="normal">level-reset</span><span class="cbracket">)</span>

<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> lnum </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">+</span><span class="normal"> level</span><span class="keyword">-</span><span class="normal">current</span><span class="keyword">-</span><span class="normal">number </span><span class="number">{D+1}</span><span class="cbracket">)</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> lnum </span><span class="keyword">as</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">+</span><span class="normal"> level-current-number </span><span class="number">{D+1}</span><span class="cbracket">)</span>
<span class="normal">        </span><span class="string">[level number]</span><span class="cbracket">)</span>

<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">&gt;</span><span class="normal"> lnum number</span><span class="keyword">-</span><span class="normal">of</span><span class="keyword">-</span><span class="normal">levels</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">=</span><span class="normal"> lnum </span><span class="number">{D+1}</span><span class="cbracket">))</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">if</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">&gt;</span><span class="normal"> lnum number-of-levels</span><span class="cbracket">)</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">=</span><span class="normal"> lnum </span><span class="number">{D+1}</span><span class="cbracket">))</span>

<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> name</span><span class="keyword">-</span><span class="normal">of</span><span class="keyword">-fn-</span><span class="normal">to</span><span class="keyword">-</span><span class="normal">call </span><span class="keyword">as</span><span class="normal"> 'level</span><span class="keyword">-</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">define</span><span class="normal"> name-of-fn-to-call </span><span class="keyword">as</span><span class="normal"> 'level</span><span class="keyword">-</span>
<span class="normal">        </span><span class="string">[name of the level builder function to call]</span><span class="cbracket">)</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> name</span><span class="keyword">-</span><span class="normal">of</span><span class="keyword">-fn-</span><span class="normal">to</span><span class="keyword">-</span><span class="normal">call lnum</span><span class="cbracket">)</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">eval</span><span class="normal"> </span><span class="cbracket">((</span><span class="keyword">eval</span><span class="normal"> name</span><span class="keyword">-</span><span class="normal">of</span><span class="keyword">-fn-</span><span class="normal">to</span><span class="keyword">-</span><span class="normal">call</span><span class="cbracket">))))</span><span class="normal"> </span><span class="string">[next level]</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">+=</span><span class="normal"> name-of-fn-to-call lnum</span><span class="cbracket">)</span>
<span class="normal">    </span><span class="cbracket">(</span><span class="keyword">eval</span><span class="normal"> </span><span class="cbracket">((</span><span class="keyword">eval</span><span class="normal"> name-of-fn-to-call</span><span class="cbracket">))))</span><span class="normal"> </span><span class="string">[next level]</span>
<span class="normal">        '</span><span class="cbracket">()</span><span class="normal"> </span><span class="keyword">howto-no</span><span class="cbracket">)</span></pre>

  <h2><a id="22"></a>22. Input and output ports</h2>
  <h2><a id="23"></a>23. Input and output ports</h2>

  <p>
    Input and output can be done through ports. Ports can be created and


@@ 1543,10 1675,10 @@ http://www.gnu.org/software/src-highlite -->
<span class="cbracket">(</span><span class="keyword">port-write</span><span class="normal"> f </span><span class="number">{D+65}</span><span class="cbracket">)</span>

<span class="comment">; Seek one octet forward  from the current position</span>
<span class="cbracket">(</span><span class="keyword">port-seek</span><span class="normal"> f  </span><span class="number">{D+1}</span><span class="normal"> 'from</span><span class="keyword">-</span><span class="normal">current</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">port-seek</span><span class="normal"> f  </span><span class="number">{D+1}</span><span class="normal"> 'from-current</span><span class="cbracket">)</span>

<span class="comment">; Seek one octet backward from the current position</span>
<span class="cbracket">(</span><span class="keyword">port-seek</span><span class="normal"> f </span><span class="number">{D-1}</span><span class="normal"> 'from</span><span class="keyword">-</span><span class="normal">current</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="keyword">port-seek</span><span class="normal"> f </span><span class="number">{D-1}</span><span class="normal"> 'from-current</span><span class="cbracket">)</span>

<span class="comment">; Tell the distance (in octets) from</span>
<span class="comment">; the beginning of the port</span>


@@ 1633,13 1765,13 @@ http://www.gnu.org/software/src-highlite -->

<span class="cbracket">(</span><span class="keyword">port-write</span><span class="normal"> f '</span><span class="cbracket">(</span><span class="number">{D+65}</span><span class="normal"> |A| </span><span class="string">[ Hi!]</span><span class="cbracket">))</span><span class="normal"> </span><span class="comment">; AA Hi!</span></pre>

  <h2><a id="23"></a>23. Converting between types</h2>
  <h2><a id="24"></a>24. Converting between types</h2>

  <p>
    TODO
  </p>

  <h2><a id="24"></a>24. Searching and indexing</h2>
  <h2><a id="25"></a>25. Searching and indexing</h2>

  <p>
    TODO


@@ 1677,7 1809,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">find</span><span class="normal"> </span><span class="string">[012345 abc abc abc]</span><span class="normal"> </span><span class="string">[abc]</span><span class="cbracket">))</span>
<span class="cbracket">(</span><span class="keyword">println</span><span class="normal"> </span><span class="cbracket">(</span><span class="keyword">find</span><span class="normal"> </span><span class="string">[012345]</span><span class="normal"> |3|</span><span class="cbracket">))</span><span class="normal"> </span><span class="comment">; prints ({D+3})</span></pre>

  <h2><a id="25"></a>25. Loading libraries with <code>require</code></h2>
  <h2><a id="26"></a>26. Loading libraries with <code>require</code></h2>

  <p>
    Dern has support for loading libraries or "plugins" during run time with


@@ 1707,7 1839,7 @@ by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'mylib</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">mylib</span><span class="keyword">-</span><span class="normal">say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">mylib-say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>

  <p>
    If <b>mylib</b>-library is required later again, there is no need to


@@ 1803,7 1935,7 @@ http://www.gnu.org/software/src-highlite -->
    an example with Makefiles for different systems.
  </p>

    <h3>25.1 Building and using a binary library in Haiku</h3>
    <h3>26.1 Building and using a binary library in Haiku</h3>

  <p>
    Run these commands from the <b>build</b>-directory of


@@ 1828,9 1960,9 @@ by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'mylib</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">mylib</span><span class="keyword">-</span><span class="normal">say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">mylib-say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>

    <h3>25.2 Building and using a binary library in MINIX 3</h3>
    <h3>26.2 Building and using a binary library in MINIX 3</h3>

  <p>
    Run these commands from the <b>build</b>-directory of


@@ 1855,9 1987,9 @@ by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'mylib</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">mylib</span><span class="keyword">-</span><span class="normal">say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">mylib-say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>

    <h3>25.3 Building and using a binary library in Linux</h3>
    <h3>26.3 Building and using a binary library in Linux</h3>

  <p>
    Run these commands from the <b>build</b>-directory of


@@ 1882,9 2014,9 @@ by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'mylib</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">mylib</span><span class="keyword">-</span><span class="normal">say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">mylib-say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>

    <h3>25.4 Building and using a binary library in FreeBSD</h3>
    <h3>26.4 Building and using a binary library in FreeBSD</h3>

  <p>
    Run these commands from the <b>build</b>-directory of


@@ 1909,9 2041,9 @@ by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'mylib</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">mylib</span><span class="keyword">-</span><span class="normal">say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">mylib-say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>

    <h3>25.5 Building and using a binary library in NetBSD</h3>
    <h3>26.5 Building and using a binary library in NetBSD</h3>

  <p>
    Run these commands from the <b>build</b>-directory of


@@ 1936,9 2068,9 @@ by Lorenzo Bettini
http://www.lorenzobettini.it
http://www.gnu.org/software/src-highlite -->
<pre><span class="cbracket">(</span><span class="keyword">require</span><span class="normal"> 'mylib</span><span class="cbracket">)</span>
<span class="cbracket">(</span><span class="normal">mylib</span><span class="keyword">-</span><span class="normal">say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>
<span class="cbracket">(</span><span class="normal">mylib-say </span><span class="string">[Hello world from library]</span><span class="cbracket">)</span></pre>

  <h2><a id="26"></a>26. Using custom library loader with <code>require</code></h2>
  <h2><a id="27"></a>27. Using custom library loader with <code>require</code></h2>

  <p>
    Sometimes you might want to override the default library searching and


@@ 1996,20 2128,20 @@ http://www.gnu.org/software/src-highlite -->
<span class="cbracket">}</span>
</pre>

  <h2><a id="27"></a>27. Embedding in C programs</h2>
  <h2><a id="28"></a>28. Embedding in C programs</h2>

  <p>
    TODO
  </p>

  <h2><a id="28"></a>28. Tool support</h2>
  <h2><a id="29"></a>29. Tool support</h2>

  <p>
    <b>etc</b>-directory of the source distribution contains syntax files
    for <b>vim</b>, <b>emacs</b> and <b>GNU source-highlight</b>.
  </p>

  <h2><a id="29"></a>29. Using the development repository</h2>
  <h2><a id="30"></a>30. Using the development repository</h2>

  <p>
  The amalgamated source release can be used without Make or other build tools;


@@ 2116,7 2248,7 @@ http://www.gnu.org/software/src-highlite -->
    the documentation.
  </p>

    <h3>29.1 Raspberry Pi, Debian and Ubuntu</h3>
    <h3>30.1 Raspberry Pi, Debian and Ubuntu</h3>

  <p>
    To build Dern from the regular source distribution in <i>Raspberry Pi


@@ 2134,7 2266,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">make</span>
</pre>

    <h3>29.2 Arch Linux</h3>
    <h3>30.2 Arch Linux</h3>

  <p>
    To build on <i>Arch Linux (Arch Linux ARM)</i> system:


@@ 2151,7 2283,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">make</span>
</pre>

    <h3>29.3 Haiku</h3>
    <h3>30.3 Haiku</h3>

  <p>
    To build on <i>Haiku (Version Walter (Revision hrev51127) x86_gcc2)</i>:


@@ 2168,7 2300,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="variable">CC</span><span class="symbol">=</span><span class="normal">gcc-x</span><span class="number">86</span><span class="normal"> make</span>
</pre>

    <h3>29.4 FreeBSD</h3>
    <h3>30.4 FreeBSD</h3>

  <p>
    To build on <i>FreeBSD (FreeBSD-11.0-RELEASE-arm-armv6-RPI2)</i> system:


@@ 2185,7 2317,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">make</span>
</pre>

    <h3>29.5 NetBSD</h3>
    <h3>30.5 NetBSD</h3>

  <p>
    To build on <i>NetBSD (NetBSD-7.1-i386)</i> system:


@@ 2203,7 2335,7 @@ http://www.gnu.org/software/src-highlite -->
<span class="normal">make</span>
</pre>

    <h3>29.6 MINIX 3</h3>
    <h3>30.6 MINIX 3</h3>

  <p>
    To build from the regular source distribution on

A release/examples/dern_util.dern => release/examples/dern_util.dern +57 -0
@@ 0,0 1,57 @@
(define first as (macro (container)
  (if (== (len container) {D+0}) (return nil))
  (define tmp as (cp@ container {D+0}) [tmp])
  (quote tmp))
  [Return a copy of the first value in a container]
  '(container [container])
  howto-ok)

(define car as (macro (container)
  (define tmp as `(first ,container) [tmp])
  (quote tmp))
  [Return a copy of the first value in a container]
  '(container [container])
  howto-ok)

(define rest as (macro (container)
  (if (<= (len container) {D+1})
    nil
    (do
      (define tmp as (cp@ container {D+1} {D-1}) [tmp])
      (quote tmp))))
  [Return a vector holding copies of all but the first value of a container]
  '(container [container])
  howto-ok)

(define cdr as (macro (container)
  (define tmp as `(rest ,container) [tmp])
  (quote tmp))
  [Return a vector holding copies of all but the first value of a container]
  '(container [container])
  howto-ok)

(define when as (macro (cond action)
  `(if ,cond ,action nil))
  [if without else branch] '(cond [cond] action [action]) howto-ok)

(define ensure-vector as (macro (v)
   (if (vector? v) (return (quote v)))
   (define tmp as `(vector ,v) [vector to be returned])
   (quote tmp))
  [ensure given value is a vector] '(v [value]) howto-ok)

(define ->> as (macro (x forms ...)
  (if (== forms nil) (return x))
  (define num-forms as (len forms) [number of forms])
  (if (== {D+0} num-forms) (return (quote x)))
  (define first-form as `(ensure-vector (car ,forms)) [currently first form])
  (= first-form (eval first-form))
  (+= first-form (template ,x))
  (= first-form (eval first-form))
  (define rest-forms as `(cdr ,forms) [forms without the first])
  (= rest-forms (eval rest-forms))
  (if (== rest-forms nil) (return first-form))
  `(->> ,first-form ,@ rest-forms))
  [Threads the expr through the forms]
  '(x [expression] forms [forms to thread through] ... [varargs])
  howto-ok)

M release/octaspire-dern-amalgamated.c => release/octaspire-dern-amalgamated.c +1585 -115
@@ 218,8 218,8 @@ limitations under the License.
#define OCTASPIRE_CORE_CONFIG_H

#define OCTASPIRE_CORE_CONFIG_VERSION_MAJOR "0"
#define OCTASPIRE_CORE_CONFIG_VERSION_MINOR "117"
#define OCTASPIRE_CORE_CONFIG_VERSION_PATCH "4"
#define OCTASPIRE_CORE_CONFIG_VERSION_MINOR "119"
#define OCTASPIRE_CORE_CONFIG_VERSION_PATCH "1"

#define OCTASPIRE_CORE_CONFIG_VERSION_STR "Octaspire Core version " \
    OCTASPIRE_CORE_CONFIG_VERSION_MAJOR "." \


@@ 1046,10 1046,18 @@ bool octaspire_string_starts_with(
    octaspire_string_t const * const self,
    octaspire_string_t const * const other);

bool octaspire_string_starts_with_c_string(
    octaspire_string_t const * const self,
    char const * const str);

bool octaspire_string_ends_with(
    octaspire_string_t const * const self,
    octaspire_string_t const * const other);

bool octaspire_string_ends_with_c_string(
    octaspire_string_t const * const self,
    char const * const str);

uint32_t octaspire_string_get_hash(
    octaspire_string_t const * const self);



@@ 6249,6 6257,23 @@ bool octaspire_string_starts_with(
    return true;
}

bool octaspire_string_starts_with_c_string(
    octaspire_string_t const * const self,
    char const * const str)
{
    assert(self && str);

    octaspire_string_t * other = octaspire_string_new(str, self->allocator);
    octaspire_helpers_verify_not_null(other);

    bool const result = octaspire_string_starts_with(self, other);

    octaspire_string_release(other);
    other = 0;

    return result;
}

bool octaspire_string_ends_with(
    octaspire_string_t const * const self,
    octaspire_string_t const * const other)


@@ 6281,6 6306,23 @@ bool octaspire_string_ends_with(
    return true;
}

bool octaspire_string_ends_with_c_string(
    octaspire_string_t const * const self,
    char const * const str)
{
    assert(self && str);

    octaspire_string_t * other = octaspire_string_new(str, self->allocator);
    octaspire_helpers_verify_not_null(other);

    bool const result = octaspire_string_ends_with(self, other);

    octaspire_string_release(other);
    other = 0;

    return result;
}

uint32_t octaspire_string_get_hash(
    octaspire_string_t const * const self)
{


@@ 21882,6 21924,72 @@ TEST octaspire_string_levenshtein_distance_called_with_two_longer_strings_test(v
    PASS();
}

TEST octaspire_string_starts_with_c_string_test(void)
{
    octaspire_string_t *str =
        octaspire_string_new(
            "abcdefghij",
            octaspireContainerUtf8StringTestAllocator);

    ASSERT(str);
    ASSERT(octaspire_string_starts_with_c_string(str, "a"));
    ASSERT(octaspire_string_starts_with_c_string(str, "ab"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abc"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcd"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcde"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcdef"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcdefg"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcdefgh"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcdefghi"));
    ASSERT(octaspire_string_starts_with_c_string(str, "abcdefghij"));

    ASSERT_FALSE(octaspire_string_starts_with_c_string(str, "abcdefghijk"));
    ASSERT_FALSE(octaspire_string_starts_with_c_string(str, "abcdefghix"));
    ASSERT_FALSE(octaspire_string_starts_with_c_string(str, "abcdefghxj"));
    ASSERT_FALSE(octaspire_string_starts_with_c_string(str, "abcdefgxij"));
    ASSERT_FALSE(octaspire_string_starts_with_c_string(str, "b"));

    ASSERT(octaspire_string_starts_with_c_string(str, ""));

    octaspire_string_release(str);
    str = 0;

    PASS();
}

TEST octaspire_string_ends_with_c_string_test(void)
{
    octaspire_string_t *str =
        octaspire_string_new(
            "abcdefghij",
            octaspireContainerUtf8StringTestAllocator);

    ASSERT(str);
    ASSERT(octaspire_string_ends_with_c_string(str, "j"));
    ASSERT(octaspire_string_ends_with_c_string(str, "ij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "hij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "ghij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "fghij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "efghij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "defghij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "cdefghij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "bcdefghij"));
    ASSERT(octaspire_string_ends_with_c_string(str, "abcdefghij"));

    ASSERT_FALSE(octaspire_string_ends_with_c_string(str, "abcdefghijk"));
    ASSERT_FALSE(octaspire_string_ends_with_c_string(str, "abcdefghix"));
    ASSERT_FALSE(octaspire_string_ends_with_c_string(str, "abcdefghxj"));
    ASSERT_FALSE(octaspire_string_ends_with_c_string(str, "abcdefgxij"));
    ASSERT_FALSE(octaspire_string_ends_with_c_string(str, "i"));

    ASSERT(octaspire_string_ends_with_c_string(str, ""));

    octaspire_string_release(str);
    str = 0;

    PASS();
}

TEST octaspire_string_is_index_valid_test(void)
{
    octaspire_string_t *str1 =


@@ 22084,6 22192,9 @@ GREATEST_SUITE(octaspire_string_suite)
    RUN_TEST(octaspire_string_levenshtein_distance_called_with_rosettacode_and_raisethysword_test);
    RUN_TEST(octaspire_string_levenshtein_distance_called_with_two_longer_strings_test);

    RUN_TEST(octaspire_string_starts_with_c_string_test);
    RUN_TEST(octaspire_string_ends_with_c_string_test);

    RUN_TEST(octaspire_string_is_index_valid_test);

    RUN_TEST(octaspire_string_set_from_c_string_test);


@@ 26336,7 26447,7 @@ limitations under the License.
#define OCTASPIRE_DERN_CONFIG_H

#define OCTASPIRE_DERN_CONFIG_VERSION_MAJOR "0"
#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "486"
#define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "487"
#define OCTASPIRE_DERN_CONFIG_VERSION_PATCH "0"

#define OCTASPIRE_DERN_CONFIG_VERSION_STR "Octaspire Dern version " \


@@ 26387,6 26498,7 @@ typedef enum
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE,
    OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL,


@@ 26754,6 26866,7 @@ typedef enum
    OCTASPIRE_DERN_VALUE_TAG_LIST,
    OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT,
    OCTASPIRE_DERN_VALUE_TAG_FUNCTION,
    OCTASPIRE_DERN_VALUE_TAG_MACRO,
    OCTASPIRE_DERN_VALUE_TAG_SPECIAL,
    OCTASPIRE_DERN_VALUE_TAG_BUILTIN,
    OCTASPIRE_DERN_VALUE_TAG_PORT,


@@ 27072,6 27185,9 @@ struct octaspire_dern_environment_t const *octaspire_dern_value_as_environment_g
bool octaspire_dern_value_is_function(
    octaspire_dern_value_t const * const self);

bool octaspire_dern_value_is_macro(
    octaspire_dern_value_t const * const self);

bool octaspire_dern_value_is_builtin(
    octaspire_dern_value_t const * const self);



@@ 27128,6 27244,9 @@ double octaspire_dern_value_as_number_get_value(
octaspire_dern_function_t *octaspire_dern_value_as_function(
    octaspire_dern_value_t * const self);

octaspire_dern_function_t *octaspire_dern_value_as_macro(
    octaspire_dern_value_t * const self);

bool octaspire_dern_value_as_hash_map_add(
    octaspire_dern_value_t * const self,
    octaspire_dern_value_t * const toBeAdded1,


@@ 27263,6 27382,10 @@ bool octaspire_dern_value_is_symbol_and_equal_to_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str);

bool octaspire_dern_value_is_symbol_and_starts_with_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str);

bool octaspire_dern_value_as_symbol_is_equal_to_c_string(
    octaspire_dern_value_t const * const self,
    char const * const str);


@@ 27287,6 27410,9 @@ octaspire_string_t const *octaspire_dern_value_as_text_get_string_const(
size_t octaspire_dern_value_as_text_get_length_in_octets(
    octaspire_dern_value_t const * const self);

size_t octaspire_dern_value_as_text_get_length_in_ucs_characters(
    octaspire_dern_value_t const * const self);

bool octaspire_dern_value_as_vector_is_index_valid(
    octaspire_dern_value_t const * const self,
    ptrdiff_t const possiblyNegativeIndex);


@@ 27988,6 28114,12 @@ struct octaspire_dern_value_t *octaspire_dern_vm_create_new_value_function(
    char const * const docstr,
    octaspire_vector_t *docVec);

struct octaspire_dern_value_t *octaspire_dern_vm_create_new_value_macro(
    octaspire_dern_vm_t *self,
    octaspire_dern_function_t * const value,
    char const * const docstr,
    octaspire_vector_t *docVec);

struct octaspire_dern_value_t *octaspire_dern_vm_create_new_value_special(
    octaspire_dern_vm_t *self,
    octaspire_dern_special_t * const value,


@@ 28638,11 28770,21 @@ octaspire_dern_value_t *octaspire_dern_vm_special_greater_than_or_equal(
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_special_template(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_special_fn(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_special_macro(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment);

octaspire_dern_value_t *octaspire_dern_vm_builtin_uid(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,


@@ 29466,6 29608,7 @@ static char const * const octaspire_dern_lexer_private_token_tag_types_as_c_stri
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE",
    "OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL",


@@ 29514,6 29657,13 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_quote(
    size_t const startColumn,
    size_t const startIndexInInput);

octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_back_quote(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,
    size_t const startLine,
    size_t const startColumn,
    size_t const startIndexInInput);

octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_integer_or_real_number(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,


@@ 29614,6 29764,7 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_token_new(
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL:


@@ 29855,6 30006,7 @@ void octaspire_dern_lexer_token_release(
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL:


@@ 30059,6 30211,7 @@ bool octaspire_dern_lexer_token_is_equal(
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_LPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_RPAREN:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_FALSE:
        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_NIL:


@@ 30116,6 30269,16 @@ octaspire_string_t *octaspire_dern_lexer_token_to_string(
            return result;
        }

        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE:
        {
            if (!octaspire_string_concatenate_c_string(result, "back quote"))
            {
                return 0;
            }

            return result;
        }

        case OCTASPIRE_DERN_LEXER_TOKEN_TAG_TRUE:
        {
            if (!octaspire_string_concatenate_c_string(result, "true"))


@@ 30742,6 30905,78 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_quote(
    }
}

octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_pop_back_quote(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,
    size_t const startLine,
    size_t const startColumn,
    size_t const startIndexInInput)
{
    size_t endIndexInInput = startIndexInInput;

    if (octaspire_input_is_good(input))
    {
        endIndexInInput  = octaspire_input_get_ucs_character_index(input);
        uint32_t const c = octaspire_input_peek_next_ucs_character(input);

        if (c == '`')
        {
            octaspire_dern_lexer_token_t *result = octaspire_dern_lexer_token_new(
                OCTASPIRE_DERN_LEXER_TOKEN_TAG_BACK_QUOTE,
                0,
                octaspire_dern_lexer_token_position_init(
                    startLine,
                    octaspire_input_get_line_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startColumn,
                    octaspire_input_get_column_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startIndexInInput,
                    endIndexInInput),
                allocator);

            if (!octaspire_input_pop_next_ucs_character(input))
            {
                abort();
            }

            return result;
        }
        else
        {
            return octaspire_dern_lexer_token_new(
                OCTASPIRE_DERN_LEXER_TOKEN_TAG_ERROR,
                "Back quote ` expected",
                octaspire_dern_lexer_token_position_init(
                    startLine,
                    octaspire_input_get_line_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startColumn,
                    octaspire_input_get_column_number(input)),
                octaspire_dern_lexer_token_position_init(
                    startIndexInInput,
                    endIndexInInput),
                allocator);
        }
    }
    else
    {
        return octaspire_dern_lexer_token_new(
            OCTASPIRE_DERN_LEXER_TOKEN_TAG_ERROR,
            "Back quote ` expected",
            octaspire_dern_lexer_token_position_init(
                startLine,
                octaspire_input_get_line_number(input)),
            octaspire_dern_lexer_token_position_init(
                startColumn,
                octaspire_input_get_column_number(input)),
            octaspire_dern_lexer_token_position_init(
                startIndexInInput,
                endIndexInInput),
            allocator);
    }
}

static octaspire_dern_lexer_token_t *octaspire_dern_lexer_private_expect_octet(
    octaspire_input_t *input,
    octaspire_allocator_t *allocator,


@@ 32282,6 32517,16 @@ octaspire_dern_lexer_token_t *octaspire_dern_lexer_pop_next_token(
                    startIndexInInput);
            }

            case '`':
            {
                return octaspire_dern_lexer_private_pop_back_quote(
                    input,
                    allocator,
                    startLine,
                    startColumn,
                    startIndexInInput);
            }

            case '-':
            {
                return octaspire_dern_lexer_private_pop_true_or_false_or_nil_or_symbol(


@@ 35204,7 35449,8 @@ octaspire_dern_value_t *octaspire_dern_vm_special_define(
    }
    else if (numArgs == 6)
    {
        if (octaspire_dern_value_is_function(evaluatedThirdArg))
        if (octaspire_dern_value_is_function(evaluatedThirdArg) ||
            octaspire_dern_value_is_macro(evaluatedThirdArg))
        {
            octaspire_dern_value_t *result =
                octaspire_dern_vm_special_private_define_fun_no_env(


@@ 37221,6 37467,405 @@ octaspire_dern_value_t *octaspire_dern_vm_special_greater_than_or_equal(
    return octaspire_dern_vm_get_value_true(vm);
}

static size_t octaspire_dern_vm_private_template_helper(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t * arguments,
    size_t * currentIndex,
    octaspire_dern_value_t *environment,
    octaspire_dern_value_t **result)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
    char   const * const dernFuncName = "template";
    size_t const numArgs = octaspire_dern_value_get_length(arguments);

    octaspire_dern_value_t * value =
        octaspire_dern_value_as_vector_get_element_at(arguments, *currentIndex);

    octaspire_helpers_verify_not_null(value);

    if (octaspire_dern_value_is_symbol_and_equal_to_c_string(
            value,
            ","))
    {
        if (*currentIndex == (numArgs - 1))
        {
            octaspire_dern_value_t * tmpVal =
                octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Special '%s' expects a value after %zu. argument ','.",
                    dernFuncName,
                    (*currentIndex + 1));

            octaspire_helpers_verify_true(
                octaspire_dern_vm_push_value(vm, tmpVal));


            if (*result == 0)
            {
                *result = tmpVal;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &tmpVal));
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, tmpVal));

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }

        ++(*currentIndex);

        value = octaspire_dern_value_as_vector_get_element_at(
            arguments,
            *currentIndex);

        octaspire_helpers_verify_not_null(value);

        octaspire_dern_value_t * tmpVal =
            octaspire_dern_vm_eval(vm, value, environment);

        octaspire_helpers_verify_not_null(tmpVal);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, tmpVal));

        if (*result == 0)
        {
            *result = tmpVal;
        }
        else
        {
            octaspire_helpers_verify_true(
                octaspire_dern_value_as_vector_push_back_element(
                    *result,
                    &tmpVal));
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, tmpVal));

        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        ++(*currentIndex);
        return 2;
    }
    else if (octaspire_dern_value_is_symbol_and_equal_to_c_string(
                 value,
                 ",@"))
    {
        if (*currentIndex == (numArgs - 1))
        {
            octaspire_dern_value_t * tmpVal =
                octaspire_dern_vm_create_new_value_error_format(
                    vm,
                    "Special '%s' expects a value after %zu. argument ',@'.",
                    dernFuncName,
                    (*currentIndex + 1));

            octaspire_helpers_verify_true(
                octaspire_dern_vm_push_value(vm, tmpVal));

            if (*result == 0)
            {
                *result = tmpVal;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &tmpVal));
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, tmpVal));

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }

        ++(*currentIndex);

        value = octaspire_dern_value_as_vector_get_element_at(
            arguments,
            *currentIndex);

        octaspire_helpers_verify_not_null(value);

        octaspire_dern_value_t * tmpVal =
            octaspire_dern_vm_eval(vm, value, environment);

        octaspire_helpers_verify_not_null(tmpVal);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, tmpVal));

        if (octaspire_dern_value_is_vector(tmpVal))
        {
            if (*result == 0)
            {
                *result = tmpVal;
            }
            else
            {
                for (size_t i = 0;
                     i < octaspire_dern_value_as_vector_get_length(tmpVal);
                     ++i)
                {
                    octaspire_dern_value_t * const valueFromVector =
                        octaspire_dern_value_as_vector_get_element_at(
                            tmpVal,
                            i);

                    octaspire_helpers_verify_true(
                        octaspire_dern_value_as_vector_push_back_element(
                            *result,
                            &valueFromVector));
                }
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, tmpVal));

            ++(*currentIndex);
            return 2;
        }

        if (*result == 0)
        {
            *result = tmpVal;
        }
        else
        {
            octaspire_helpers_verify_true(
                octaspire_dern_value_as_vector_push_back_element(
                    *result,
                    &tmpVal));
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, tmpVal));

        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        ++(*currentIndex);
        return 2;
    }
    else if (octaspire_dern_value_is_symbol_and_starts_with_c_string(
                 value,
                 ","))
    {
        octaspire_string_t * renamedStr =
            octaspire_string_new(
                octaspire_dern_value_as_symbol_get_c_string(value),
                octaspire_dern_vm_get_allocator(vm));

        octaspire_helpers_verify_not_null(renamedStr);

        octaspire_helpers_verify_true(
            octaspire_string_pop_front_ucs_character(renamedStr));

        octaspire_dern_value_t * const renamedVal =
            octaspire_dern_vm_create_new_value_symbol_from_c_string(
                vm,
                octaspire_string_get_c_string(renamedStr));

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, renamedVal));

        octaspire_string_release(renamedStr);
        renamedStr = 0;

        octaspire_dern_value_t * const tmpVal =
            octaspire_dern_vm_eval(vm, renamedVal, environment);

        octaspire_helpers_verify_not_null(tmpVal);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, tmpVal));

        if (*result == 0)
        {
            *result = tmpVal;
        }
        else
        {
            octaspire_helpers_verify_true(
                octaspire_dern_value_as_vector_push_back_element(
                    *result,
                    &tmpVal));
        }

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, tmpVal));

        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, renamedVal));

        octaspire_helpers_verify_true(
            stackLength == octaspire_dern_vm_get_stack_length(vm));

        ++(*currentIndex);
        return 1;
    }
    else
    {
        if (octaspire_dern_value_is_vector(value))
        {
            octaspire_dern_value_t * innerVecVal =
                octaspire_dern_vm_create_new_value_vector(vm);

            octaspire_helpers_verify_not_null(innerVecVal);

            octaspire_helpers_verify_true(
                octaspire_dern_vm_push_value(vm, innerVecVal));


            size_t currentIndex2 = 0;

            size_t const numArgs2 =
                octaspire_dern_value_as_vector_get_length(value);

            while (true)
            {
                // Recursive step.
                octaspire_dern_vm_private_template_helper(
                    vm,
                    value,
                    &currentIndex2,
                    environment,
                    &innerVecVal);

                if (currentIndex2 >= numArgs2)
                {
                    break;
                }
            }

            if (*result == 0)
            {
                *result = innerVecVal;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &innerVecVal));
            }

            octaspire_helpers_verify_true(
                octaspire_dern_vm_pop_value(vm, innerVecVal));

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }
        else
        {
            if (*result == 0)
            {
                *result = value;
            }
            else
            {
                octaspire_helpers_verify_true(
                    octaspire_dern_value_as_vector_push_back_element(
                        *result,
                        &value));
            }

            octaspire_helpers_verify_true(
                stackLength == octaspire_dern_vm_get_stack_length(vm));

            ++(*currentIndex);
            return 1;
        }
    }
}

octaspire_dern_value_t *octaspire_dern_vm_special_template(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);

    octaspire_helpers_verify_true(
        arguments->typeTag == OCTASPIRE_DERN_VALUE_TAG_VECTOR);

    octaspire_helpers_verify_true(
        environment->typeTag == OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT);

    size_t const numArgs = octaspire_dern_value_get_length(arguments);

    octaspire_helpers_verify_true(
        octaspire_dern_vm_push_value(vm, arguments));

    octaspire_dern_value_t * result = 0;

    if (numArgs > 1)
    {
        result = octaspire_dern_vm_create_new_value_vector(vm);
        octaspire_helpers_verify_not_null(result);

        octaspire_helpers_verify_true(
            octaspire_dern_vm_push_value(vm, result));
    }

    size_t i = 0;

    while (true)
    {
        size_t const prevI = i;

        size_t const delta = octaspire_dern_vm_private_template_helper(
            vm,
            arguments,
            &i,
            environment,
            &result);

        octaspire_helpers_verify_true(delta >= 1 && delta <= 2);
        octaspire_helpers_verify_true((prevI + delta) == i);

        if (i >= numArgs)
        {
            break;
        }
    }

    if (numArgs > 1)
    {
        octaspire_helpers_verify_true(
            octaspire_dern_vm_pop_value(vm, result));
    }

    octaspire_helpers_verify_true(
        octaspire_dern_vm_pop_value(vm, arguments));

    octaspire_helpers_verify_true(
        stackLength == octaspire_dern_vm_get_stack_length(vm));

    return result;
}

octaspire_dern_value_t *octaspire_dern_stdlib_private_validate_function(
    octaspire_dern_vm_t* vm,
    octaspire_dern_function_t *function)


@@ 37436,6 38081,140 @@ octaspire_dern_value_t *octaspire_dern_vm_special_fn(
    return result;
}

octaspire_dern_value_t *octaspire_dern_vm_special_macro(
    octaspire_dern_vm_t *vm,
    octaspire_dern_value_t *arguments,
    octaspire_dern_value_t *environment)
{
    size_t const stackLength = octaspire_dern_vm_get_stack_length(vm);
    char   const * const de