Lichen

templates/ops.c

588:316c1c90b643
2017-02-17 Paul Boddie Eliminated superfluous accessor instructions loading static invocation targets. Added a test of nested calls employing explicitly retained contexts. method-wrapper-for-context
     1 /* Common operations.     2      3 Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>     4      5 This program is free software; you can redistribute it and/or modify it under     6 the terms of the GNU General Public License as published by the Free Software     7 Foundation; either version 3 of the License, or (at your option) any later     8 version.     9     10 This program is distributed in the hope that it will be useful, but WITHOUT    11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    12 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    13 details.    14     15 You should have received a copy of the GNU General Public License along with    16 this program.  If not, see <http://www.gnu.org/licenses/>.    17 */    18     19 #include "gc.h" /* GC_MALLOC, GC_REALLOC */    20 #include "ops.h"    21 #include "progops.h" /* for raising errors */    22 #include "progconsts.h"    23 #include "progtypes.h"    24 #include <stdio.h>    25     26 /* Direct access and manipulation of static objects. */    27     28 __attr __load_static_ignore(__ref obj)    29 {    30     return (__attr) {.value=obj};    31 }    32     33 __attr __load_static_replace(__ref context, __ref obj)    34 {    35     return __update_context(context, (__attr) {.value=obj});    36 }    37     38 __attr __load_static_test(__ref context, __ref obj)    39 {    40     return __test_context(context, (__attr) {.value=obj});    41 }    42     43 /* Direct retrieval operations, returning and setting attributes. */    44     45 __attr __load_via_object(__ref obj, int pos)    46 {    47     return obj->attrs[pos];    48 }    49     50 __attr __load_via_class(__ref obj, int pos)    51 {    52     return __load_via_object(__get_class(obj), pos);    53 }    54     55 __attr __get_class_and_load(__ref obj, int pos)    56 {    57     if (__is_instance(obj))    58         return __load_via_class(obj, pos);    59     else    60         return __load_via_object(obj, pos);    61 }    62     63 /* Direct storage operations. */    64     65 int __store_via_object(__ref obj, int pos, __attr value)    66 {    67     obj->attrs[pos] = value;    68     return 1;    69 }    70     71 int __get_class_and_store(__ref obj, int pos, __attr value)    72 {    73     /* Forbid class-relative assignments. */    74     75     __raise_type_error();    76     return 0;    77 }    78     79 /* Introspection. */    80     81 int __is_instance(__ref obj)    82 {    83     return obj->pos == __INSTANCEPOS;    84 }    85     86 int __is_type_instance(__ref obj)    87 {    88     return __HASATTR(__get_class(obj), __TYPE_CLASS_POS, __TYPE_CLASS_CODE);    89 }    90     91 __ref __get_class(__ref obj)    92 {    93     return __load_via_object(obj, __pos___class__).value;    94 }    95     96 __attr __get_class_attr(__ref obj)    97 {    98     return __load_via_object(obj, __pos___class__);    99 }   100    101 /* Attribute testing operations. */   102    103 __ref __test_specific_instance(__ref obj, __ref type)   104 {   105     return __get_class(obj) == type ? obj : 0;   106 }   107    108 __ref __test_specific_object(__ref obj, __ref type)   109 {   110     return __test_specific_type(obj, type) || __test_specific_instance(obj, type) ? obj : 0;   111 }   112    113 __ref __test_specific_type(__ref obj, __ref type)   114 {   115     return obj == type ? obj : 0;   116 }   117    118 __ref __test_common_instance(__ref obj, int pos, int code)   119 {   120     return __HASATTR(__get_class(obj), pos, code) ? obj : 0;   121 }   122    123 __ref __test_common_object(__ref obj, int pos, int code)   124 {   125     return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0;   126 }   127    128 __ref __test_common_type(__ref obj, int pos, int code)   129 {   130     return __HASATTR(obj, pos, code) ? obj : 0;   131 }   132    133 /* Attribute testing and retrieval operations. */   134    135 __attr __check_and_load_via_object_null(__ref obj, int pos, int code)   136 {   137     if (__HASATTR(obj, pos, code))   138         return __load_via_object(obj, pos);   139     else   140         return __NULL;   141 }   142    143 __attr __check_and_load_via_class(__ref obj, int pos, int code)   144 {   145     return __check_and_load_via_object(__get_class(obj), pos, code);   146 }   147    148 __attr __check_and_load_via_object(__ref obj, int pos, int code)   149 {   150     if (__HASATTR(obj, pos, code))   151         return __load_via_object(obj, pos);   152    153     __raise_type_error();   154     return __NULL;   155 }   156    157 __attr __check_and_load_via_any(__ref obj, int pos, int code)   158 {   159     __attr out = __check_and_load_via_object_null(obj, pos, code);   160     if (out.value == 0)   161         out = __check_and_load_via_class(obj, pos, code);   162     return out;   163 }   164    165 /* Attribute testing and storage operations. */   166    167 int __check_and_store_via_class(__ref obj, int pos, int code, __attr value)   168 {   169     /* Forbid class-relative assignments. */   170    171     __raise_type_error();   172     return 0;   173 }   174    175 int __check_and_store_via_object(__ref obj, int pos, int code, __attr value)   176 {   177     if (__HASATTR(obj, pos, code))   178     {   179         __store_via_object(obj, pos, value);   180         return 1;   181     }   182    183     /* No suitable attribute. */   184    185     __raise_type_error();   186     return 0;   187 }   188    189 int __check_and_store_via_any(__ref obj, int pos, int code, __attr value)   190 {   191     if (__check_and_store_via_object(obj, pos, code, value))   192         return 1;   193    194     /* Forbid class-relative assignments. */   195    196     __raise_type_error();   197     return 0;   198 }   199    200 /* Context-related operations. */   201    202 __attr __test_context(__ref context, __attr attr)   203 {   204     __ref attrcontext = __CONTEXT_AS_VALUE(attr).value;   205    206     /* Preserve any existing null or instance context. */   207    208     if ((attrcontext == 0) || __is_instance(attrcontext))   209         return attr;   210    211     /* Test any instance context against the context employed by the   212        attribute. */   213    214     if (__is_instance(context))   215     {   216         if (__test_common_instance(context, __TYPEPOS(attrcontext), __TYPECODE(attrcontext)))   217             return __update_context(context, attr);   218         else   219             __raise_type_error();   220     }   221    222     /* Test for access to a type class attribute using a type instance. */   223    224     if (__test_specific_type(attrcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context))   225         return __update_context(context, attr);   226    227     /* Otherwise, preserve the attribute as retrieved. */   228    229     return attr;   230 }   231    232 __attr __update_context(__ref context, __attr attr)   233 {   234     return __new_wrapper(context, attr);   235 }   236    237 /* Context testing for invocations. */   238    239 int __type_method_invocation(__ref context, __attr target)   240 {   241     __ref targetcontext = __CONTEXT_AS_VALUE(target).value;   242    243     /* Require instances, not classes, where methods are function instances. */   244    245     if (!__is_instance(target.value))   246         return 0;   247    248     /* Access the context of the callable and test if it is the type object. */   249    250     return ((targetcontext != 0) && __test_specific_type(targetcontext, &__TYPE_CLASS_TYPE) && __is_type_instance(context));   251 }   252    253 __attr __unwrap_callable(__attr callable)   254 {   255     __attr value = __check_and_load_via_object_null(callable.value, __ATTRPOS(__value__), __ATTRCODE(__value__));   256     return value.value ? value : callable;   257 }   258    259 __attr (*__get_function(__ref context, __attr target))(__attr[])   260 {   261     target = __unwrap_callable(target);   262    263     /* Require null or instance contexts for functions and methods respectively,   264        or type instance contexts for type methods. */   265    266     if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))   267         return __load_via_object(target.value, __ATTRPOS(__fn__)).fn;   268     else   269         return __unbound_method;   270 }   271    272 __attr (*__check_and_get_function(__ref context, __attr target))(__attr[])   273 {   274     target = __unwrap_callable(target);   275    276     /* Require null or instance contexts for functions and methods respectively,   277        or type instance contexts for type methods. */   278    279     if ((context == 0) || __is_instance(context) || __type_method_invocation(context, target))   280         return __check_and_load_via_object(target.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;   281     else   282         return __unbound_method;   283 }   284    285 /* Basic structure tests. */   286    287 int __WITHIN(__ref obj, int pos)   288 {   289     return pos < obj->table->size;   290 }   291    292 int __HASATTR(__ref obj, int pos, int code)   293 {   294     return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code);   295 }   296    297 /* Parameter position operations. */   298    299 int __HASPARAM(const __ptable *ptable, int ppos, int pcode)   300 {   301     __param param;   302    303     if (ppos < ptable->size)   304     {   305         param = ptable->params[ppos];   306         if (param.code == pcode)   307             return param.pos;   308     }   309    310     return -1;   311 }   312    313 /* Conversions. */   314    315 __attr __CONTEXT_AS_VALUE(__attr attr)   316 {   317     return __check_and_load_via_object_null(attr.value, __ATTRPOS(__context__), __ATTRCODE(__context__));   318 }   319    320 /* Type testing. */   321    322 __ref __ISFUNC(__ref obj)   323 {   324     return __test_specific_instance(obj, &__FUNCTION_TYPE);   325 }   326    327 int __ISNULL(__attr value)   328 {   329     return (value.value == 0); /* __NULL.value */   330 }   331    332 /* Attribute codes and positions for type objects. */   333    334 unsigned int __TYPECODE(__ref obj)   335 {   336     return obj->table->attrs[obj->pos];   337 }   338    339 unsigned int __TYPEPOS(__ref obj)   340 {   341     return obj->pos;   342 }   343    344 /* Memory allocation. */   345    346 void *__ALLOCATE(size_t nmemb, size_t size)   347 {   348     void *ptr = GC_MALLOC(nmemb * size); /* sets memory to zero */   349     if (ptr == NULL)   350         __raise_memory_error();   351     return ptr;   352 }   353    354 void *__REALLOCATE(void *ptr, size_t size)   355 {   356     void *nptr = GC_REALLOC(ptr, size);   357     if (nptr == NULL)   358         __raise_memory_error();   359     return nptr;   360 }   361    362 /* Copying of structures. */   363    364 __ref __COPY(__ref obj, int size)   365 {   366     __ref copy = (__ref) __ALLOCATE(1, size);   367     memcpy(copy, obj, size);   368     return copy;   369 }