e0d7b19488f655a7618e4d510b640bf7b63e871e — octaspire 2 months ago c245954 v0.474.0
Make 'cp@' to support symbols and integers

* Make 'cp@' (copy at) to support symbols and integers in
  addition to the already supported types.

  Symbols are handled the same way as strings are (character
  is returned).
  When 'cp@' is used with integers, the integer is thought as
  a bit container and individual bit is copied from the
  given index. Negative indices count from the end, as
  usual.

* Add helper functions.

* Add unit tests.

* Work with game bounce.

* Fix code style.
M dev/doc/book/examples/dern/selectingFromCollection.dern => dev/doc/book/examples/dern/selectingFromCollection.dern +18 -1
@@ 1,4 1,21 @@ (++ (ln@ '({D+1} {D+2} {D+3}) {D+1}))   ; 3
  (+= (cp@ [abc] {D+1}) {D+2}))           ; |d|
  (ln@ (hash-map |a| [abc]) |a|   'hash)  ; [abc]
- (ln@ (hash-map |a| [abc]) {D+0} 'index) ; [abc]> 
\ No newline at end of file
+ (ln@ (hash-map |a| [abc]) {D+0} 'index) ; [abc]
+ 
+ ; Copy characters from text (string and symbol)
+ 
+ (cp@ [abc] {D+1})                       ; |b|
+ (cp@ 'ABC  {D+2})                       ; |A|
+ 
+ ; Copy bits from integer (32 bits available)
+ 
+ (cp@ {B+1000} {D+2})                    ; {D+0}
+ (cp@ {B+1000} {D+3})                    ; {D+1}
+ (cp@ {B+1000} {D+31})                   ; {D+0}
+ (cp@ {B+1000} {D-1})                    ; {D+0}
+ 
+ ; Copy values from containers
+ 
+ (cp@ (vector |a| |b| |c|) {D+1})        ; |b|
+ (cp@ (hash-map |a| [abc]) {D+0} 'index) ; [abc]

M dev/include/octaspire/dern/octaspire_dern_config.h => dev/include/octaspire/dern/octaspire_dern_config.h +1 -1
@@ 18,7 18,7 @@ #define OCTASPIRE_DERN_CONFIG_H
  
  #define OCTASPIRE_DERN_CONFIG_VERSION_MAJOR "0"
- #define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "473"
+ #define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "474"
  #define OCTASPIRE_DERN_CONFIG_VERSION_PATCH "0"
  
  #define OCTASPIRE_DERN_CONFIG_VERSION_STR "Octaspire Dern version " \

M dev/include/octaspire/dern/octaspire_dern_value.h => dev/include/octaspire/dern/octaspire_dern_value.h +12 -0
@@ 518,6 518,10 @@ bool octaspire_dern_value_as_string_pop_front_ucs_character(
      octaspire_dern_value_t * const self);
  
+ uint32_t octaspire_dern_value_as_text_get_ucs_character_at_index(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex);
+ 
  bool octaspire_dern_value_as_string_remove_all_substrings(
      octaspire_dern_value_t * const self,
      octaspire_dern_value_t * const value);


@@ 526,6 530,14 @@ octaspire_dern_value_t const * const self,
      ptrdiff_t const possiblyNegativeIndex);
  
+ bool octaspire_dern_value_as_symbol_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex);
+ 
+ bool octaspire_dern_value_as_text_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex);
+ 
  bool octaspire_dern_value_as_string_is_empty(
      octaspire_dern_value_t const * const self);
  

M dev/src/octaspire_dern_stdlib.c => dev/src/octaspire_dern_stdlib.c +78 -9
@@ 9531,6 9531,7 @@ }
  
          case OCTASPIRE_DERN_VALUE_TAG_STRING:
+         case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
          {
              if (numArgs > 2)
              {


@@ 9539,7 9540,8 @@                   return octaspire_dern_vm_create_new_value_error_from_c_string(
                      vm,
-                     "Builtin 'cp@' expects exactly two arguments when used with string.");
+                     "Builtin 'cp@' expects exactly two arguments when used "
+                     "with text (string or symbol).");
              }
  
              octaspire_dern_value_t const * const indexVal =


@@ 9554,7 9556,8 @@                   return octaspire_dern_vm_create_new_value_error_format(
                      vm,
-                     "Builtin 'cp@' expects integer as second argument when indexing a string. "
+                     "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));


@@ 9563,7 9566,7 @@ ptrdiff_t const index =
                  (ptrdiff_t)octaspire_dern_value_as_integer_get_value(indexVal);
  
-             if (!octaspire_dern_value_as_string_is_index_valid(
+             if (!octaspire_dern_value_as_text_is_index_valid(
                      collectionVal,
                      index))
              {


@@ 9572,7 9575,8 @@                   return octaspire_dern_vm_create_new_value_error_format(
                      vm,
-                     "Index to builtin 'cp@' is not valid for the given string. "
+                     "Index to builtin 'cp@' is not valid for the given text "
+                     "value (string or symbol). "
  #ifdef __AROS__
                      "Index '%ld' was given.",
  #else


@@ 9586,8 9590,8 @@               return octaspire_dern_vm_create_new_value_character_from_uint32t(
                  vm,
-                 octaspire_string_get_ucs_character_at_index(
-                     collectionVal->value.string,
+                 octaspire_dern_value_as_text_get_ucs_character_at_index(
+                     collectionVal,
                      index));
          }
  


@@ 9834,17 9838,82 @@ {
                  return octaspire_dern_vm_create_new_value_error_from_c_string(
                      vm,
-                     "Builtin 'cp@' expects exactly one argument when used with nil.");
+                     "Builtin 'cp@' expects exactly two arguments when used with nil.");
              }
  
              return octaspire_dern_vm_create_new_value_nil(vm);
          }
  
-         case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
          case OCTASPIRE_DERN_VALUE_TAG_INTEGER:
+         {
+             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(
+                     vm,
+                     "Builtin 'cp@' expects exactly two arguments when used "
+                     "with integer.");
+             }
+ 
+             octaspire_dern_value_t const * const indexVal =
+                 octaspire_dern_value_as_vector_get_element_at_const(arguments, 1);
+ 
+             octaspire_helpers_verify_not_null(indexVal);
+ 
+             if (!octaspire_dern_value_is_integer(indexVal))
+             {
+                 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 an integer value. "
+                     "Now type '%s' was given.",
+                     octaspire_dern_value_helper_get_type_as_c_string(
+                         indexVal->typeTag));
+             }
+ 
+             int32_t const index =
+                 octaspire_dern_value_as_integer_get_value(indexVal);
+ 
+             if (index < -32 || index > 31)
+             {
+                 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@' must be between -32 .. 31 "
+                     "(inclusive) when indexing an integer. "
+ #ifdef __AROS__
+                     "Index '%ld' was given.",
+ #else
+                     "Index %" PRId32 " was given.",
+ #endif
+                     index);
+             }
+ 
+             uint32_t const bits =
+                 (uint32_t)octaspire_dern_value_as_integer_get_value(
+                     collectionVal);
+ 
+             uint32_t const realIndex = (index >= 0) ? index : (32 + index);
+             uint32_t const mask      = 1;
+ 
+             octaspire_helpers_verify_true(
+                 stackLength == octaspire_dern_vm_get_stack_length(vm));
+ 
+             return octaspire_dern_vm_create_new_value_integer(
+                 vm,
+                 (bits & (mask << realIndex)) ? 1 : 0);
+         }
+ 
+         case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
          case OCTASPIRE_DERN_VALUE_TAG_REAL:
          case OCTASPIRE_DERN_VALUE_TAG_CHARACTER:
-         case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
          case OCTASPIRE_DERN_VALUE_TAG_ERROR:
          case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
          case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:

M dev/src/octaspire_dern_value.c => dev/src/octaspire_dern_value.c +52 -0
@@ 2950,6 2950,26 @@ return octaspire_string_pop_front_ucs_character(self->value.string);
  }
  
+ uint32_t octaspire_dern_value_as_text_get_ucs_character_at_index(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex)
+ {
+     octaspire_helpers_verify_true(
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_STRING ||
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_SYMBOL);
+ 
+     if (octaspire_dern_value_is_symbol(self))
+     {
+         return octaspire_string_get_ucs_character_at_index(
+             self->value.symbol,
+             possiblyNegativeIndex);
+     }
+ 
+     return octaspire_string_get_ucs_character_at_index(
+         self->value.string,
+         possiblyNegativeIndex);
+ }
+ 
  bool octaspire_dern_value_as_string_remove_all_substrings(
      octaspire_dern_value_t * const self,
      octaspire_dern_value_t * const value)


@@ 3015,6 3035,38 @@ possiblyNegativeIndex);
  }
  
