Lichen

templates/native.c

217:e5aa9e58703e
2016-11-23 Paul Boddie Automatically convert non-buffer, non-string objects to strings for appending.
     1 #include <stdlib.h> /* calloc, exit, realloc */     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 inline __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 inline __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 /* Native functions. */    33     34 __attr __fn_native__exit(__attr __args[])    35 {    36     __attr * const status = &__args[1];    37     38     exit(__load_via_object(status->value, __pos___data__).intvalue);    39     return __builtins___none_None;    40 }    41     42 __attr __fn_native__get_argv(__attr __args[])    43 {    44     __attr * const status = &__args[1];    45     46     /* NOTE: To be written. */    47     return __builtins___none_None;    48 }    49     50 __attr __fn_native__get_path(__attr __args[])    51 {    52     __attr * const status = &__args[1];    53     54     /* NOTE: To be written. */    55     return __builtins___none_None;    56 }    57     58 __attr __fn_native__is(__attr __args[])    59 {    60     __attr * const x = &__args[1];    61     __attr * const y = &__args[2];    62     63     return x->value == y->value ? __builtins___boolean_True : __builtins___boolean_False;    64 }    65     66 __attr __fn_native__is_not(__attr __args[])    67 {    68     __attr * const x = &__args[1];    69     __attr * const y = &__args[2];    70     71     return x->value != y->value ? __builtins___boolean_True : __builtins___boolean_False;    72 }    73     74 __attr __fn_native__int_add(__attr __args[])    75 {    76     __attr * const self = &__args[1];    77     __attr * const other = &__args[2];    78     /* self.__data__ and other.__data__ interpreted as int */    79     int i = __load_via_object(self->value, __pos___data__).intvalue;    80     int j = __load_via_object(other->value, __pos___data__).intvalue;    81     82     /* Return the new integer. */    83     /* NOTE: No overflow test applied. */    84     return __new_int(i + j);    85 }    86     87 __attr __fn_native__int_sub(__attr __args[])    88 {    89     __attr * const self = &__args[1];    90     __attr * const other = &__args[2];    91     /* self.__data__ and other.__data__ interpreted as int */    92     int i = __load_via_object(self->value, __pos___data__).intvalue;    93     int j = __load_via_object(other->value, __pos___data__).intvalue;    94     95     /* Return the new integer. */    96     /* NOTE: No overflow test applied. */    97     return __new_int(i - j);    98 }    99    100 __attr __fn_native__int_mul(__attr __args[])   101 {   102     __attr * const self = &__args[1];   103     __attr * const other = &__args[2];   104     /* self.__data__ and other.__data__ interpreted as int */   105     int i = __load_via_object(self->value, __pos___data__).intvalue;   106     int j = __load_via_object(other->value, __pos___data__).intvalue;   107    108     /* Return the new integer. */   109     /* NOTE: No overflow test applied. */   110     return __new_int(i * j);   111 }   112    113 __attr __fn_native__int_div(__attr __args[])   114 {   115     __attr * const self = &__args[1];   116     __attr * const other = &__args[2];   117     /* self.__data__ and other.__data__ interpreted as int */   118     int i = __load_via_object(self->value, __pos___data__).intvalue;   119     int j = __load_via_object(other->value, __pos___data__).intvalue;   120    121     /* Return the new integer. */   122     /* NOTE: No overflow test applied. */   123     return __new_int(i / j);   124 }   125    126 __attr __fn_native__int_mod(__attr __args[])   127 {   128     __attr * const self = &__args[1];   129     __attr * const other = &__args[2];   130     /* self.__data__ and other.__data__ interpreted as int */   131     int i = __load_via_object(self->value, __pos___data__).intvalue;   132     int j = __load_via_object(other->value, __pos___data__).intvalue;   133    134     /* Return the new integer. */   135     /* NOTE: No overflow test applied. */   136     return __new_int(i % j);   137 }   138    139 __attr __fn_native__int_neg(__attr __args[])   140 {   141     __attr * const self = &__args[1];   142     /* self.__data__ interpreted as int */   143     int i = __load_via_object(self->value, __pos___data__).intvalue;   144    145     /* Return the new integer. */   146     return __new_int(-i);   147 }   148    149 __attr __fn_native__int_pow(__attr __args[])   150 {   151     __attr * const self = &__args[1];   152     __attr * const other = &__args[2];   153     /* self.__data__ and other.__data__ interpreted as int */   154     int i = __load_via_object(self->value, __pos___data__).intvalue;   155     int j = __load_via_object(other->value, __pos___data__).intvalue;   156    157     /* Return the new integer. */   158     /* NOTE: No overflow test applied. */   159     return __new_int((int) pow(i, j));   160 }   161    162 __attr __fn_native__int_and(__attr __args[])   163 {   164     __attr * const self = &__args[1];   165     __attr * const other = &__args[2];   166     /* self.__data__ and other.__data__ interpreted as int */   167     int i = __load_via_object(self->value, __pos___data__).intvalue;   168     int j = __load_via_object(other->value, __pos___data__).intvalue;   169    170     /* Return the new integer. */   171     /* NOTE: No overflow test applied. */   172     return __new_int(i & j);   173 }   174    175 __attr __fn_native__int_or(__attr __args[])   176 {   177     __attr * const self = &__args[1];   178     __attr * const other = &__args[2];   179     /* self.__data__ and other.__data__ interpreted as int */   180     int i = __load_via_object(self->value, __pos___data__).intvalue;   181     int j = __load_via_object(other->value, __pos___data__).intvalue;   182    183     /* Return the new integer. */   184     /* NOTE: No overflow test applied. */   185     return __new_int(i | j);   186 }   187    188 __attr __fn_native__int_xor(__attr __args[])   189 {   190     __attr * const self = &__args[1];   191     __attr * const other = &__args[2];   192     /* self.__data__ and other.__data__ interpreted as int */   193     int i = __load_via_object(self->value, __pos___data__).intvalue;   194     int j = __load_via_object(other->value, __pos___data__).intvalue;   195    196     /* Return the new integer. */   197     /* NOTE: No overflow test applied. */   198     return __new_int(i ^ j);   199 }   200    201 __attr __fn_native__int_lt(__attr __args[])   202 {   203     __attr * const self = &__args[1];   204     __attr * const other = &__args[2];   205     /* self.__data__ and other.__data__ interpreted as int */   206     int i = __load_via_object(self->value, __pos___data__).intvalue;   207     int j = __load_via_object(other->value, __pos___data__).intvalue;   208    209     /* Return a boolean result. */   210     return i < j ? __builtins___boolean_True : __builtins___boolean_False;   211 }   212    213 __attr __fn_native__int_gt(__attr __args[])   214 {   215     __attr * const self = &__args[1];   216     __attr * const other = &__args[2];   217     /* self.__data__ and other.__data__ interpreted as int */   218     int i = __load_via_object(self->value, __pos___data__).intvalue;   219     int j = __load_via_object(other->value, __pos___data__).intvalue;   220    221     /* Return a boolean result. */   222     return i > j ? __builtins___boolean_True : __builtins___boolean_False;   223 }   224    225 __attr __fn_native__int_eq(__attr __args[])   226 {   227     __attr * const self = &__args[1];   228     __attr * const other = &__args[2];   229     /* self.__data__ and other.__data__ interpreted as int */   230     int i = __load_via_object(self->value, __pos___data__).intvalue;   231     int j = __load_via_object(other->value, __pos___data__).intvalue;   232    233     /* Return a boolean result. */   234     return i == j ? __builtins___boolean_True : __builtins___boolean_False;   235 }   236    237 __attr __fn_native__int_ne(__attr __args[])   238 {   239     __attr * const self = &__args[1];   240     __attr * const other = &__args[2];   241     /* self.__data__ and other.__data__ interpreted as int */   242     int i = __load_via_object(self->value, __pos___data__).intvalue;   243     int j = __load_via_object(other->value, __pos___data__).intvalue;   244    245     /* Return a boolean result. */   246     return i != j ? __builtins___boolean_True : __builtins___boolean_False;   247 }   248    249 __attr __fn_native__int_str(__attr __args[])   250 {   251     __attr * const self = &__args[1];   252     /* self.__data__ interpreted as int */   253     int i = __load_via_object(self->value, __pos___data__).intvalue;   254     int n = i != 0 ? (int) ceil(log10(i+1)) + 1 : 2;   255     char *s = calloc(n, sizeof(char));   256    257     if (i < 0) n++;   258     snprintf(s, n, "%d", i);   259    260     /* Return a new string. */   261     return __new_str(s);   262 }   263    264 __attr __fn_native__str_add(__attr __args[])   265 {   266     __attr * const self = &__args[1];   267     __attr * const other = &__args[2];   268     /* self.__data__, other.__data__ interpreted as string */   269     char *s = __load_via_object(self->value, __pos___data__).strvalue;   270     char *o = __load_via_object(other->value, __pos___data__).strvalue;   271     int n = strlen(s) + strlen(o) + 1;   272     char *r = calloc(n, sizeof(char));   273    274     strncpy(r, s, n);   275     strncpy(r + strlen(s), o, n - strlen(s));   276    277     /* Return a new string. */   278     return __new_str(r);   279 }   280    281 __attr __fn_native__str_lt(__attr __args[])   282 {   283     __attr * const self = &__args[1];   284     __attr * const other = &__args[2];   285     /* self.__data__, other.__data__ interpreted as string */   286     char *s = __load_via_object(self->value, __pos___data__).strvalue;   287     char *o = __load_via_object(other->value, __pos___data__).strvalue;   288    289     /* NOTE: Using simple byte-level string operations. */   290     return strcmp(s, o) < 0 ? __builtins___boolean_True : __builtins___boolean_False;   291 }   292    293 __attr __fn_native__str_gt(__attr __args[])   294 {   295     __attr * const self = &__args[1];   296     __attr * const other = &__args[2];   297     /* self.__data__, other.__data__ interpreted as string */   298     char *s = __load_via_object(self->value, __pos___data__).strvalue;   299     char *o = __load_via_object(other->value, __pos___data__).strvalue;   300    301     /* NOTE: Using simple byte-level string operations. */   302     return strcmp(s, o) > 0 ? __builtins___boolean_True : __builtins___boolean_False;   303 }   304    305 __attr __fn_native__str_eq(__attr __args[])   306 {   307     __attr * const self = &__args[1];   308     __attr * const other = &__args[2];   309     /* self.__data__, other.__data__ interpreted as string */   310     char *s = __load_via_object(self->value, __pos___data__).strvalue;   311     char *o = __load_via_object(other->value, __pos___data__).strvalue;   312    313     /* NOTE: Using simple byte-level string operations. */   314     return strcmp(s, o) == 0 ? __builtins___boolean_True : __builtins___boolean_False;   315 }   316    317 __attr __fn_native__str_len(__attr __args[])   318 {   319     __attr * const self = &__args[1];   320     /* self.__data__ interpreted as string */   321     char *s = __load_via_object(self->value, __pos___data__).strvalue;   322    323     /* Return the new integer. */   324     return __new_int(strlen(s));   325 }   326    327 __attr __fn_native__str_nonempty(__attr __args[])   328 {   329     __attr * const self = &__args[1];   330     /* self.__data__ interpreted as string */   331     char *s = __load_via_object(self->value, __pos___data__).strvalue;   332    333     return strlen(s) ? __builtins___boolean_True : __builtins___boolean_False;   334 }   335    336 __attr __fn_native__list_init(__attr __args[])   337 {   338     __attr * const size = &__args[1];   339     /* size.__data__ interpreted as int */   340     unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;   341    342     /* Allocate space for the list. */   343     __fragment *data = calloc(1, __FRAGMENT_SIZE(n));   344     __attr attr = {0, .data=data};   345    346     /* The initial capacity is the same as the given size. */   347     data->size = 0;   348     data->capacity = n;   349     return attr;   350 }   351    352 __attr __fn_native__list_append(__attr __args[])   353 {   354     __attr * const self = &__args[1];   355     __attr * const value = &__args[2];   356     /* self.__data__ interpreted as list */   357     __fragment *data = __load_via_object(self->value, __pos___data__).data;   358     __fragment *newdata = data;   359     unsigned int size = data->size, capacity = data->capacity;   360     unsigned int n;   361    362     /* Re-allocate the fragment if the capacity has been reached. */   363     if (size >= capacity)   364     {   365         /* NOTE: Consider various restrictions on capacity increases. */   366         n = capacity ? capacity * 2 : 1;   367         newdata = realloc(data, __FRAGMENT_SIZE(n));   368         newdata->capacity = n;   369     }   370    371     /* Insert the new element and increment the list size. */   372     newdata->attrs[size] = *value;   373     newdata->size = size + 1;   374    375     /* Replace the __data__ attribute if appropriate. */   376     if (newdata != data)   377         __store_via_object(self->value, __pos___data__, ((__attr) {0, .data=newdata}));   378     return __builtins___none_None;   379 }   380    381 __attr __fn_native__list_concat(__attr __args[])   382 {   383     __attr * const self = &__args[1];   384     __attr * const other = &__args[2];   385     /* self.__data__, other.__data__ interpreted as list */   386     __fragment *data = __load_via_object(self->value, __pos___data__).data;   387     __fragment *other_data = __load_via_object(other->value, __pos___data__).data;   388     __fragment *newdata = data;   389     unsigned int size = data->size, capacity = data->capacity;   390     unsigned int other_size = other_data->size;   391     unsigned int i, j, n;   392    393     /* Re-allocate the fragment if the capacity has been reached. */   394     if (size + other_size >= capacity)   395     {   396         n = size + other_size;   397         newdata = realloc(data, __FRAGMENT_SIZE(n));   398         newdata->capacity = n;   399     }   400    401     /* Copy the elements from the other list and increment the list size. */   402     for (i = size, j = 0; j < other_size; i++, j++)   403         newdata->attrs[i] = other_data->attrs[j];   404     newdata->size = n;   405    406     /* Replace the __data__ attribute if appropriate. */   407     if (newdata != data)   408         __store_via_object(self->value, __pos___data__, ((__attr) {0, .data=newdata}));   409     return __builtins___none_None;   410 }   411    412 __attr __fn_native__list_len(__attr __args[])   413 {   414     __attr * const self = &__args[1];   415     /* self.__data__ interpreted as fragment */   416     unsigned int size = __load_via_object(self->value, __pos___data__).data->size;   417    418     /* Return the new integer. */   419     return __new_int(size);   420 }   421    422 __attr __fn_native__list_nonempty(__attr __args[])   423 {   424     __attr * const self = &__args[1];   425    426     return __load_via_object(self->value, __pos___data__).data->size ? __builtins___boolean_True : __builtins___boolean_False;   427 }   428    429 __attr __fn_native__list_element(__attr __args[])   430 {   431     __attr * const self = &__args[1];   432     __attr * const index = &__args[2];   433     /* self.__data__ interpreted as fragment */   434     __attr *elements = __load_via_object(self->value, __pos___data__).data->attrs;   435     /* index.__data__ interpreted as int */   436     int i = __load_via_object(index->value, __pos___data__).intvalue;   437    438     return elements[i];   439 }   440    441 __attr __fn_native__list_to_tuple(__attr __args[])   442 {   443     __attr * const l = &__args[1];   444    445     /* NOTE: To be written. */   446     return __builtins___none_None;   447 }   448    449 __attr __fn_native__buffer_str(__attr __args[])   450 {   451     __attr * const self = &__args[1];   452     /* self.__data__ interpreted as buffer */   453     __fragment *data = __load_via_object(self->value, __pos___data__).data;   454     unsigned int size = 0, i, j, n;   455     char *s, *o;   456    457     /* Calculate the size of the string. */   458     for (i = 0; i < data->size; i++)   459         size += strlen(data->attrs[i].strvalue);   460    461     /* Reserve space for a new string. */   462     s = calloc(size + 1, sizeof(char));   463    464     /* Build a single string from the buffer contents. */   465     for (i = 0, j = 0; i < data->size; i++)   466     {   467         o = __load_via_object(data->attrs[i].value, __pos___data__).strvalue;   468         n = strlen(o);   469         strncpy(s + j, o, n);   470         j += n;   471     }   472    473     /* Return a new string. */   474     return __new_str(s);   475 }   476    477 __attr __fn_native__tuple_init(__attr __args[])   478 {   479     __attr * const size = &__args[1];   480     /* size.__data__ interpreted as fragment */   481     __fragment *data = calloc(__load_via_object(size->value, __pos___data__).intvalue, sizeof(__attr));   482     __attr attr = {0, .data=data};   483    484     return attr;   485 }   486    487 __attr __fn_native__tuple_len(__attr __args[])   488 {   489     __attr * const self = &__args[1];   490     /* self.__data__ interpreted as fragment */   491     unsigned int size = __load_via_object(self->value, __pos___data__).data->size;   492    493     /* Return the new integer. */   494     return __new_int(size);   495 }   496    497 __attr __fn_native__tuple_element(__attr __args[])   498 {   499     __attr * const self = &__args[1];   500     __attr * const index = &__args[2];   501     /* self.__data__ interpreted as fragment */   502     __attr *elements = __load_via_object(self->value, __pos___data__).data->attrs;   503     /* index.__data__ interpreted as int */   504     int i = __load_via_object(index->value, __pos___data__).intvalue;   505    506     return elements[i];   507 }   508    509 __attr __fn_native__isinstance(__attr __args[])   510 {   511     __attr * const obj = &__args[1];   512     __attr * const cls = &__args[2];   513    514     if (__is_instance(obj->value) && __HASATTR(__get_class(obj->value), __TYPEPOS(cls->value), __TYPECODE(cls->value)))   515         return __builtins___boolean_True;   516     else   517         return __builtins___boolean_False;   518 }   519    520 __attr __fn_native__read(__attr __args[])   521 {   522     __attr * const fd = &__args[1];   523     __attr * const n = &__args[2];   524    525     /* NOTE: To be written. */   526     return __builtins___none_None;   527 }   528    529 __attr __fn_native__write(__attr __args[])   530 {   531     __attr * const fd = &__args[1];   532     __attr * const str = &__args[2];   533     /* fd.__data__ interpreted as int */   534     int i = __load_via_object(fd->value, __pos___data__).intvalue;   535     /* str.__data__ interpreted as string */   536     char *s = __load_via_object(str->value, __pos___data__).strvalue;   537    538     write(i, s, sizeof(char) * strlen(s));   539     return __builtins___none_None;   540 }   541    542 /* Module initialisation. */   543    544 void __main_native()   545 {   546 }