Lichen

templates/ops.c

543:b7334adb7dec
2017-02-04 Paul Boddie Handle situations where a global accidentally refers to a built-in module.
     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(__ref parent, __ref obj)    29 {    30     __attr out = {.context=parent, .value=obj};    31     return out;    32 }    33     34 /* Direct retrieval operations, returning and setting attributes. */    35     36 __attr __load_via_object(__ref obj, int pos)    37 {    38     return obj->attrs[pos];    39 }    40     41 __attr __load_via_class(__ref obj, int pos)    42 {    43     return __load_via_object(__get_class(obj), pos);    44 }    45     46 __attr __get_class_and_load(__ref obj, int pos)    47 {    48     if (__is_instance(obj))    49         return __load_via_class(obj, pos);    50     else    51         return __load_via_object(obj, pos);    52 }    53     54 /* Direct storage operations. */    55     56 int __store_via_object(__ref obj, int pos, __attr value)    57 {    58     obj->attrs[pos] = value;    59     return 1;    60 }    61     62 int __get_class_and_store(__ref obj, int pos, __attr value)    63 {    64     /* Forbid class-relative assignments. */    65     66     __raise_type_error();    67     return 0;    68 }    69     70 /* Introspection. */    71     72 int __is_instance(__ref obj)    73 {    74     return obj->pos == __INSTANCEPOS;    75 }    76     77 int __is_type_instance(__ref obj)    78 {    79     return __HASATTR(__get_class(obj), __TYPE_CLASS_POS, __TYPE_CLASS_CODE);    80 }    81     82 __ref __get_class(__ref obj)    83 {    84     return __load_via_object(obj, __pos___class__).value;    85 }    86     87 __attr __get_class_attr(__ref obj)    88 {    89     return __load_via_object(obj, __pos___class__);    90 }    91     92 /* Attribute testing operations. */    93     94 __ref __test_specific_instance(__ref obj, __ref type)    95 {    96     return __get_class(obj) == type ? obj : 0;    97 }    98     99 __ref __test_specific_object(__ref obj, __ref type)   100 {   101     return __test_specific_type(obj, type) || __test_specific_instance(obj, type) ? obj : 0;   102 }   103    104 __ref __test_specific_type(__ref obj, __ref type)   105 {   106     return obj == type ? obj : 0;   107 }   108    109 __ref __test_common_instance(__ref obj, int pos, int code)   110 {   111     return __HASATTR(__get_class(obj), pos, code) ? obj : 0;   112 }   113    114 __ref __test_common_object(__ref obj, int pos, int code)   115 {   116     return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0;   117 }   118    119 __ref __test_common_type(__ref obj, int pos, int code)   120 {   121     return __HASATTR(obj, pos, code) ? obj : 0;   122 }   123    124 /* Attribute testing and retrieval operations. */   125    126 __attr __check_and_load_via_object_null(__ref obj, int pos, int code)   127 {   128     if (__HASATTR(obj, pos, code))   129         return __load_via_object(obj, pos);   130     else   131         return __NULL;   132 }   133    134 __attr __check_and_load_via_class(__ref obj, int pos, int code)   135 {   136     return __check_and_load_via_object(__get_class(obj), pos, code);   137 }   138    139 __attr __check_and_load_via_object(__ref obj, int pos, int code)   140 {   141     if (__HASATTR(obj, pos, code))   142         return __load_via_object(obj, pos);   143    144     __raise_type_error();   145     return __NULL;   146 }   147    148 __attr __check_and_load_via_any(__ref obj, int pos, int code)   149 {   150     __attr out = __check_and_load_via_object_null(obj, pos, code);   151     if (out.value == 0)   152         out = __check_and_load_via_class(obj, pos, code);   153     return out;   154 }   155    156 /* Attribute testing and storage operations. */   157    158 int __check_and_store_via_class(__ref obj, int pos, int code, __attr value)   159 {   160     /* Forbid class-relative assignments. */   161    162     __raise_type_error();   163     return 0;   164 }   165    166 int __check_and_store_via_object(__ref obj, int pos, int code, __attr value)   167 {   168     if (__HASATTR(obj, pos, code))   169     {   170         __store_via_object(obj, pos, value);   171         return 1;   172     }   173    174     /* No suitable attribute. */   175    176     __raise_type_error();   177     return 0;   178 }   179    180 int __check_and_store_via_any(__ref obj, int pos, int code, __attr value)   181 {   182     if (__check_and_store_via_object(obj, pos, code, value))   183         return 1;   184    185     /* Forbid class-relative assignments. */   186    187     __raise_type_error();   188     return 0;   189 }   190    191 /* Context-related operations. */   192    193 __attr __test_context(__ref context, __attr attr)   194 {   195     /* Preserve any existing null or instance context. */   196    197     if ((attr.context == 0) || __is_instance(attr.context))   198         return attr;   199    200     /* Test any instance context against the context employed by the   201        attribute. */   202    203     if (__is_instance(context))   204     {   205         if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context)))   206             return __update_context(context, attr);   207         else   208             __raise_type_error();   209     }   210    211     /* Test for access to a type class attribute using a type instance. */   212    213     if (__test_specific_type(attr.context, &__TYPE_CLASS_TYPE) && __is_type_instance(context))   214         return __update_context(context, attr);   215    216     /* Otherwise, preserve the attribute as retrieved. */   217    218     return attr;   219 }   220    221 __attr __update_context(__ref context, __attr attr)   222 {   223     __attr out = {.context=context, .value=attr.value};   224     return out;   225 }   226    227 /* Context testing for invocations. */   228    229 int __type_method_invocation(__attr attr)   230 {   231     __attr parent;   232    233     /* Require instances, not classes, where methods are function instances. */   234    235     if (!__is_instance(attr.value))   236         return 0;   237    238     /* Access the parent of the callable and test if it is the type object. */   239    240     parent = __check_and_load_via_object_null(attr.value, __ATTRPOS(__parent__), __ATTRCODE(__parent__));   241     return ((parent.value != 0) && __test_specific_type(parent.value, &__TYPE_CLASS_TYPE) && __is_type_instance(attr.context));   242 }   243    244 __attr (*__get_function(__attr attr))(__attr[])   245 {   246     /* Require null or instance contexts for functions and methods respectively,   247        or type instance contexts for type methods. */   248    249     if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))   250         return __load_via_object(attr.value, __ATTRPOS(__fn__)).fn;   251     else   252         return __load_via_object(attr.value, __ATTRPOS(__fn__)).inv;   253 }   254    255 __attr (*__check_and_get_function(__attr attr))(__attr[])   256 {   257     /* Require null or instance contexts for functions and methods respectively,   258        or type instance contexts for type methods. */   259    260     if ((attr.context == 0) || __is_instance(attr.context) || __type_method_invocation(attr))   261         return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).fn;   262     else   263         return __check_and_load_via_object(attr.value, __ATTRPOS(__fn__), __ATTRCODE(__fn__)).inv;   264 }   265    266 /* Basic structure tests. */   267    268 int __WITHIN(__ref obj, int pos)   269 {   270     return pos < obj->table->size;   271 }   272    273 int __HASATTR(__ref obj, int pos, int code)   274 {   275     return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code);   276 }   277    278 /* Parameter position operations. */   279    280 int __HASPARAM(const __ptable *ptable, int ppos, int pcode)   281 {   282     __param param;   283    284     if (ppos < ptable->size)   285     {   286         param = ptable->params[ppos];   287         if (param.code == pcode)   288             return param.pos;   289     }   290    291     return -1;   292 }   293    294 /* Conversions. */   295    296 __attr __CONTEXT_AS_VALUE(__attr attr)   297 {   298     __attr out;   299     out.context = attr.context;   300     out.value = attr.context;   301     return out;   302 }   303    304 /* Type testing. */   305    306 __ref __ISFUNC(__ref obj)   307 {   308     return __test_specific_instance(obj, &__FUNCTION_TYPE);   309 }   310    311 int __ISNULL(__attr value)   312 {   313     /* (value.context == __NULL.context) is superfluous */   314     return (value.value == 0); /* __NULL.value */   315 }   316    317 /* Attribute codes and positions for type objects. */   318    319 unsigned int __TYPECODE(__ref obj)   320 {   321     return obj->table->attrs[obj->pos];   322 }   323    324 unsigned int __TYPEPOS(__ref obj)   325 {   326     return obj->pos;   327 }   328    329 /* Memory allocation. */   330    331 void *__ALLOCATE(size_t nmemb, size_t size)   332 {   333     void *ptr = GC_MALLOC(nmemb * size); /* sets memory to zero */   334     if (ptr == NULL)   335         __raise_memory_error();   336     return ptr;   337 }   338    339 void *__REALLOCATE(void *ptr, size_t size)   340 {   341     void *nptr = GC_REALLOC(ptr, size);   342     if (nptr == NULL)   343         __raise_memory_error();   344     return nptr;   345 }   346    347 /* Copying of structures. */   348    349 __ref __COPY(__ref obj, int size)   350 {   351     __ref copy = (__ref) __ALLOCATE(1, size);   352     memcpy(copy, obj, size);   353     return copy;   354 }