+ bool octaspire_dern_value_as_symbol_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex)
+ {
+     octaspire_helpers_verify_true(
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_SYMBOL);
+ 
+     return octaspire_string_is_index_valid(
+         self->value.symbol,
+         possiblyNegativeIndex);
+ }
+ 
+ bool octaspire_dern_value_as_text_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex)
+ {
+     octaspire_helpers_verify_true(
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_STRING ||
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_SYMBOL);
+ 
+     if (octaspire_dern_value_is_symbol(self))
+     {
+         return octaspire_dern_value_as_symbol_is_index_valid(
+             self,
+             possiblyNegativeIndex);
+     }
+ 
+     return octaspire_dern_value_as_string_is_index_valid(
+         self,
+         possiblyNegativeIndex);
+ }
+ 
  bool octaspire_dern_value_as_string_is_empty(
      octaspire_dern_value_t const * const self)
  {

M dev/test/test_dern_vm.c => dev/test/test_dern_vm.c +249 -2
@@ 8621,6 8621,28 @@ PASS();
  }
  
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_symbol_abc_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@ 'abc {D+2})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_CHARACTER, evaluatedValue->typeTag);
+ 
+     ASSERT_STR_EQ(
+         "c",
+         octaspire_string_get_c_string(evaluatedValue->value.character));
+ 
+     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);


