Lichen

templates/native.c

288:fff09c70f489
2016-11-30 Paul Boddie Implemented the dictionary items method and expanded IndexError. Expanded the dictionary test program.
     1 #include <stdlib.h> /* exit */     2 #include <unistd.h> /* read, write */     3 #include <math.h>   /* ceil, log10, pow */     4 #include <string.h> /* strcmp, strncpy, strlen */     5 #include <stdio.h>  /* snprintf */     6 #include "types.h"     7 #include "exceptions.h"     8 #include "ops.h"     9 #include "progconsts.h"    10 #include "progops.h"    11 #include "progtypes.h"    12 #include "main.h"    13     14 /* Utility functions. */    15     16 static __attr __new_int(int i)    17 {    18     /* Create a new integer and mutate the __data__ attribute. */    19     __attr attr = __new(&__InstanceTable___builtins___int_int, &__builtins___int_int, sizeof(__obj___builtins___int_int));    20     attr.value->attrs[__pos___data__].intvalue = i;    21     return attr;    22 }    23     24 static __attr __new_str(char *s)    25 {    26     /* Create a new string and mutate the __data__ attribute. */    27     __attr attr = __new(&__InstanceTable___builtins___str_string, &__builtins___str_string, sizeof(__obj___builtins___str_string));    28     attr.value->attrs[__pos___data__].strvalue = s;    29     return attr;    30 }    31     32 static __attr __new_list(__fragment *f)    33 {    34     /* Create a new list and mutate the __data__ attribute. */    35     __attr attr = __new(&__InstanceTable___builtins___list_list, &__builtins___list_list, sizeof(__obj___builtins___list_list));    36     attr.value->attrs[__pos___data__].seqvalue = f;    37     return attr;    38 }    39     40 static __fragment *__fragment_append(__fragment *data, __attr * const value)    41 {    42     __fragment *newdata = data;    43     unsigned int size = data->size, capacity = data->capacity;    44     unsigned int n;    45     46     /* Re-allocate the fragment if the capacity has been reached. */    47     if (size >= capacity)    48     {    49         /* NOTE: Consider various restrictions on capacity increases. */    50         n = capacity ? capacity * 2 : 1;    51         newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));    52         newdata->capacity = n;    53     }    54     55     /* Insert the new element and increment the list size. */    56     newdata->attrs[size] = *value;    57     newdata->size = size + 1;    58     59     return newdata;    60 }    61     62 /* Native functions. */    63     64 __attr __fn_native__exit(__attr __args[])    65 {    66     __attr * const status = &__args[1];    67     68     exit(__load_via_object(status->value, __pos___data__).intvalue);    69     return __builtins___none_None;    70 }    71     72 __attr __fn_native__get_argv(__attr __args[])    73 {    74     __attr * const status = &__args[1];    75     76     /* NOTE: To be written. */    77     return __builtins___none_None;    78 }    79     80 __attr __fn_native__get_path(__attr __args[])    81 {    82     __attr * const status = &__args[1];    83     84     /* NOTE: To be written. */    85     return __builtins___none_None;    86 }    87     88 __attr __fn_native__is(__attr __args[])    89 {    90     __attr * const x = &__args[1];    91     __attr * const y = &__args[2];    92     93     return x->value == y->value ? __builtins___boolean_True : __builtins___boolean_False;    94 }    95     96 __attr __fn_native__is_not(__attr __args[])    97 {    98     __attr * const x = &__args[1];    99     __attr * const y = &__args[2];   100    101     return x->value != y->value ? __builtins___boolean_True : __builtins___boolean_False;   102 }   103    104 __attr __fn_native__int_add(__attr __args[])   105 {   106     __attr * const self = &__args[1];   107     __attr * const other = &__args[2];   108     /* self.__data__ and other.__data__ interpreted as int */   109     int i = __load_via_object(self->value, __pos___data__).intvalue;   110     int j = __load_via_object(other->value, __pos___data__).intvalue;   111    112     /* Return the new integer. */   113     /* NOTE: No overflow test applied. */   114     return __new_int(i + j);   115 }   116    117 __attr __fn_native__int_sub(__attr __args[])   118 {   119     __attr * const self = &__args[1];   120     __attr * const other = &__args[2];   121     /* self.__data__ and other.__data__ interpreted as int */   122     int i = __load_via_object(self->value, __pos___data__).intvalue;   123     int j = __load_via_object(other->value, __pos___data__).intvalue;   124    125     /* Return the new integer. */   126     /* NOTE: No overflow test applied. */   127     return __new_int(i - j);   128 }   129    130 __attr __fn_native__int_mul(__attr __args[])   131 {   132     __attr * const self = &__args[1];   133     __attr * const other = &__args[2];   134     /* self.__data__ and other.__data__ interpreted as int */   135     int i = __load_via_object(self->value, __pos___data__).intvalue;   136     int j = __load_via_object(other->value, __pos___data__).intvalue;   137    138     /* Return the new integer. */   139     /* NOTE: No overflow test applied. */   140     return __new_int(i * j);   141 }   142    143 __attr __fn_native__int_div(__attr __args[])   144 {   145     __attr * const self = &__args[1];   146     __attr * const other = &__args[2];   147     /* self.__data__ and other.__data__ interpreted as int */   148     int i = __load_via_object(self->value, __pos___data__).intvalue;   149     int j = __load_via_object(other->value, __pos___data__).intvalue;   150    151     /* Return the new integer. */   152     /* NOTE: No overflow test applied. */   153     return __new_int(i / j);   154 }   155    156 __attr __fn_native__int_mod(__attr __args[])   157 {   158     __attr * const self = &__args[1];   159     __attr * const other = &__args[2];   160     /* self.__data__ and other.__data__ interpreted as int */   161     int i = __load_via_object(self->value, __pos___data__).intvalue;   162     int j = __load_via_object(other->value, __pos___data__).intvalue;   163    164     /* Return the new integer. */   165     /* NOTE: No overflow test applied. */   166     return __new_int(i % j);   167 }   168    169 __attr __fn_native__int_neg(__attr __args[])   170 {   171     __attr * const self = &__args[1];   172     /* self.__data__ interpreted as int */   173     int i = __load_via_object(self->value, __pos___data__).intvalue;   174    175     /* Return the new integer. */   176     return __new_int(-i);   177 }   178    179 __attr __fn_native__int_pow(__attr __args[])   180 {   181     __attr * const self = &__args[1];   182     __attr * const other = &__args[2];   183     /* self.__data__ and other.__data__ interpreted as int */   184     int i = __load_via_object(self->value, __pos___data__).intvalue;   185     int j = __load_via_object(other->value, __pos___data__).intvalue;   186    187     /* Return the new integer. */   188     /* NOTE: No overflow test applied. */   189     return __new_int((int) pow(i, j));   190 }   191    192 __attr __fn_native__int_and(__attr __args[])   193 {   194     __attr * const self = &__args[1];   195     __attr * const other = &__args[2];   196     /* self.__data__ and other.__data__ interpreted as int */   197     int i = __load_via_object(self->value, __pos___data__).intvalue;   198     int j = __load_via_object(other->value, __pos___data__).intvalue;   199    200     /* Return the new integer. */   201     /* NOTE: No overflow test applied. */   202     return __new_int(i & j);   203 }   204    205 __attr __fn_native__int_or(__attr __args[])   206 {   207     __attr * const self = &__args[1];   208     __attr * const other = &__args[2];   209     /* self.__data__ and other.__data__ interpreted as int */   210     int i = __load_via_object(self->value, __pos___data__).intvalue;   211     int j = __load_via_object(other->value, __pos___data__).intvalue;   212    213     /* Return the new integer. */   214     /* NOTE: No overflow test applied. */   215     return __new_int(i | j);   216 }   217    218 __attr __fn_native__int_xor(__attr __args[])   219 {   220     __attr * const self = &__args[1];   221     __attr * const other = &__args[2];   222     /* self.__data__ and other.__data__ interpreted as int */   223     int i = __load_via_object(self->value, __pos___data__).intvalue;   224     int j = __load_via_object(other->value, __pos___data__).intvalue;   225    226     /* Return the new integer. */   227     /* NOTE: No overflow test applied. */   228     return __new_int(i ^ j);   229 }   230    231 __attr __fn_native__int_lt(__attr __args[])   232 {   233     __attr * const self = &__args[1];   234     __attr * const other = &__args[2];   235     /* self.__data__ and other.__data__ interpreted as int */   236     int i = __load_via_object(self->value, __pos___data__).intvalue;   237     int j = __load_via_object(other->value, __pos___data__).intvalue;   238    239     /* Return a boolean result. */   240     return i < j ? __builtins___boolean_True : __builtins___boolean_False;   241 }   242    243 __attr __fn_native__int_gt(__attr __args[])   244 {   245     __attr * const self = &__args[1];   246     __attr * const other = &__args[2];   247     /* self.__data__ and other.__data__ interpreted as int */   248     int i = __load_via_object(self->value, __pos___data__).intvalue;   249     int j = __load_via_object(other->value, __pos___data__).intvalue;   250    251     /* Return a boolean result. */   252     return i > j ? __builtins___boolean_True : __builtins___boolean_False;   253 }   254    255 __attr __fn_native__int_eq(__attr __args[])   256 {   257     __attr * const self = &__args[1];   258     __attr * const other = &__args[2];   259     /* self.__data__ and other.__data__ interpreted as int */   260     int i = __load_via_object(self->value, __pos___data__).intvalue;   261     int j = __load_via_object(other->value, __pos___data__).intvalue;   262    263     /* Return a boolean result. */   264     return i == j ? __builtins___boolean_True : __builtins___boolean_False;   265 }   266    267 __attr __fn_native__int_ne(__attr __args[])   268 {   269     __attr * const self = &__args[1];   270     __attr * const other = &__args[2];   271     /* self.__data__ and other.__data__ interpreted as int */   272     int i = __load_via_object(self->value, __pos___data__).intvalue;   273     int j = __load_via_object(other->value, __pos___data__).intvalue;   274    275     /* Return a boolean result. */   276     return i != j ? __builtins___boolean_True : __builtins___boolean_False;   277 }   278    279 __attr __fn_native__int_str(__attr __args[])   280 {   281     __attr * const self = &__args[1];   282     /* self.__data__ interpreted as int */   283     int i = __load_via_object(self->value, __pos___data__).intvalue;   284     int n = i != 0 ? (int) ceil(log10(i+1)) + 1 : 2;   285     char *s = (char *) __ALLOCATE(n, sizeof(char));   286    287     if (i < 0) n++;   288     snprintf(s, n, "%d", i);   289    290     /* Return a new string. */   291     return __new_str(s);   292 }   293    294 __attr __fn_native__str_add(__attr __args[])   295 {   296     __attr * const self = &__args[1];   297     __attr * const other = &__args[2];   298     /* self.__data__, other.__data__ interpreted as string */   299     char *s = __load_via_object(self->value, __pos___data__).strvalue;   300     char *o = __load_via_object(other->value, __pos___data__).strvalue;   301     int n = strlen(s) + strlen(o) + 1;   302     char *r = (char *) __ALLOCATE(n, sizeof(char));   303    304     strncpy(r, s, n);   305     strncpy(r + strlen(s), o, n - strlen(s));   306    307     /* Return a new string. */   308     return __new_str(r);   309 }   310    311 __attr __fn_native__str_lt(__attr __args[])   312 {   313     __attr * const self = &__args[1];   314     __attr * const other = &__args[2];   315     /* self.__data__, other.__data__ interpreted as string */   316     char *s = __load_via_object(self->value, __pos___data__).strvalue;   317     char *o = __load_via_object(other->value, __pos___data__).strvalue;   318    319     /* NOTE: Using simple byte-level string operations. */   320     return strcmp(s, o) < 0 ? __builtins___boolean_True : __builtins___boolean_False;   321 }   322    323 __attr __fn_native__str_gt(__attr __args[])   324 {   325     __attr * const self = &__args[1];   326     __attr * const other = &__args[2];   327     /* self.__data__, other.__data__ interpreted as string */   328     char *s = __load_via_object(self->value, __pos___data__).strvalue;   329     char *o = __load_via_object(other->value, __pos___data__).strvalue;   330    331     /* NOTE: Using simple byte-level string operations. */   332     return strcmp(s, o) > 0 ? __builtins___boolean_True : __builtins___boolean_False;   333 }   334    335 __attr __fn_native__str_eq(__attr __args[])   336 {   337     __attr * const self = &__args[1];   338     __attr * const other = &__args[2];   339     /* self.__data__, other.__data__ interpreted as string */   340     char *s = __load_via_object(self->value, __pos___data__).strvalue;   341     char *o = __load_via_object(other->value, __pos___data__).strvalue;   342    343     /* NOTE: Using simple byte-level string operations. */   344     return strcmp(s, o) == 0 ? __builtins___boolean_True : __builtins___boolean_False;   345 }   346    347 __attr __fn_native__str_len(__attr __args[])   348 {   349     __attr * const self = &__args[1];   350     /* self.__data__ interpreted as string */   351     char *s = __load_via_object(self->value, __pos___data__).strvalue;   352    353     /* Return the new integer. */   354     return __new_int(strlen(s));   355 }   356    357 __attr __fn_native__str_nonempty(__attr __args[])   358 {   359     __attr * const self = &__args[1];   360     /* self.__data__ interpreted as string */   361     char *s = __load_via_object(self->value, __pos___data__).strvalue;   362    363     return strlen(s) ? __builtins___boolean_True : __builtins___boolean_False;   364 }   365    366 __attr __fn_native__list_init(__attr __args[])   367 {   368     __attr * const size = &__args[1];   369     /* size.__data__ interpreted as int */   370     unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;   371     __attr attr = {0, .seqvalue=__new_fragment(n)};   372    373     /* Return the __data__ attribute. */   374     return attr;   375 }   376    377 __attr __fn_native__list_setsize(__attr __args[])   378 {   379     __attr * const self = &__args[1];   380     __attr * const size = &__args[2];   381     /* self.__data__ interpreted as list */   382     __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;   383     /* size.__data__ interpreted as int */   384     unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;   385    386     data->size = n;   387     return __builtins___none_None;   388 }   389    390 __attr __fn_native__list_append(__attr __args[])   391 {   392     __attr * const self = &__args[1];   393     __attr * const value = &__args[2];   394     /* self.__data__ interpreted as list */   395     __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;   396     __fragment *newdata = __fragment_append(data, value);   397    398     /* Replace the __data__ attribute if appropriate. */   399     if (newdata != data)   400         __store_via_object(self->value, __pos___data__, ((__attr) {0, .seqvalue=newdata}));   401     return __builtins___none_None;   402 }   403    404 __attr __fn_native__list_concat(__attr __args[])   405 {   406     __attr * const self = &__args[1];   407     __attr * const other = &__args[2];   408     /* self.__data__, other.__data__ interpreted as list */   409     __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;   410     __fragment *other_data = __load_via_object(other->value, __pos___data__).seqvalue;   411     __fragment *newdata = data;   412     unsigned int size = data->size, capacity = data->capacity;   413     unsigned int other_size = other_data->size;   414     unsigned int i, j, n;   415    416     /* Re-allocate the fragment if the capacity has been reached. */   417     if (size + other_size >= capacity)   418     {   419         n = size + other_size;   420         newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));   421         newdata->capacity = n;   422     }   423    424     /* Copy the elements from the other list and increment the list size. */   425     for (i = size, j = 0; j < other_size; i++, j++)   426         newdata->attrs[i] = other_data->attrs[j];   427     newdata->size = n;   428    429     /* Replace the __data__ attribute if appropriate. */   430     if (newdata != data)   431         __store_via_object(self->value, __pos___data__, ((__attr) {0, .seqvalue=newdata}));   432     return __builtins___none_None;   433 }   434    435 __attr __fn_native__list_len(__attr __args[])   436 {   437     __attr * const self = &__args[1];   438     /* self.__data__ interpreted as fragment */   439     unsigned int size = __load_via_object(self->value, __pos___data__).seqvalue->size;   440    441     /* Return the new integer. */   442     return __new_int(size);   443 }   444    445 __attr __fn_native__list_nonempty(__attr __args[])   446 {   447     __attr * const self = &__args[1];   448    449     return __load_via_object(self->value, __pos___data__).seqvalue->size ? __builtins___boolean_True : __builtins___boolean_False;   450 }   451    452 __attr __fn_native__list_element(__attr __args[])   453 {   454     __attr * const self = &__args[1];   455     __attr * const index = &__args[2];   456     /* self.__data__ interpreted as fragment */   457     __attr *elements = __load_via_object(self->value, __pos___data__).seqvalue->attrs;   458     /* index.__data__ interpreted as int */   459     int i = __load_via_object(index->value, __pos___data__).intvalue;   460    461     return elements[i];   462 }   463    464 __attr __fn_native__list_setelement(__attr __args[])   465 {   466     __attr * const self = &__args[1];   467     __attr * const index = &__args[2];   468     __attr * const value = &__args[3];   469     /* self.__data__ interpreted as fragment */   470     __attr *elements = __load_via_object(self->value, __pos___data__).seqvalue->attrs;   471     /* index.__data__ interpreted as int */   472     int i = __load_via_object(index->value, __pos___data__).intvalue;   473    474     /* Set the element. */   475     elements[i] = *value;   476     return __builtins___none_None;   477 }   478    479 __attr __fn_native__dict_init(__attr __args[])   480 {   481     __attr * const size = &__args[1];   482     /* size.__data__ interpreted as int */   483     unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;   484     __mapping *data = __new_mapping(n);   485     __attr attr = {0, .mapvalue=data};   486    487     /* Return the __data__ attribute. */   488     return attr;   489 }   490    491 __attr __fn_native__dict_bucketsize(__attr __args[])   492 {   493     __attr * const self = &__args[1];   494     __attr * const index = &__args[2];   495     /* self.__data__ interpreted as dict */   496     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   497     /* index.__data__ interpreted as int */   498     int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;   499    500     /* Return size of bucket k. */   501     return __new_int(data->keys[k]->size);   502 }   503    504 __attr __fn_native__dict_keys(__attr __args[])   505 {   506     __attr * const self = &__args[1];   507     /* self.__data__ interpreted as dict */   508     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   509     unsigned int k, i, j, size = 0;   510     __fragment *f;   511    512     /* Count the number of keys. */   513     for (k = 0; k < __MAPPING_BUCKETS; k++)   514         size += data->keys[k]->size;   515    516     /* Create a fragment for the keys. */   517     f =  __new_fragment(size);   518    519     /* Populate the fragment with the keys. */   520     for (j = 0, k = 0; k < __MAPPING_BUCKETS; k++)   521         for (i = 0; i < data->keys[k]->size; i++, j++)   522             f->attrs[j] = data->keys[k]->attrs[i];   523     f->size = size;   524    525     /* Return a list. */   526     return __new_list(f);   527 }   528    529 __attr __fn_native__dict_values(__attr __args[])   530 {   531     __attr * const self = &__args[1];   532     /* self.__data__ interpreted as dict */   533     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   534     unsigned int k, i, j, size = 0;   535     __fragment *f;   536    537     /* Count the number of values. */   538     for (k = 0; k < __MAPPING_BUCKETS; k++)   539         size += data->values[k]->size;   540    541     /* Create a fragment for the values. */   542     f =  __new_fragment(size);   543    544     /* Populate the fragment with the values. */   545     for (j = 0, k = 0; k < __MAPPING_BUCKETS; k++)   546         for (i = 0; i < data->values[k]->size; i++, j++)   547             f->attrs[j] = data->values[k]->attrs[i];   548     f->size = size;   549    550     /* Return a list. */   551     return __new_list(f);   552 }   553    554 __attr __fn_native__dict_key(__attr __args[])   555 {   556     __attr * const self = &__args[1];   557     __attr * const index = &__args[2];   558     __attr * const element = &__args[3];   559     /* self.__data__ interpreted as dict */   560     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   561     /* index.__data__ interpreted as int */   562     int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;   563     /* element.__data__ interpreted as int */   564     int i = __load_via_object(element->value, __pos___data__).intvalue;   565    566     /* Return key from bucket k, element i. */   567     return data->keys[k]->attrs[i];   568 }   569    570 __attr __fn_native__dict_value(__attr __args[])   571 {   572     __attr * const self = &__args[1];   573     __attr * const index = &__args[2];   574     __attr * const element = &__args[3];   575     /* self.__data__ interpreted as dict */   576     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   577     /* index.__data__ interpreted as int */   578     int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;   579     /* element.__data__ interpreted as int */   580     int i = __load_via_object(element->value, __pos___data__).intvalue;   581    582     /* Return value from bucket k, element i. */   583     return data->values[k]->attrs[i];   584 }   585    586 __attr __fn_native__dict_additem(__attr __args[])   587 {   588     __attr * const self = &__args[1];   589     __attr * const index = &__args[2];   590     __attr * const key = &__args[3];   591     __attr * const value = &__args[4];   592     /* self.__data__ interpreted as dict */   593     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   594     /* index.__data__ interpreted as int */   595     int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;   596     __fragment *keys = data->keys[k], *newkeys;   597     __fragment *values = data->values[k], *newvalues;   598    599     /* Append the item. */   600     newkeys = __fragment_append(keys, key);   601     newvalues = __fragment_append(values, value);   602    603     /* Replace the fragments if appropriate. */   604     if (newkeys != keys)   605         data->keys[k] = newkeys;   606     if (newvalues != values)   607         data->values[k] = newvalues;   608     return __builtins___none_None;   609 }   610    611 __attr __fn_native__dict_setitem(__attr __args[])   612 {   613     __attr * const self = &__args[1];   614     __attr * const index = &__args[2];   615     __attr * const element = &__args[3];   616     __attr * const key = &__args[4];   617     __attr * const value = &__args[5];   618     /* self.__data__ interpreted as dict */   619     __mapping *data = __load_via_object(self->value, __pos___data__).mapvalue;   620     /* index.__data__ interpreted as int */   621     int k = __load_via_object(index->value, __pos___data__).intvalue % __MAPPING_BUCKETS;   622     /* element.__data__ interpreted as int */   623     int i = __load_via_object(element->value, __pos___data__).intvalue;   624    625     /* Replace the item. */   626     data->keys[k]->attrs[i] = *key;   627     data->values[k]->attrs[i] = *value;   628    629     return __builtins___none_None;   630 }   631    632 __attr __fn_native__buffer_str(__attr __args[])   633 {   634     __attr * const self = &__args[1];   635     /* self.__data__ interpreted as buffer */   636     __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;   637     unsigned int size = 0, i, j, n;   638     char *s, *o;   639    640     /* Calculate the size of the string. */   641     for (i = 0; i < data->size; i++)   642         size += strlen(__load_via_object(data->attrs[i].value, __pos___data__).strvalue);   643    644     /* Reserve space for a new string. */   645     s = (char *) __ALLOCATE(size + 1, sizeof(char));   646    647     /* Build a single string from the buffer contents. */   648     for (i = 0, j = 0; i < data->size; i++)   649     {   650         o = __load_via_object(data->attrs[i].value, __pos___data__).strvalue;   651         n = strlen(o);   652         strncpy(s + j, o, n);   653         j += n;   654     }   655    656     /* Return a new string. */   657     return __new_str(s);   658 }   659    660 __attr __fn_native__get_using(__attr __args[])   661 {   662     __attr * const callable = &__args[1];   663     __attr * const instance = &__args[2];   664    665     return __replace_context(instance->value, *callable);   666 }   667    668 __attr __fn_native__object_getattr(__attr __args[])   669 {   670     __attr * const obj = &__args[1];   671     __attr * const name = &__args[2];   672     __attr * const _default = &__args[3];   673    674     /* NOTE: To be written. */   675     return __builtins___none_None;   676 }   677    678 static int __issubclass(__ref obj, __attr cls)   679 {   680     return (__HASATTR(obj, __TYPEPOS(cls.value), __TYPECODE(cls.value)));   681 }   682    683 __attr __fn_native__isinstance(__attr __args[])   684 {   685     __attr * const obj = &__args[1];   686     __attr * const cls = &__args[2];   687    688     /* cls must be a class. */   689     if (__is_instance(obj->value) && __issubclass(__get_class(obj->value), *cls))   690         return __builtins___boolean_True;   691     else   692         return __builtins___boolean_False;   693 }   694    695 __attr __fn_native__issubclass(__attr __args[])   696 {   697     __attr * const obj = &__args[1];   698     __attr * const cls = &__args[2];   699    700     /* obj and cls must be classes. */   701     if (__issubclass(obj->value, *cls))   702         return __builtins___boolean_True;   703     else   704         return __builtins___boolean_False;   705 }   706    707 __attr __fn_native__read(__attr __args[])   708 {   709     __attr * const fd = &__args[1];   710     __attr * const n = &__args[2];   711    712     /* NOTE: To be written. */   713     return __builtins___none_None;   714 }   715    716 __attr __fn_native__write(__attr __args[])   717 {   718     __attr * const fd = &__args[1];   719     __attr * const str = &__args[2];   720     /* fd.__data__ interpreted as int */   721     int i = __load_via_object(fd->value, __pos___data__).intvalue;   722     /* str.__data__ interpreted as string */   723     char *s = __load_via_object(str->value, __pos___data__).strvalue;   724    725     write(i, s, sizeof(char) * strlen(s));   726     return __builtins___none_None;   727 }   728    729 /* Module initialisation. */   730    731 void __main_native()   732 {   733 }