Lichen

templates/native.c

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