@@ 8634,8 8656,8 @@ ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_ERROR, evaluatedValue->typeTag);
  
      ASSERT_STR_EQ(
-         "Index to builtin 'cp@' is not valid for the given string. "
-         "Index '3' was given.\n"
+         "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));
  


@@ 8645,6 8667,220 @@ PASS();
  }
  
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_nil_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@ nil {D+3})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_NIL, evaluatedValue->typeTag);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_minus1_and_integer_with_only_MSB_on_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@ {B+10000000000000000000000000000000} {D-1})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(1,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_minus2_and_integer_with_only_MSB_on_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@ {B+10000000000000000000000000000000} {D-2})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_0_and_integer_Bplus_1000_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@ {B+1000} {D+0})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_integer_Bplus_1000_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@ {B+1000} {D+1})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_integer_Bplus_1000_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@ {B+1000} {D+2})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_integer_Bplus_1000_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@ {B+1000} {D+3})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(1,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_4_and_integer_Bplus_1000_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@ {B+1000} {D+4})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_31_and_integer_Bplus_1000_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@ {B+1000} {D+31})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_32_and_integer_Bplus_1000_failure_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@ {B+1000} {D+32})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_ERROR, evaluatedValue->typeTag);
+ 
+     ASSERT_STR_EQ(
+         "Index to builtin 'cp@' must be between -32 .. 31 (inclusive) "
+         "when indexing an integer. Index 32 was given.\n"
+         "\tAt form: >>>>>>>>>>(cp@ {D+8} {D+32})<<<<<<<<<<\n",
+         octaspire_string_get_c_string(evaluatedValue->value.error->message));
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
  TEST octaspire_dern_vm_builtin_ln_at_sign_called_with_0_and_vector_1_2_3_test(void)
  {
      octaspire_dern_vm_t *vm = octaspire_dern_vm_new(octaspireDernVmTestAllocator, octaspireDernVmTestStdio);


@@ 17522,7 17758,18 @@ 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_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);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_minus2_and_integer_with_only_MSB_on_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_0_and_integer_Bplus_1000_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_integer_Bplus_1000_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_integer_Bplus_1000_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_integer_Bplus_1000_test);
+     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 +19 -1
@@ 1219,7 1219,25 @@ <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></pre>
+ <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="comment">; Copy characters from text (string and symbol)</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="comment">; |b|</span>
+ <span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> 'ABC  </span><span class="number">{D+2}</span><span class="cbracket">)</span><span class="normal">                       </span><span class="comment">; |A|</span>
+ 
+ <span class="comment">; Copy bits from integer (32 bits available)</span>
+ 
+ <span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="number">{B+1000}</span><span class="normal"> </span><span class="number">{D+2}</span><span class="cbracket">)</span><span class="normal">                    </span><span class="comment">; {D+0}</span>
+ <span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="number">{B+1000}</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">cp@</span><span class="normal"> </span><span class="number">{B+1000}</span><span class="normal"> </span><span class="number">{D+31}</span><span class="cbracket">)</span><span class="normal">                   </span><span class="comment">; {D+0}</span>
+ <span class="cbracket">(</span><span class="keyword">cp@</span><span class="normal"> </span><span class="number">{B+1000}</span><span class="normal"> </span><span class="number">{D-1}</span><span class="cbracket">)</span><span class="normal">                    </span><span class="comment">; {D+0}</span>
+ 
+ <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>
+ </pre>
  
    <h2><a id="14"></a>14. Accessing and manipulating command line arguments and environment variables</h2>
  

