Lichen

templates/ops.c

217:e5aa9e58703e
2016-11-23 Paul Boddie Automatically convert non-buffer, non-string objects to strings for appending.
     1 /* Common operations. */     2      3 #include <stdlib.h>     4 #include "ops.h"     5 #include "progconsts.h"     6 #include "progtypes.h"     7      8 /* Direct access and manipulation of static objects. */     9     10 __attr __load_static(__ref parent, __ref obj)    11 {    12     __attr out = {.context=parent, .value=obj};    13     return out;    14 }    15     16 /* Direct retrieval operations, returning and setting attributes. */    17     18 __attr __load_via_object(__ref obj, int pos)    19 {    20     return obj->attrs[pos];    21 }    22     23 __attr __load_via_class(__ref obj, int pos)    24 {    25     return __load_via_object(__get_class(obj), pos);    26 }    27     28 __attr __get_class_and_load(__ref obj, int pos)    29 {    30     if (__is_instance(obj))    31         return __load_via_class(obj, pos);    32     else    33         return __load_via_object(obj, pos);    34 }    35     36 /* Direct storage operations. */    37     38 int __store_via_object(__ref obj, int pos, __attr value)    39 {    40     obj->attrs[pos] = value;    41     return 1;    42 }    43     44 /* Introspection. */    45     46 int __is_instance(__ref obj)    47 {    48     return obj->pos == __INSTANCEPOS;    49 }    50     51 __ref __get_class(__ref obj)    52 {    53     return __load_via_object(obj, __pos___class__).value;    54 }    55     56 /* Attribute testing operations. */    57     58 __ref __test_specific_instance(__ref obj, __ref type)    59 {    60     return __get_class(obj) == type ? obj : 0;    61 }    62     63 __ref __test_common_instance(__ref obj, int pos, int code)    64 {    65     return __HASATTR(__get_class(obj), pos, code) ? obj : 0;    66 }    67     68 __ref __test_common_object(__ref obj, int pos, int code)    69 {    70     return __test_common_type(obj, pos, code) || __test_common_instance(obj, pos, code) ? obj : 0;    71 }    72     73 __ref __test_common_type(__ref obj, int pos, int code)    74 {    75     return __HASATTR(obj, pos, code) ? obj : 0;    76 }    77     78 /* Attribute testing and retrieval operations. */    79     80 __attr __check_and_load_via_class(__ref obj, int pos, int code)    81 {    82     return __check_and_load_via_object(__get_class(obj), pos, code);    83 }    84     85 __attr __check_and_load_via_object(__ref obj, int pos, int code)    86 {    87     return __HASATTR(obj, pos, code) ? __load_via_object(obj, pos) : __NULL;    88 }    89     90 __attr __check_and_load_via_any(__ref obj, int pos, int code)    91 {    92     __attr out = __check_and_load_via_object(obj, pos, code);    93     if (out.value == 0)    94         out = __check_and_load_via_class(obj, pos, code);    95     return out;    96 }    97     98 /* Attribute testing and storage operations. */    99    100 int __check_and_store_via_object(__ref obj, int pos, int code, __attr value)   101 {   102     if (__HASATTR(obj, pos, code))   103     {   104         __store_via_object(obj, pos, value);   105         return 1;   106     }   107     return 0;   108 }   109    110 int __check_and_store_via_any(__ref obj, int pos, int code, __attr value)   111 {   112     if (__check_and_store_via_object(obj, pos, code, value))   113         return 1;   114     return __check_and_store_via_object(__get_class(obj), pos, code, value);   115 }   116    117 /* Context-related operations. */   118    119 __attr __test_context(__ref context, __attr attr)   120 {   121     if (__is_instance(attr.context))   122         return attr;   123     if (__test_common_instance(context, __TYPEPOS(attr.context), __TYPECODE(attr.context)))   124         return __replace_context(context, attr);   125    126     /* NOTE: An error may be more appropriate. */   127    128     return __NULL;   129 }   130    131 __attr __replace_context(__ref context, __attr attr)   132 {   133     __attr out;   134    135     /* Set the context. */   136    137     out.context = context;   138    139     /* Reference a callable version of the attribute by obtaining the bound   140        method reference from the __fn__ special attribute. */   141    142     out.value = __load_via_object(attr.value, __ATTRPOS(__fn__)).b;   143     return out;   144 }   145    146 __attr __update_context(__ref context, __attr attr)   147 {   148     __attr out = {context, .fn=attr.fn};   149     return out;   150 }   151    152 /* Basic structure tests. */   153    154 int __WITHIN(__ref obj, int pos)   155 {   156     return pos < obj->table->size;   157 }   158    159 int __HASATTR(__ref obj, int pos, int code)   160 {   161     return __WITHIN(obj, pos) && (obj->table->attrs[pos] == code);   162 }   163    164 /* Parameter position operations. */   165    166 int __HASPARAM(const __ptable *ptable, int ppos, int pcode)   167 {   168     __param param;   169    170     if (ppos < ptable->size)   171     {   172         param = ptable->params[ppos];   173         if (param.code == pcode)   174             return param.pos;   175     }   176    177     return -1;   178 }   179    180 /* Conversions. */   181    182 __attr __CONTEXT_AS_VALUE(__attr attr)   183 {   184     __attr out;   185     out.context = attr.context;   186     out.value = attr.context;   187     return out;   188 }   189    190 /* Type testing. */   191    192 __ref __ISFUNC(__ref obj)   193 {   194     return __test_specific_instance(obj, &__FUNCTION_TYPE);   195 }   196    197 int __ISNULL(__attr value)   198 {   199     /* (value.context == __NULL.context) is superfluous */   200     return (value.value == 0); /* __NULL.value */   201 }   202    203 /* Attribute codes and positions for type objects. */   204    205 unsigned int __TYPECODE(__ref obj)   206 {   207     return obj->table->attrs[obj->pos];   208 }   209    210 unsigned int __TYPEPOS(__ref obj)   211 {   212     return obj->pos;   213 }   214    215 /* Copying of structures. */   216    217 __ref __COPY(__ref obj, int size)   218 {   219     __ref copy = calloc(1, size);   220     memcpy(copy, obj, size);   221     return copy;   222 }