M release/games/octaspire-bounce.dern => release/games/octaspire-bounce.dern +4 -4
@@ 422,13 422,13 @@ (sdl2-gl-ortho-star-rotated (* {D+10} bounce-star-location-x) (* {D+10} bounce-star-location-y) {D+40} {D+5} bounce-star-angle)
    (sdl2-glColor4ub {X+FF} {X+FF} {X+FF} {X+FF})
    ; ui
-   (if (nuklear-begin bounce-nuklear-ctx [] {D+370} {D+500} {D+150} {D+90})
+   (if (nuklear-begin bounce-nuklear-ctx [] {D+370} {D+500} {D+155} {D+85})
      (do
-       (nuklear-layout-row-static bounce-nuklear-ctx {D+30} {D+150} {D+1})
+       (nuklear-layout-row-static bounce-nuklear-ctx {D+30} {D+130} {D+1})
          (if bounce-game-paused
-           (nuklear-label bounce-nuklear-ctx [-- PAUSED --] 'RIGHT)
+           (nuklear-label bounce-nuklear-ctx [-- PAUSED --] 'CENTERED)
            (nuklear-label bounce-nuklear-ctx (string-format [Level {}] (+ bounce-level-index {D+1})) 'RIGHT))
-       (nuklear-layout-row-static bounce-nuklear-ctx {D+30} {D+150} {D+1})
+       (nuklear-layout-row-static bounce-nuklear-ctx {D+30} {D+130} {D+1})
        (nuklear-progress bounce-nuklear-ctx (bounce-duration-to-impulse) {D+250} false)))
    (nuklear-end bounce-nuklear-ctx))
    [render game] '() howto-no)

M release/octaspire-dern-amalgamated.c => release/octaspire-dern-amalgamated.c +392 -12
@@ 26224,7 26224,7 @@ #define OCTASPIRE_DERN_CONFIG_H
  
  #define OCTASPIRE_DERN_CONFIG_VERSION_MAJOR "0"
- #define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "473"
+ #define OCTASPIRE_DERN_CONFIG_VERSION_MINOR "474"
  #define OCTASPIRE_DERN_CONFIG_VERSION_PATCH "0"
  
  #define OCTASPIRE_DERN_CONFIG_VERSION_STR "Octaspire Dern version " \


@@ 27105,6 27105,10 @@ bool octaspire_dern_value_as_string_pop_front_ucs_character(
      octaspire_dern_value_t * const self);
  
+ uint32_t octaspire_dern_value_as_text_get_ucs_character_at_index(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex);
+ 
  bool octaspire_dern_value_as_string_remove_all_substrings(
      octaspire_dern_value_t * const self,
      octaspire_dern_value_t * const value);


@@ 27113,6 27117,14 @@ octaspire_dern_value_t const * const self,
      ptrdiff_t const possiblyNegativeIndex);
  
+ bool octaspire_dern_value_as_symbol_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex);
+ 
+ bool octaspire_dern_value_as_text_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex);
+ 
  bool octaspire_dern_value_as_string_is_empty(
      octaspire_dern_value_t const * const self);
  


@@ 43442,6 43454,7 @@ }
  
          case OCTASPIRE_DERN_VALUE_TAG_STRING:
+         case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
          {
              if (numArgs > 2)
              {


@@ 43450,7 43463,8 @@                   return octaspire_dern_vm_create_new_value_error_from_c_string(
                      vm,
-                     "Builtin 'cp@' expects exactly two arguments when used with string.");
+                     "Builtin 'cp@' expects exactly two arguments when used "
+                     "with text (string or symbol).");
              }
  
              octaspire_dern_value_t const * const indexVal =


@@ 43465,7 43479,8 @@                   return octaspire_dern_vm_create_new_value_error_format(
                      vm,
-                     "Builtin 'cp@' expects integer as second argument when indexing a string. "
+                     "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));


@@ 43474,7 43489,7 @@ ptrdiff_t const index =
                  (ptrdiff_t)octaspire_dern_value_as_integer_get_value(indexVal);
  
-             if (!octaspire_dern_value_as_string_is_index_valid(
+             if (!octaspire_dern_value_as_text_is_index_valid(
                      collectionVal,
                      index))
              {


@@ 43483,7 43498,8 @@                   return octaspire_dern_vm_create_new_value_error_format(
                      vm,
-                     "Index to builtin 'cp@' is not valid for the given string. "
+                     "Index to builtin 'cp@' is not valid for the given text "
+                     "value (string or symbol). "
  #ifdef __AROS__
                      "Index '%ld' was given.",
  #else


@@ 43497,8 43513,8 @@               return octaspire_dern_vm_create_new_value_character_from_uint32t(
                  vm,
-                 octaspire_string_get_ucs_character_at_index(
-                     collectionVal->value.string,
+                 octaspire_dern_value_as_text_get_ucs_character_at_index(
+                     collectionVal,
                      index));
          }
  


@@ 43745,17 43761,82 @@ {
                  return octaspire_dern_vm_create_new_value_error_from_c_string(
                      vm,
-                     "Builtin 'cp@' expects exactly one argument when used with nil.");
+                     "Builtin 'cp@' expects exactly two arguments when used with nil.");
              }
  
              return octaspire_dern_vm_create_new_value_nil(vm);
          }
  
-         case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
          case OCTASPIRE_DERN_VALUE_TAG_INTEGER:
+         {
+             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(
+                     vm,
+                     "Builtin 'cp@' expects exactly two arguments when used "
+                     "with integer.");
+             }
+ 
+             octaspire_dern_value_t const * const indexVal =
+                 octaspire_dern_value_as_vector_get_element_at_const(arguments, 1);
+ 
+             octaspire_helpers_verify_not_null(indexVal);
+ 
+             if (!octaspire_dern_value_is_integer(indexVal))
+             {
+                 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 an integer value. "
+                     "Now type '%s' was given.",
+                     octaspire_dern_value_helper_get_type_as_c_string(
+                         indexVal->typeTag));
+             }
+ 
+             int32_t const index =
+                 octaspire_dern_value_as_integer_get_value(indexVal);
+ 
+             if (index < -32 || index > 31)
+             {
+                 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@' must be between -32 .. 31 "
+                     "(inclusive) when indexing an integer. "
+ #ifdef __AROS__
+                     "Index '%ld' was given.",
+ #else
+                     "Index %" PRId32 " was given.",
+ #endif
+                     index);
+             }
+ 
+             uint32_t const bits =
+                 (uint32_t)octaspire_dern_value_as_integer_get_value(
+                     collectionVal);
+ 
+             uint32_t const realIndex = (index >= 0) ? index : (32 + index);
+             uint32_t const mask      = 1;
+ 
+             octaspire_helpers_verify_true(
+                 stackLength == octaspire_dern_vm_get_stack_length(vm));
+ 
+             return octaspire_dern_vm_create_new_value_integer(
+                 vm,
+                 (bits & (mask << realIndex)) ? 1 : 0);
+         }
+ 
+         case OCTASPIRE_DERN_VALUE_TAG_BOOLEAN:
          case OCTASPIRE_DERN_VALUE_TAG_REAL:
          case OCTASPIRE_DERN_VALUE_TAG_CHARACTER:
-         case OCTASPIRE_DERN_VALUE_TAG_SYMBOL:
          case OCTASPIRE_DERN_VALUE_TAG_ERROR:
          case OCTASPIRE_DERN_VALUE_TAG_ENVIRONMENT:
          case OCTASPIRE_DERN_VALUE_TAG_FUNCTION:


@@ 47695,6 47776,26 @@ return octaspire_string_pop_front_ucs_character(self->value.string);
  }
  
+ uint32_t octaspire_dern_value_as_text_get_ucs_character_at_index(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex)
+ {
+     octaspire_helpers_verify_true(
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_STRING ||
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_SYMBOL);
+ 
+     if (octaspire_dern_value_is_symbol(self))
+     {
+         return octaspire_string_get_ucs_character_at_index(
+             self->value.symbol,
+             possiblyNegativeIndex);
+     }
+ 
+     return octaspire_string_get_ucs_character_at_index(
+         self->value.string,
+         possiblyNegativeIndex);
+ }
+ 
  bool octaspire_dern_value_as_string_remove_all_substrings(
      octaspire_dern_value_t * const self,
      octaspire_dern_value_t * const value)


@@ 47760,6 47861,38 @@ possiblyNegativeIndex);
  }
  
+ bool octaspire_dern_value_as_symbol_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex)
+ {
+     octaspire_helpers_verify_true(
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_SYMBOL);
+ 
+     return octaspire_string_is_index_valid(
+         self->value.symbol,
+         possiblyNegativeIndex);
+ }
+ 
+ bool octaspire_dern_value_as_text_is_index_valid(
+     octaspire_dern_value_t const * const self,
+     ptrdiff_t const possiblyNegativeIndex)
+ {
+     octaspire_helpers_verify_true(
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_STRING ||
+         self->typeTag == OCTASPIRE_DERN_VALUE_TAG_SYMBOL);
+ 
+     if (octaspire_dern_value_is_symbol(self))
+     {
+         return octaspire_dern_value_as_symbol_is_index_valid(
+             self,
+             possiblyNegativeIndex);
+     }
+ 
+     return octaspire_dern_value_as_string_is_index_valid(
+         self,
+         possiblyNegativeIndex);
+ }
+ 
  bool octaspire_dern_value_as_string_is_empty(
      octaspire_dern_value_t const * const self)
  {


@@ 68135,6 68268,28 @@ PASS();
  }
  
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_symbol_abc_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@ 'abc {D+2})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_CHARACTER, evaluatedValue->typeTag);
+ 
+     ASSERT_STR_EQ(
+         "c",
+         octaspire_string_get_c_string(evaluatedValue->value.character));
+ 
+     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);


@@ 68148,8 68303,8 @@ ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_ERROR, evaluatedValue->typeTag);
  
      ASSERT_STR_EQ(
-         "Index to builtin 'cp@' is not valid for the given string. "
-         "Index '3' was given.\n"
+         "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));
  


@@ 68159,6 68314,220 @@ PASS();
  }
  
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_nil_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@ nil {D+3})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_NIL, evaluatedValue->typeTag);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_minus1_and_integer_with_only_MSB_on_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@ {B+10000000000000000000000000000000} {D-1})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(1,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_minus2_and_integer_with_only_MSB_on_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@ {B+10000000000000000000000000000000} {D-2})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_0_and_integer_Bplus_1000_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@ {B+1000} {D+0})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_integer_Bplus_1000_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@ {B+1000} {D+1})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_integer_Bplus_1000_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@ {B+1000} {D+2})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_integer_Bplus_1000_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@ {B+1000} {D+3})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(1,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_4_and_integer_Bplus_1000_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@ {B+1000} {D+4})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_31_and_integer_Bplus_1000_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@ {B+1000} {D+31})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_INTEGER, evaluatedValue->typeTag);
+     ASSERT_EQ(0,                                evaluatedValue->value.integer);
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
+ TEST octaspire_dern_vm_builtin_cp_at_sign_called_with_32_and_integer_Bplus_1000_failure_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@ {B+1000} {D+32})");
+ 
+     ASSERT(evaluatedValue);
+     ASSERT_EQ(OCTASPIRE_DERN_VALUE_TAG_ERROR, evaluatedValue->typeTag);
+ 
+     ASSERT_STR_EQ(
+         "Index to builtin 'cp@' must be between -32 .. 31 (inclusive) "
+         "when indexing an integer. Index 32 was given.\n"
+         "\tAt form: >>>>>>>>>>(cp@ {D+8} {D+32})<<<<<<<<<<\n",
+         octaspire_string_get_c_string(evaluatedValue->value.error->message));
+ 
+     octaspire_dern_vm_release(vm);
+     vm = 0;
+ 
+     PASS();
+ }
+ 
  TEST octaspire_dern_vm_builtin_ln_at_sign_called_with_0_and_vector_1_2_3_test(void)
  {
      octaspire_dern_vm_t *vm = octaspire_dern_vm_new(octaspireDernVmTestAllocator, octaspireDernVmTestStdio);


@@ 77036,7 77405,18 @@ 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_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);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_minus2_and_integer_with_only_MSB_on_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_0_and_integer_Bplus_1000_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_1_and_integer_Bplus_1000_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_2_and_integer_Bplus_1000_test);
+     RUN_TEST(octaspire_dern_vm_builtin_cp_at_sign_called_with_3_and_integer_Bplus_1000_test);
+     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/plugins/dern_nuklear.c => release/plugins/dern_nuklear.c +2 -2
@@ 2432,8 2432,8 @@ "",
          "",
          "",
-         "",//"dern_nuklear_to_string",
-         "",//"dern_nuklear_compare",
+         "", //"dern_nuklear_to_string",
+         "", //"dern_nuklear_compare",
          false,
          context);
  }