diff options
Diffstat (limited to 'mdk-stage1/slang/slarray.c')
-rw-r--r-- | mdk-stage1/slang/slarray.c | 3139 |
1 files changed, 0 insertions, 3139 deletions
diff --git a/mdk-stage1/slang/slarray.c b/mdk-stage1/slang/slarray.c deleted file mode 100644 index 0b9a1406c..000000000 --- a/mdk-stage1/slang/slarray.c +++ /dev/null @@ -1,3139 +0,0 @@ -/* Array manipulation routines for S-Lang */ -/* Copyright (c) 1997, 1999, 2001 John E. Davis - * This file is part of the S-Lang library. - * - * You may distribute under the terms of either the GNU General Public - * License or the Perl Artistic License. - */ - -#include "slinclud.h" - -#define SL_APP_WANTS_FOREACH -#include "slang.h" -#include "_slang.h" - -typedef struct -{ - int first_index; - int last_index; - int delta; -} -SLarray_Range_Array_Type; - -/* Use SLang_pop_array when a linear array is required. */ -static int pop_array (SLang_Array_Type **at_ptr, int convert_scalar) -{ - SLang_Array_Type *at; - int one = 1; - int type; - - *at_ptr = NULL; - type = SLang_peek_at_stack (); - - switch (type) - { - case -1: - return -1; - - case SLANG_ARRAY_TYPE: - return SLclass_pop_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR *) at_ptr); - - case SLANG_NULL_TYPE: - convert_scalar = 0; - /* drop */ - default: - if (convert_scalar == 0) - { - SLdo_pop (); - SLang_verror (SL_TYPE_MISMATCH, "Context requires an array. Scalar not converted"); - return -1; - } - break; - } - - if (NULL == (at = SLang_create_array ((unsigned char) type, 0, NULL, &one, 1))) - return -1; - - if (-1 == at->cl->cl_apop ((unsigned char) type, at->data)) - { - SLang_free_array (at); - return -1; - } - - *at_ptr = at; - - return 0; -} - -static VOID_STAR linear_get_data_addr (SLang_Array_Type *at, int *dims) -{ - unsigned int num_dims; - unsigned int ofs; - unsigned int i; - int *max_dims; - - ofs = 0; - max_dims = at->dims; - num_dims = at->num_dims; - - for (i = 0; i < num_dims; i++) - { - int d = dims[i]; - - if (d < 0) - d = d + max_dims[i]; - - ofs = ofs * (unsigned int)max_dims [i] + (unsigned int) d; - } - - return (VOID_STAR) ((char *)at->data + (ofs * at->sizeof_type)); -} - -static VOID_STAR get_data_addr (SLang_Array_Type *at, int *dims) -{ - VOID_STAR data; - - data = at->data; - if (data == NULL) - { - SLang_verror (SL_UNKNOWN_ERROR, "Array has no data"); - return NULL; - } - - data = (*at->index_fun) (at, dims); - - if (data == NULL) - { - SLang_verror (SL_UNKNOWN_ERROR, "Unable to access array element"); - return NULL; - } - - return data; -} - -void _SLarray_free_array_elements (SLang_Class_Type *cl, VOID_STAR s, unsigned int num) -{ - unsigned int sizeof_type; - void (*f) (unsigned char, VOID_STAR); - char *p; - unsigned char type; - - if ((cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR) - || (cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR)) - return; - - f = cl->cl_destroy; - sizeof_type = cl->cl_sizeof_type; - type = cl->cl_data_type; - - p = (char *) s; - while (num != 0) - { - if (NULL != *(VOID_STAR *)p) - { - (*f) (type, (VOID_STAR)p); - *(VOID_STAR *) p = NULL; - } - p += sizeof_type; - num--; - } -} - -static int destroy_element (SLang_Array_Type *at, - int *dims, - VOID_STAR data) -{ - data = get_data_addr (at, dims); - if (data == NULL) - return -1; - - /* This function should only get called for arrays that have - * pointer elements. Do not call the destroy method if the element - * is NULL. - */ - if (NULL != *(VOID_STAR *)data) - { - (*at->cl->cl_destroy) (at->data_type, data); - *(VOID_STAR *) data = NULL; - } - return 0; -} - -/* This function only gets called when a new array is created. Thus there - * is no need to destroy the object first. - */ -static int new_object_element (SLang_Array_Type *at, - int *dims, - VOID_STAR data) -{ - data = get_data_addr (at, dims); - if (data == NULL) - return -1; - - return (*at->cl->cl_init_array_object) (at->data_type, data); -} - -static int next_index (int *dims, int *max_dims, unsigned int num_dims) -{ - while (num_dims) - { - int dims_i; - - num_dims--; - - dims_i = dims [num_dims] + 1; - if (dims_i != (int) max_dims [num_dims]) - { - dims [num_dims] = dims_i; - return 0; - } - dims [num_dims] = 0; - } - - return -1; -} - -static int do_method_for_all_elements (SLang_Array_Type *at, - int (*method)(SLang_Array_Type *, - int *, - VOID_STAR), - VOID_STAR client_data) -{ - int dims [SLARRAY_MAX_DIMS]; - int *max_dims; - unsigned int num_dims; - - if (at->num_elements == 0) - return 0; - - max_dims = at->dims; - num_dims = at->num_dims; - - SLMEMSET((char *)dims, 0, sizeof(dims)); - - do - { - if (-1 == (*method) (at, dims, client_data)) - return -1; - } - while (0 == next_index (dims, max_dims, num_dims)); - - return 0; -} - -void SLang_free_array (SLang_Array_Type *at) -{ - VOID_STAR data; - unsigned int flags; - - if (at == NULL) return; - - if (at->num_refs > 1) - { - at->num_refs -= 1; - return; - } - - data = at->data; - flags = at->flags; - - if (flags & SLARR_DATA_VALUE_IS_INTRINSIC) - return; /* not to be freed */ - - if (flags & SLARR_DATA_VALUE_IS_POINTER) - (void) do_method_for_all_elements (at, destroy_element, NULL); - - SLfree ((char *) data); - SLfree ((char *) at); -} - -SLang_Array_Type * -SLang_create_array1 (unsigned char type, int read_only, VOID_STAR data, - int *dims, unsigned int num_dims, int no_init) -{ - SLang_Class_Type *cl; - unsigned int i; - SLang_Array_Type *at; - unsigned int num_elements; - unsigned int sizeof_type; - unsigned int size; - - if (num_dims > SLARRAY_MAX_DIMS) - { - SLang_verror (SL_NOT_IMPLEMENTED, "%u dimensional arrays are not supported", num_dims); - return NULL; - } - - for (i = 0; i < num_dims; i++) - { - if (dims[i] < 0) - { - SLang_verror (SL_INVALID_PARM, "Size of array dim %u is less than 0", i); - return NULL; - } - } - - cl = _SLclass_get_class (type); - - at = (SLang_Array_Type *) SLmalloc (sizeof(SLang_Array_Type)); - if (at == NULL) - return NULL; - - SLMEMSET ((char*) at, 0, sizeof(SLang_Array_Type)); - - at->data_type = type; - at->cl = cl; - at->num_dims = num_dims; - at->num_refs = 1; - - if (read_only) at->flags = SLARR_DATA_VALUE_IS_READ_ONLY; - switch (cl->cl_class_type) - { - case SLANG_CLASS_TYPE_VECTOR: - case SLANG_CLASS_TYPE_SCALAR: - break; - - default: - at->flags |= SLARR_DATA_VALUE_IS_POINTER; - } - - num_elements = 1; - for (i = 0; i < num_dims; i++) - { - at->dims [i] = dims[i]; - num_elements = dims [i] * num_elements; - } - - /* Now set the rest of the unused dimensions to 1. This makes it easier - * when transposing arrays. - */ - while (i < SLARRAY_MAX_DIMS) - at->dims[i++] = 1; - - at->num_elements = num_elements; - at->index_fun = linear_get_data_addr; - at->sizeof_type = sizeof_type = cl->cl_sizeof_type; - - if (data != NULL) - { - at->data = data; - return at; - } - - size = num_elements * sizeof_type; - - if (size == 0) size = 1; - - if (NULL == (data = (VOID_STAR) SLmalloc (size))) - { - SLang_free_array (at); - return NULL; - } - - if (no_init == 0) - SLMEMSET ((char *) data, 0, size); - - at->data = data; - - if ((cl->cl_init_array_object != NULL) - && (-1 == do_method_for_all_elements (at, new_object_element, NULL))) - { - SLang_free_array (at); - return NULL; - } - return at; -} - -SLang_Array_Type * -SLang_create_array (unsigned char type, int read_only, VOID_STAR data, - int *dims, unsigned int num_dims) -{ - return SLang_create_array1 (type, read_only, data, dims, num_dims, 0); -} - -int SLang_add_intrinsic_array (char *name, - unsigned char type, - int read_only, - VOID_STAR data, - unsigned int num_dims, ...) -{ - va_list ap; - unsigned int i; - int dims[SLARRAY_MAX_DIMS]; - SLang_Array_Type *at; - - if ((num_dims > SLARRAY_MAX_DIMS) - || (name == NULL) - || (data == NULL)) - { - SLang_verror (SL_INVALID_PARM, "Unable to create intrinsic array"); - return -1; - } - - va_start (ap, num_dims); - for (i = 0; i < num_dims; i++) - dims [i] = va_arg (ap, int); - va_end (ap); - - at = SLang_create_array (type, read_only, data, dims, num_dims); - if (at == NULL) - return -1; - at->flags |= SLARR_DATA_VALUE_IS_INTRINSIC; - - /* Note: The variable that refers to the intrinsic array is regarded as - * read-only. That way, Array_Name = another_array; will fail. - */ - if (-1 == SLadd_intrinsic_variable (name, (VOID_STAR) at, SLANG_ARRAY_TYPE, 1)) - { - SLang_free_array (at); - return -1; - } - return 0; -} - -static int pop_array_indices (int *dims, unsigned int num_dims) -{ - unsigned int n; - int i; - - if (num_dims > SLARRAY_MAX_DIMS) - { - SLang_verror (SL_INVALID_PARM, "Array size not supported"); - return -1; - } - - n = num_dims; - while (n != 0) - { - n--; - if (-1 == SLang_pop_integer (&i)) - return -1; - - dims[n] = i; - } - - return 0; -} - -int SLang_push_array (SLang_Array_Type *at, int free_flag) -{ - if (at == NULL) - return SLang_push_null (); - - at->num_refs += 1; - - if (0 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR) at)) - { - if (free_flag) - SLang_free_array (at); - return 0; - } - - at->num_refs -= 1; - - if (free_flag) SLang_free_array (at); - return -1; -} - -/* This function gets called via expressions such as Double_Type[10, 20]; - */ -static int push_create_new_array (void) -{ - unsigned int num_dims; - SLang_Array_Type *at; - unsigned char type; - int dims [SLARRAY_MAX_DIMS]; - int (*anew) (unsigned char, unsigned int); - - num_dims = (SLang_Num_Function_Args - 1); - - if (-1 == _SLang_pop_datatype (&type)) - return -1; - - anew = (_SLclass_get_class (type))->cl_anew; - if (anew != NULL) - return (*anew) (type, num_dims); - - if (-1 == pop_array_indices (dims, num_dims)) - return -1; - - if (NULL == (at = SLang_create_array (type, 0, NULL, dims, num_dims))) - return -1; - - return SLang_push_array (at, 1); -} - -static int push_element_at_addr (SLang_Array_Type *at, - VOID_STAR data, int allow_null) -{ - SLang_Class_Type *cl; - - cl = at->cl; - if ((at->flags & SLARR_DATA_VALUE_IS_POINTER) - && (*(VOID_STAR *) data == NULL)) - { - if (allow_null) - return SLang_push_null (); - - SLang_verror (SL_VARIABLE_UNINITIALIZED, - "%s array has unitialized element", cl->cl_name); - return -1; - } - - return (*cl->cl_apush)(at->data_type, data); -} - -static int coerse_array_to_linear (SLang_Array_Type *at) -{ - SLarray_Range_Array_Type *range; - int *data; - int xmin, dx; - unsigned int i, imax; - - /* FIXME: Priority = low. This assumes that if an array is not linear, then - * it is a range. - */ - if (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE)) - return 0; - - range = (SLarray_Range_Array_Type *) at->data; - xmin = range->first_index; - dx = range->delta; - - imax = at->num_elements; - data = (int *) SLmalloc ((imax + 1) * sizeof (int)); - if (data == NULL) - return -1; - - for (i = 0; i < imax; i++) - { - data [i] = xmin; - xmin += dx; - } - - SLfree ((char *) range); - at->data = (VOID_STAR) data; - at->flags &= ~SLARR_DATA_VALUE_IS_RANGE; - at->index_fun = linear_get_data_addr; - return 0; -} - -static void -free_index_objects (SLang_Object_Type *index_objs, unsigned int num_indices) -{ - unsigned int i; - SLang_Object_Type *obj; - - for (i = 0; i < num_indices; i++) - { - obj = index_objs + i; - if (obj->data_type != 0) - SLang_free_object (obj); - } -} - -static int -pop_indices (SLang_Object_Type *index_objs, unsigned int num_indices, - int *is_index_array) -{ - unsigned int i; - - SLMEMSET((char *) index_objs, 0, num_indices * sizeof (SLang_Object_Type)); - - *is_index_array = 0; - - if (num_indices >= SLARRAY_MAX_DIMS) - { - SLang_verror (SL_INVALID_PARM, "too many indices for array"); - return -1; - } - - i = num_indices; - while (i != 0) - { - SLang_Object_Type *obj; - - i--; - obj = index_objs + i; - if (-1 == _SLang_pop_object_of_type (SLANG_INT_TYPE, obj, 1)) - goto return_error; - - if (obj->data_type == SLANG_ARRAY_TYPE) - { - SLang_Array_Type *at = obj->v.array_val; - - if (at->num_dims == 1) - { - if ((num_indices == 1) - && (0 == (at->flags & SLARR_DATA_VALUE_IS_RANGE))) - *is_index_array = 1; - } - else - { - SLang_verror (SL_INVALID_PARM, "expecting a 1-d index array"); - goto return_error; - } - } - } - - return 0; - - return_error: - free_index_objects (index_objs, num_indices); - return -1; -} - -/* Here ind_at is a linear 1-d array of indices */ -static int -check_index_array_ranges (SLang_Array_Type *at, SLang_Array_Type *ind_at) -{ - int *indices, *indices_max; - unsigned int num_elements; - - num_elements = at->num_elements; - indices = (int *) ind_at->data; - indices_max = indices + ind_at->num_elements; - - while (indices < indices_max) - { - unsigned int d; - - d = (unsigned int) *indices++; - if (d >= num_elements) - { - SLang_verror (SL_INVALID_PARM, - "index-array is out of range"); - return -1; - } - } - return 0; -} - -static int -transfer_n_elements (SLang_Array_Type *at, VOID_STAR dest_data, VOID_STAR src_data, - unsigned int sizeof_type, unsigned int n, int is_ptr) -{ - unsigned char data_type; - SLang_Class_Type *cl; - - if (is_ptr == 0) - { - SLMEMCPY ((char *) dest_data, (char *)src_data, n * sizeof_type); - return 0; - } - - data_type = at->data_type; - cl = at->cl; - - while (n != 0) - { - if (*(VOID_STAR *)dest_data != NULL) - { - (*cl->cl_destroy) (data_type, dest_data); - *(VOID_STAR *) dest_data = NULL; - } - - if (*(VOID_STAR *) src_data == NULL) - *(VOID_STAR *) dest_data = NULL; - else - { - if (-1 == (*cl->cl_acopy) (data_type, src_data, dest_data)) - /* No need to destroy anything */ - return -1; - } - - src_data = (VOID_STAR) ((char *)src_data + sizeof_type); - dest_data = (VOID_STAR) ((char *)dest_data + sizeof_type); - - n--; - } - - return 0; -} - -int -_SLarray_aget_transfer_elem (SLang_Array_Type *at, int *indices, - VOID_STAR new_data, unsigned int sizeof_type, int is_ptr) -{ - VOID_STAR at_data; - - /* Since 1 element is being transferred, there is not need to coerse - * the array to linear. - */ - if (NULL == (at_data = get_data_addr (at, indices))) - return -1; - - return transfer_n_elements (at, new_data, at_data, sizeof_type, 1, is_ptr); -} - -/* Here the ind_at index-array is a 1-d array of indices. This function - * creates a 1-d array of made up of values of 'at' at the locations - * specified by the indices. The result is pushed. - */ -static int -aget_from_index_array (SLang_Array_Type *at, - SLang_Array_Type *ind_at) -{ - SLang_Array_Type *new_at; - int *indices, *indices_max; - unsigned char *new_data, *src_data; - unsigned int sizeof_type; - int is_ptr; - - if (-1 == coerse_array_to_linear (at)) - return -1; - - if (-1 == coerse_array_to_linear (ind_at)) - return -1; - - if (-1 == check_index_array_ranges (at, ind_at)) - return -1; - - if (NULL == (new_at = SLang_create_array (at->data_type, 0, NULL, ind_at->dims, 1))) - return -1; - - /* Since the index array is linear, I can address it directly */ - indices = (int *) ind_at->data; - indices_max = indices + ind_at->num_elements; - - src_data = (unsigned char *) at->data; - new_data = (unsigned char *) new_at->data; - sizeof_type = new_at->sizeof_type; - is_ptr = (new_at->flags & SLARR_DATA_VALUE_IS_POINTER); - - while (indices < indices_max) - { - unsigned int offset; - - offset = sizeof_type * (unsigned int)*indices; - if (-1 == transfer_n_elements (at, (VOID_STAR) new_data, - (VOID_STAR) (src_data + offset), - sizeof_type, 1, is_ptr)) - { - SLang_free_array (new_at); - return -1; - } - - new_data += sizeof_type; - indices++; - } - - return SLang_push_array (new_at, 1); -} - -/* This is extremely ugly. It is due to the fact that the index_objects - * may contain ranges. This is a utility function for the aget/aput - * routines - */ -static int -convert_nasty_index_objs (SLang_Array_Type *at, - SLang_Object_Type *index_objs, - unsigned int num_indices, - int **index_data, - int *range_buf, int *range_delta_buf, - int *max_dims, - unsigned int *num_elements, - int *is_array, int is_dim_array[SLARRAY_MAX_DIMS]) -{ - unsigned int i, total_num_elements; - SLang_Array_Type *ind_at; - - if (num_indices != at->num_dims) - { - SLang_verror (SL_INVALID_PARM, "Array requires %u indices", at->num_dims); - return -1; - } - - *is_array = 0; - total_num_elements = 1; - for (i = 0; i < num_indices; i++) - { - int max_index, min_index; - SLang_Object_Type *obj; - int at_dims_i; - - at_dims_i = at->dims[i]; - obj = index_objs + i; - range_delta_buf [i] = 0; - - if (obj->data_type == SLANG_INT_TYPE) - { - range_buf [i] = min_index = max_index = obj->v.int_val; - max_dims [i] = 1; - index_data[i] = range_buf + i; - is_dim_array[i] = 0; - } - else - { - *is_array = 1; - is_dim_array[i] = 1; - ind_at = obj->v.array_val; - - if (ind_at->flags & SLARR_DATA_VALUE_IS_RANGE) - { - SLarray_Range_Array_Type *r; - int delta; - int first_index, last_index; - - r = (SLarray_Range_Array_Type *) ind_at->data; - - /* In an array indexing context, range arrays have different - * semantics. Consider a[[0:10]]. Clearly this means elements - * 0-10 of a. But what does a[[0:-1]] mean? By itself, - * [0:-1] is a null matrix []. But, it is useful in an - * indexing context to allow -1 to refer to the last element - * of the array. Similarly, [-3:-1] refers to the last 3 - * elements. - * - * However, [-1:-3] does not refer to any of the elements. - */ - if ((first_index = r->first_index) < 0) - { - if (at_dims_i != 0) - first_index = (at_dims_i + first_index) % at_dims_i; - } - - if ((last_index = r->last_index) < 0) - { - if (at_dims_i != 0) - last_index = (at_dims_i + last_index) % at_dims_i; - } - - delta = r->delta; - - range_delta_buf [i] = delta; - range_buf[i] = first_index; - - if (delta > 0) - { - if (first_index > last_index) - max_dims[i] = min_index = max_index = 0; - else - { - max_index = min_index = first_index; - while (max_index + delta <= last_index) - max_index += delta; - max_dims [i] = 1 + (max_index - min_index) / delta; - } - } - else - { - if (first_index < last_index) - max_dims[i] = min_index = max_index = 0; - else - { - min_index = max_index = first_index; - while (min_index + delta >= last_index) - min_index += delta; - max_dims [i] = 1 + (max_index - min_index) / (-delta); - } - } - } - else - { - int *tmp, *tmp_max; - - if (0 == (max_dims[i] = ind_at->num_elements)) - { - total_num_elements = 0; - break; - } - - tmp = (int *) ind_at->data; - tmp_max = tmp + ind_at->num_elements; - index_data [i] = tmp; - - min_index = max_index = *tmp; - while (tmp < tmp_max) - { - if (max_index > *tmp) - max_index = *tmp; - if (min_index < *tmp) - min_index = *tmp; - - tmp++; - } - } - } - - if ((at_dims_i == 0) && (max_dims[i] == 0)) - { - total_num_elements = 0; - continue; - } - - if (max_index < 0) - max_index += at_dims_i; - if (min_index < 0) - min_index += at_dims_i; - - if ((min_index < 0) || (min_index >= at_dims_i) - || (max_index < 0) || (max_index >= at_dims_i)) - { - SLang_verror (SL_INVALID_PARM, "Array index %u ([%d:%d]) out of allowed range [0->%d]", - i, min_index, max_index, at_dims_i); - return -1; - } - - total_num_elements = total_num_elements * max_dims[i]; - } - - *num_elements = total_num_elements; - return 0; -} - -/* This routine pushes a 1-d vector of values from 'at' indexed by - * the objects 'index_objs'. These objects can either be integers or - * 1-d integer arrays. The fact that the 1-d arrays can be ranges - * makes this look ugly. - */ -static int -aget_from_indices (SLang_Array_Type *at, - SLang_Object_Type *index_objs, unsigned int num_indices) -{ - int *index_data [SLARRAY_MAX_DIMS]; - int range_buf [SLARRAY_MAX_DIMS]; - int range_delta_buf [SLARRAY_MAX_DIMS]; - int max_dims [SLARRAY_MAX_DIMS]; - unsigned int i, num_elements; - SLang_Array_Type *new_at; - int map_indices[SLARRAY_MAX_DIMS]; - int indices [SLARRAY_MAX_DIMS]; - unsigned int sizeof_type; - int is_ptr, ret, is_array; - char *new_data; - SLang_Class_Type *cl; - int is_dim_array[SLARRAY_MAX_DIMS]; - - if (-1 == convert_nasty_index_objs (at, index_objs, num_indices, - index_data, range_buf, range_delta_buf, - max_dims, &num_elements, &is_array, - is_dim_array)) - return -1; - - is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER); - sizeof_type = at->sizeof_type; - - cl = _SLclass_get_class (at->data_type); - - if ((is_array == 0) && (num_elements == 1)) - { - new_data = (char *)cl->cl_transfer_buf; - memset (new_data, 0, sizeof_type); - new_at = NULL; - } - else - { - int i_num_elements = (int)num_elements; - - new_at = SLang_create_array (at->data_type, 0, NULL, &i_num_elements, 1); - if (NULL == new_at) - return -1; - if (num_elements == 0) - return SLang_push_array (new_at, 1); - - new_data = (char *)new_at->data; - } - - SLMEMSET((char *) map_indices, 0, sizeof(map_indices)); - do - { - for (i = 0; i < num_indices; i++) - { - int j; - - j = map_indices[i]; - - if (0 != range_delta_buf[i]) - indices[i] = range_buf[i] + j * range_delta_buf[i]; - else - indices[i] = index_data [i][j]; - } - - if (-1 == _SLarray_aget_transfer_elem (at, indices, (VOID_STAR)new_data, sizeof_type, is_ptr)) - { - SLang_free_array (new_at); - return -1; - } - new_data += sizeof_type; - } - while (0 == next_index (map_indices, max_dims, num_indices)); - - if (new_at != NULL) - { - int num_dims = 0; - /* Fixup dimensions on array */ - for (i = 0; i < num_indices; i++) - { - if (is_dim_array[i]) /* was: (max_dims[i] > 1) */ - { - new_at->dims[num_dims] = max_dims[i]; - num_dims++; - } - } - - if (num_dims != 0) new_at->num_dims = num_dims; - return SLang_push_array (new_at, 1); - } - - /* Here new_data is a whole new copy, so free it after the push */ - new_data -= sizeof_type; - if (is_ptr && (*(VOID_STAR *)new_data == NULL)) - ret = SLang_push_null (); - else - { - ret = (*cl->cl_apush) (at->data_type, (VOID_STAR)new_data); - (*cl->cl_adestroy) (at->data_type, (VOID_STAR)new_data); - } - - return ret; -} - -static int push_string_as_array (unsigned char *s, unsigned int len) -{ - int ilen; - SLang_Array_Type *at; - - ilen = (int) len; - - at = SLang_create_array (SLANG_UCHAR_TYPE, 0, NULL, &ilen, 1); - if (at == NULL) - return -1; - - memcpy ((char *)at->data, (char *)s, len); - return SLang_push_array (at, 1); -} - -static int pop_array_as_string (char **sp) -{ - SLang_Array_Type *at; - int ret; - - *sp = NULL; - - if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE)) - return -1; - - ret = 0; - - if (NULL == (*sp = SLang_create_nslstring ((char *) at->data, at->num_elements))) - ret = -1; - - SLang_free_array (at); - return ret; -} - -static int pop_array_as_bstring (SLang_BString_Type **bs) -{ - SLang_Array_Type *at; - int ret; - - *bs = NULL; - - if (-1 == SLang_pop_array_of_type (&at, SLANG_UCHAR_TYPE)) - return -1; - - ret = 0; - - if (NULL == (*bs = SLbstring_create ((unsigned char *) at->data, at->num_elements))) - ret = -1; - - SLang_free_array (at); - return ret; -} - -static int aget_from_array (unsigned int num_indices) -{ - SLang_Array_Type *at; - SLang_Object_Type index_objs [SLARRAY_MAX_DIMS]; - int ret; - int is_index_array; - unsigned int i; - - if (num_indices > SLARRAY_MAX_DIMS) - { - SLang_verror (SL_INVALID_PARM, "Number of dims must be less than %d", SLARRAY_MAX_DIMS); - return -1; - } - - if (-1 == pop_array (&at, 1)) - return -1; - - if (-1 == pop_indices (index_objs, num_indices, &is_index_array)) - { - SLang_free_array (at); - return -1; - } - - if (is_index_array == 0) - ret = aget_from_indices (at, index_objs, num_indices); - else - ret = aget_from_index_array (at, index_objs[0].v.array_val); - - SLang_free_array (at); - for (i = 0; i < num_indices; i++) - SLang_free_object (index_objs + i); - - return ret; -} - -static int push_string_element (unsigned char type, unsigned char *s, unsigned int len) -{ - int i; - - if (SLang_peek_at_stack () == SLANG_ARRAY_TYPE) - { - char *str; - - /* The indices are array values. So, do this: */ - if (-1 == push_string_as_array (s, len)) - return -1; - - if (-1 == aget_from_array (1)) - return -1; - - if (type == SLANG_BSTRING_TYPE) - { - SLang_BString_Type *bs; - int ret; - - if (-1 == pop_array_as_bstring (&bs)) - return -1; - - ret = SLang_push_bstring (bs); - SLbstring_free (bs); - return ret; - } - - if (-1 == pop_array_as_string (&str)) - return -1; - return _SLang_push_slstring (str); /* frees s upon error */ - } - - if (-1 == SLang_pop_integer (&i)) - return -1; - - if (i < 0) i = i + (int)len; - if ((unsigned int) i > len) - i = len; /* get \0 character --- bstrings include it as well */ - - i = s[(unsigned int) i]; - - return SLang_push_integer (i); -} - -/* ARRAY[i, j, k] generates code: __args i j ...k ARRAY __aput/__aget - * Here i, j, ... k may be a mixture of integers and 1-d arrays, or - * a single 2-d array of indices. The 2-d index array is generated by the - * 'where' function. - * - * If ARRAY is of type DataType, then this function will create an array of - * the appropriate type. In that case, the indices i, j, ..., k must be - * integers. - */ -int _SLarray_aget (void) -{ - unsigned int num_indices; - int type; - int (*aget_fun) (unsigned char, unsigned int); - - num_indices = (SLang_Num_Function_Args - 1); - - type = SLang_peek_at_stack (); - switch (type) - { - case -1: - return -1; /* stack underflow */ - - case SLANG_DATATYPE_TYPE: - return push_create_new_array (); - - case SLANG_BSTRING_TYPE: - if (1 == num_indices) - { - SLang_BString_Type *bs; - int ret; - unsigned int len; - unsigned char *s; - - if (-1 == SLang_pop_bstring (&bs)) - return -1; - - if (NULL == (s = SLbstring_get_pointer (bs, &len))) - ret = -1; - else - ret = push_string_element (type, s, len); - - SLbstring_free (bs); - return ret; - } - break; - - case SLANG_STRING_TYPE: - if (1 == num_indices) - { - char *s; - int ret; - - if (-1 == SLang_pop_slstring (&s)) - return -1; - - ret = push_string_element (type, (unsigned char *)s, strlen (s)); - SLang_free_slstring (s); - return ret; - } - break; - - case SLANG_ARRAY_TYPE: - break; - - default: - aget_fun = _SLclass_get_class (type)->cl_aget; - if (NULL != aget_fun) - return (*aget_fun) (type, num_indices); - } - - return aget_from_array (num_indices); -} - -int -_SLarray_aput_transfer_elem (SLang_Array_Type *at, int *indices, - VOID_STAR data_to_put, unsigned int sizeof_type, int is_ptr) -{ - VOID_STAR at_data; - - /* Since 1 element is being transferred, there is no need to coerse - * the array to linear. - */ - if (NULL == (at_data = get_data_addr (at, indices))) - return -1; - - return transfer_n_elements (at, at_data, data_to_put, sizeof_type, 1, is_ptr); -} - -static int -aput_get_array_to_put (SLang_Class_Type *cl, unsigned int num_elements, int allow_array, - SLang_Array_Type **at_ptr, char **data_to_put, unsigned int *data_increment) -{ - unsigned char data_type; - SLang_Array_Type *at; - - *at_ptr = NULL; - - data_type = cl->cl_data_type; - if (-1 == SLclass_typecast (data_type, 1, allow_array)) - return -1; - - if ((data_type != SLANG_ARRAY_TYPE) - && (data_type != SLANG_ANY_TYPE) - && (SLANG_ARRAY_TYPE == SLang_peek_at_stack ())) - { - if (-1 == SLang_pop_array (&at, 0)) - return -1; - - if ((at->num_elements != num_elements) -#if 0 - || (at->num_dims != 1) -#endif - ) - { - SLang_verror (SL_TYPE_MISMATCH, "Array size is inappropriate for use with index-array"); - SLang_free_array (at); - return -1; - } - - *data_to_put = (char *) at->data; - *data_increment = at->sizeof_type; - *at_ptr = at; - return 0; - } - - *data_increment = 0; - *data_to_put = (char *) cl->cl_transfer_buf; - - if (-1 == (*cl->cl_apop)(data_type, (VOID_STAR) *data_to_put)) - return -1; - - return 0; -} - -static int -aput_from_indices (SLang_Array_Type *at, - SLang_Object_Type *index_objs, unsigned int num_indices) -{ - int *index_data [SLARRAY_MAX_DIMS]; - int range_buf [SLARRAY_MAX_DIMS]; - int range_delta_buf [SLARRAY_MAX_DIMS]; - int max_dims [SLARRAY_MAX_DIMS]; - unsigned int i, num_elements; - SLang_Array_Type *bt; - int map_indices[SLARRAY_MAX_DIMS]; - int indices [SLARRAY_MAX_DIMS]; - unsigned int sizeof_type; - int is_ptr, is_array, ret; - char *data_to_put; - unsigned int data_increment; - SLang_Class_Type *cl; - int is_dim_array [SLARRAY_MAX_DIMS]; - - if (-1 == convert_nasty_index_objs (at, index_objs, num_indices, - index_data, range_buf, range_delta_buf, - max_dims, &num_elements, &is_array, - is_dim_array)) - return -1; - - cl = at->cl; - - if (-1 == aput_get_array_to_put (cl, num_elements, is_array, - &bt, &data_to_put, &data_increment)) - return -1; - - sizeof_type = at->sizeof_type; - is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER); - - ret = -1; - - SLMEMSET((char *) map_indices, 0, sizeof(map_indices)); - if (num_elements) do - { - for (i = 0; i < num_indices; i++) - { - int j; - - j = map_indices[i]; - - if (0 != range_delta_buf[i]) - indices[i] = range_buf[i] + j * range_delta_buf[i]; - else - indices[i] = index_data [i][j]; - } - - if (-1 == _SLarray_aput_transfer_elem (at, indices, (VOID_STAR)data_to_put, sizeof_type, is_ptr)) - goto return_error; - - data_to_put += data_increment; - } - while (0 == next_index (map_indices, max_dims, num_indices)); - - ret = 0; - - /* drop */ - - return_error: - if (bt == NULL) - { - if (is_ptr) - (*cl->cl_destroy) (cl->cl_data_type, (VOID_STAR) data_to_put); - } - else SLang_free_array (bt); - - return ret; -} - -static int -aput_from_index_array (SLang_Array_Type *at, SLang_Array_Type *ind_at) -{ - int *indices, *indices_max; - unsigned int sizeof_type; - char *data_to_put, *dest_data; - unsigned int data_increment; - int is_ptr; - SLang_Array_Type *bt; - SLang_Class_Type *cl; - int ret; - - if (-1 == coerse_array_to_linear (at)) - return -1; - - if (-1 == coerse_array_to_linear (ind_at)) - return -1; - - if (-1 == check_index_array_ranges (at, ind_at)) - return -1; - - sizeof_type = at->sizeof_type; - - cl = at->cl; - - /* Note that if bt is returned as non NULL, then the array is a linear - * one. - */ - if (-1 == aput_get_array_to_put (cl, ind_at->num_elements, 1, - &bt, &data_to_put, &data_increment)) - return -1; - - /* Since the index array is linear, I can address it directly */ - indices = (int *) ind_at->data; - indices_max = indices + ind_at->num_elements; - - is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER); - dest_data = (char *) at->data; - - ret = -1; - while (indices < indices_max) - { - unsigned int offset; - - offset = sizeof_type * (unsigned int)*indices; - - if (-1 == transfer_n_elements (at, (VOID_STAR) (dest_data + offset), - (VOID_STAR) data_to_put, sizeof_type, 1, - is_ptr)) - goto return_error; - - indices++; - data_to_put += data_increment; - } - - ret = 0; - /* Drop */ - - return_error: - - if (bt == NULL) - { - if (is_ptr) - (*cl->cl_destroy) (cl->cl_data_type, (VOID_STAR)data_to_put); - } - else SLang_free_array (bt); - - return ret; -} - -/* ARRAY[i, j, k] = generates code: __args i j k ARRAY __aput - */ -int _SLarray_aput (void) -{ - unsigned int num_indices; - SLang_Array_Type *at; - SLang_Object_Type index_objs [SLARRAY_MAX_DIMS]; - int ret; - int is_index_array; - int (*aput_fun) (unsigned char, unsigned int); - int type; - - ret = -1; - num_indices = (SLang_Num_Function_Args - 1); - - type = SLang_peek_at_stack (); - switch (type) - { - case -1: - return -1; - - case SLANG_ARRAY_TYPE: - break; - - default: - if (NULL != (aput_fun = _SLclass_get_class (type)->cl_aput)) - return (*aput_fun) (type, num_indices); - break; - } - - if (-1 == SLang_pop_array (&at, 0)) - return -1; - - if (at->flags & SLARR_DATA_VALUE_IS_READ_ONLY) - { - SLang_verror (SL_READONLY_ERROR, "%s Array is read-only", - SLclass_get_datatype_name (at->data_type)); - SLang_free_array (at); - return -1; - } - - if (-1 == pop_indices (index_objs, num_indices, &is_index_array)) - { - SLang_free_array (at); - return -1; - } - - if (is_index_array == 0) - ret = aput_from_indices (at, index_objs, num_indices); - else - ret = aput_from_index_array (at, index_objs[0].v.array_val); - - SLang_free_array (at); - free_index_objects (index_objs, num_indices); - return ret; -} - -/* This is for 1-d matrices only. It is used by the sort function */ -static int push_element_at_index (SLang_Array_Type *at, int indx) -{ - VOID_STAR data; - - if (NULL == (data = get_data_addr (at, &indx))) - return -1; - - return push_element_at_addr (at, (VOID_STAR) data, 1); -} - -static SLang_Name_Type *Sort_Function; -static SLang_Array_Type *Sort_Array; - -static int sort_cmp_fun (int *a, int *b) -{ - int cmp; - - if (SLang_Error - || (-1 == push_element_at_index (Sort_Array, *a)) - || (-1 == push_element_at_index (Sort_Array, *b)) - || (-1 == SLexecute_function (Sort_Function)) - || (-1 == SLang_pop_integer (&cmp))) - { - /* DO not allow qsort to loop forever. Return something meaningful */ - if (*a > *b) return 1; - if (*a < *b) return -1; - return 0; - } - - return cmp; -} - -static int builtin_sort_cmp_fun (int *a, int *b) -{ - VOID_STAR a_data; - VOID_STAR b_data; - SLang_Class_Type *cl; - - cl = Sort_Array->cl; - - if ((SLang_Error == 0) - && (NULL != (a_data = get_data_addr (Sort_Array, a))) - && (NULL != (b_data = get_data_addr (Sort_Array, b)))) - { - int cmp; - - if ((Sort_Array->flags & SLARR_DATA_VALUE_IS_POINTER) - && ((*(VOID_STAR *) a_data == NULL) || (*(VOID_STAR *) a_data == NULL))) - { - SLang_verror (SL_VARIABLE_UNINITIALIZED, - "%s array has unitialized element", cl->cl_name); - } - else if (0 == (*cl->cl_cmp)(Sort_Array->data_type, a_data, b_data, &cmp)) - return cmp; - } - - - if (*a > *b) return 1; - if (*a == *b) return 0; - return -1; -} - -static void sort_array_internal (SLang_Array_Type *at_str, - SLang_Name_Type *entry, - int (*sort_fun)(int *, int *)) -{ - SLang_Array_Type *ind_at; - /* This is a silly hack to make up for braindead compilers and the lack of - * uniformity in prototypes for qsort. - */ - void (*qsort_fun) (char *, unsigned int, int, int (*)(int *, int *)); - int *indx; - int i, n; - int dims[1]; - - if (Sort_Array != NULL) - { - SLang_verror (SL_NOT_IMPLEMENTED, "array_sort is not recursive"); - return; - } - - n = at_str->num_elements; - - if (at_str->num_dims != 1) - { - SLang_verror (SL_INVALID_PARM, "sort is restricted to 1 dim arrays"); - return; - } - - dims [0] = n; - - if (NULL == (ind_at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, dims, 1))) - return; - - indx = (int *) ind_at->data; - for (i = 0; i < n; i++) indx[i] = i; - - if (n > 1) - { - qsort_fun = (void (*)(char *, unsigned int, int, int (*)(int *, - int *))) - qsort; - - Sort_Array = at_str; - Sort_Function = entry; - (*qsort_fun) ((char *) indx, n, sizeof (int), sort_fun); - } - - Sort_Array = NULL; - (void) SLang_push_array (ind_at, 1); -} - -static void sort_array (void) -{ - SLang_Name_Type *entry; - SLang_Array_Type *at; - int (*sort_fun) (int *, int *); - - if (SLang_Num_Function_Args != 1) - { - sort_fun = sort_cmp_fun; - - if (NULL == (entry = SLang_pop_function ())) - return; - - if (-1 == SLang_pop_array (&at, 1)) - return; - } - else - { - sort_fun = builtin_sort_cmp_fun; - if (-1 == SLang_pop_array (&at, 1)) - return; - if (at->cl->cl_cmp == NULL) - { - SLang_verror (SL_NOT_IMPLEMENTED, - "%s does not have a predefined sorting method", - at->cl->cl_name); - SLang_free_array (at); - return; - } - entry = NULL; - } - - sort_array_internal (at, entry, sort_fun); - SLang_free_array (at); - SLang_free_function (entry); -} - -static void bstring_to_array (SLang_BString_Type *bs) -{ - unsigned char *s; - unsigned int len; - - if (NULL == (s = SLbstring_get_pointer (bs, &len))) - (void) SLang_push_null (); - else - (void) push_string_as_array (s, len); -} - -static void array_to_bstring (SLang_Array_Type *at) -{ - unsigned int nbytes; - SLang_BString_Type *bs; - - nbytes = at->num_elements * at->sizeof_type; - bs = SLbstring_create ((unsigned char *)at->data, nbytes); - (void) SLang_push_bstring (bs); - SLbstring_free (bs); -} - -static void init_char_array (void) -{ - SLang_Array_Type *at; - char *s; - unsigned int n, ndim; - - if (SLang_pop_slstring (&s)) return; - - if (-1 == SLang_pop_array (&at, 0)) - goto free_and_return; - - if (at->data_type != SLANG_CHAR_TYPE) - { - SLang_doerror("Operation requires character array"); - goto free_and_return; - } - - n = strlen (s); - ndim = at->num_elements; - if (n > ndim) - { - SLang_doerror("String too big to init array"); - goto free_and_return; - } - - strncpy((char *) at->data, s, ndim); - /* drop */ - - free_and_return: - SLang_free_array (at); - SLang_free_slstring (s); -} - -static void array_info (void) -{ - SLang_Array_Type *at, *bt; - int num_dims; - - if (-1 == pop_array (&at, 1)) - return; - - num_dims = (int)at->num_dims; - - if (NULL != (bt = SLang_create_array (SLANG_INT_TYPE, 0, NULL, &num_dims, 1))) - { - int *bdata; - int i; - int *a_dims; - - a_dims = at->dims; - bdata = (int *) bt->data; - for (i = 0; i < num_dims; i++) bdata [i] = a_dims [i]; - - if (0 == SLang_push_array (bt, 1)) - { - (void) SLang_push_integer ((int) at->num_dims); - (void) _SLang_push_datatype (at->data_type); - } - } - - SLang_free_array (at); -} - -static VOID_STAR range_get_data_addr (SLang_Array_Type *at, int *dims) -{ - static int value; - SLarray_Range_Array_Type *r; - int d; - - d = *dims; - r = (SLarray_Range_Array_Type *)at->data; - - if (d < 0) - d += at->dims[0]; - - value = r->first_index + d * r->delta; - return (VOID_STAR) &value; -} - -static SLang_Array_Type *inline_implicit_int_array (int *xminptr, int *xmaxptr, int *dxptr) -{ - int delta; - SLang_Array_Type *at; - int dims, idims; - SLarray_Range_Array_Type *data; - - if (dxptr == NULL) delta = 1; - else delta = *dxptr; - - if (delta == 0) - { - SLang_verror (SL_INVALID_PARM, "range-array increment must be non-zero"); - return NULL; - } - - data = (SLarray_Range_Array_Type *) SLmalloc (sizeof (SLarray_Range_Array_Type)); - if (data == NULL) - return NULL; - - SLMEMSET((char *) data, 0, sizeof (SLarray_Range_Array_Type)); - data->delta = delta; - dims = 0; - - if (xminptr != NULL) - data->first_index = *xminptr; - else - data->first_index = 0; - - if (xmaxptr != NULL) - data->last_index = *xmaxptr; - else - data->last_index = -1; - -/* if ((xminptr != NULL) && (xmaxptr != NULL)) - { */ - idims = 1 + (data->last_index - data->first_index) / delta; - if (idims > 0) - dims = idims; - /* } */ - - if (NULL == (at = SLang_create_array (SLANG_INT_TYPE, 0, (VOID_STAR) data, &dims, 1))) - return NULL; - - at->index_fun = range_get_data_addr; - at->flags |= SLARR_DATA_VALUE_IS_RANGE; - - return at; -} - -#if SLANG_HAS_FLOAT -static SLang_Array_Type *inline_implicit_floating_array (unsigned char type, - double *xminptr, double *xmaxptr, double *dxptr) -{ - int n, i; - SLang_Array_Type *at; - int dims; - double xmin, xmax, dx; - - if ((xminptr == NULL) || (xmaxptr == NULL)) - { - SLang_verror (SL_INVALID_PARM, "range-array has unknown size"); - return NULL; - } - xmin = *xminptr; - xmax = *xmaxptr; - if (dxptr == NULL) dx = 1.0; - else dx = *dxptr; - - if (dx == 0.0) - { - SLang_doerror ("range-array increment must be non-zero"); - return NULL; - } - - /* I have convinced myself that it is better to use semi-open intervals - * because of less ambiguities. So, [a:b:c] will represent the set of - * values a, a + c, a + 2c ... a + nc - * such that a + nc < b. That is, b lies outside the interval. - */ - - /* Allow for roundoff by adding 0.5 before truncation */ - n = (int)(1.5 + ((xmax - xmin) / dx)); - if (n <= 0) - n = 0; - else - { - double last = xmin + (n-1) * dx; - - if (dx > 0.0) - { - if (last >= xmax) - n -= 1; - } - else if (last <= xmax) - n -= 1; - } - - dims = n; - if (NULL == (at = SLang_create_array1 (type, 0, NULL, &dims, 1, 1))) - return NULL; - - if (type == SLANG_DOUBLE_TYPE) - { - double *ptr; - - ptr = (double *) at->data; - - for (i = 0; i < n; i++) - ptr[i] = xmin + i * dx; - } - else - { - float *ptr; - - ptr = (float *) at->data; - - for (i = 0; i < n; i++) - ptr[i] = (float) (xmin + i * dx); - } - return at; -} -#endif - -/* FIXME: Priority=medium - * This needs to be updated to work with all integer types. - */ -int _SLarray_inline_implicit_array (void) -{ - int int_vals[3]; -#if SLANG_HAS_FLOAT - double double_vals[3]; -#endif - int has_vals[3]; - unsigned int i, count; - SLang_Array_Type *at; - int precedence; - unsigned char type; - int is_int; - - count = SLang_Num_Function_Args; - - if (count == 2) - has_vals [2] = 0; - else if (count != 3) - { - SLang_doerror ("wrong number of arguments to __implicit_inline_array"); - return -1; - } - -#if SLANG_HAS_FLOAT - is_int = 1; -#endif - - type = 0; - precedence = 0; - - i = count; - while (i--) - { - int this_type, this_precedence; - - if (-1 == (this_type = SLang_peek_at_stack ())) - return -1; - - this_precedence = _SLarith_get_precedence ((unsigned char) this_type); - if (precedence < this_precedence) - { - type = (unsigned char) this_type; - precedence = this_precedence; - } - - has_vals [i] = 1; - - switch (this_type) - { - case SLANG_NULL_TYPE: - has_vals[i] = 0; - (void) SLdo_pop (); - break; - -#if SLANG_HAS_FLOAT - case SLANG_DOUBLE_TYPE: - case SLANG_FLOAT_TYPE: - if (-1 == SLang_pop_double (double_vals + i, NULL, NULL)) - return -1; - is_int = 0; - break; -#endif - default: - if (-1 == SLang_pop_integer (int_vals + i)) - return -1; - double_vals[i] = (double) int_vals[i]; - } - } - -#if SLANG_HAS_FLOAT - if (is_int == 0) - at = inline_implicit_floating_array (type, - (has_vals[0] ? &double_vals[0] : NULL), - (has_vals[1] ? &double_vals[1] : NULL), - (has_vals[2] ? &double_vals[2] : NULL)); - else -#endif - at = inline_implicit_int_array ((has_vals[0] ? &int_vals[0] : NULL), - (has_vals[1] ? &int_vals[1] : NULL), - (has_vals[2] ? &int_vals[2] : NULL)); - - if (at == NULL) - return -1; - - return SLang_push_array (at, 1); -} - -int _SLarray_wildcard_array (void) -{ - SLang_Array_Type *at; - - if (NULL == (at = inline_implicit_int_array (NULL, NULL, NULL))) - return -1; - - return SLang_push_array (at, 1); -} - -static SLang_Array_Type *concat_arrays (unsigned int count) -{ - SLang_Array_Type **arrays; - SLang_Array_Type *at, *bt; - unsigned int i; - int num_elements; - unsigned char type; - char *src_data, *dest_data; - int is_ptr; - unsigned int sizeof_type; - int max_dims, min_dims, max_rows, min_rows; - - arrays = (SLang_Array_Type **)SLmalloc (count * sizeof (SLang_Array_Type *)); - if (arrays == NULL) - { - SLdo_pop_n (count); - return NULL; - } - SLMEMSET((char *) arrays, 0, count * sizeof(SLang_Array_Type *)); - - at = NULL; - - num_elements = 0; - i = count; - - while (i != 0) - { - i--; - - if (-1 == SLang_pop_array (&bt, 1)) - goto free_and_return; - - arrays[i] = bt; - num_elements += (int)bt->num_elements; - } - - type = arrays[0]->data_type; - max_dims = min_dims = arrays[0]->num_dims; - min_rows = max_rows = arrays[0]->dims[0]; - - for (i = 1; i < count; i++) - { - SLang_Array_Type *ct; - int num; - - bt = arrays[i]; - - num = bt->num_dims; - if (num > max_dims) max_dims = num; - if (num < min_dims) min_dims = num; - - num = bt->dims[0]; - if (num > max_rows) max_rows = num; - if (num < min_rows) min_rows = num; - - if (type == bt->data_type) - continue; - - if (1 != _SLarray_typecast (bt->data_type, (VOID_STAR) &bt, 1, - type, (VOID_STAR) &ct, 1)) - goto free_and_return; - - SLang_free_array (bt); - arrays [i] = ct; - } - - if (NULL == (at = SLang_create_array (type, 0, NULL, &num_elements, 1))) - goto free_and_return; - - is_ptr = (at->flags & SLARR_DATA_VALUE_IS_POINTER); - sizeof_type = at->sizeof_type; - dest_data = (char *) at->data; - - for (i = 0; i < count; i++) - { - bt = arrays[i]; - - src_data = (char *) bt->data; - num_elements = bt->num_elements; - - if (-1 == transfer_n_elements (bt, (VOID_STAR)dest_data, (VOID_STAR)src_data, sizeof_type, - num_elements, is_ptr)) - { - SLang_free_array (at); - at = NULL; - goto free_and_return; - } - - dest_data += num_elements * sizeof_type; - } - - /* If the arrays are all 1-d, and all the same size, then reshape to a - * 2-d array. This will allow us to do, e.g. - * a = [[1,2], [3,4]] - * to specifiy a 2-d. - * Someday I will generalize this. - */ - if ((max_dims == min_dims) && (max_dims == 1) && (min_rows == max_rows)) - { - at->num_dims = 2; - at->dims[0] = count; - at->dims[1] = min_rows; - } - - free_and_return: - - for (i = 0; i < count; i++) - SLang_free_array (arrays[i]); - SLfree ((char *) arrays); - - return at; -} - -int _SLarray_inline_array (void) -{ - SLang_Object_Type *obj; - unsigned char type, this_type; - unsigned int count; - SLang_Array_Type *at; - - obj = _SLStack_Pointer; - - count = SLang_Num_Function_Args; - type = 0; - - while ((count > 0) && (--obj >= _SLRun_Stack)) - { - this_type = obj->data_type; - - if (type == 0) - type = this_type; - - if ((type == this_type) || (type == SLANG_ARRAY_TYPE)) - { - count--; - continue; - } - - switch (this_type) - { - case SLANG_ARRAY_TYPE: - type = SLANG_ARRAY_TYPE; - break; - - case SLANG_INT_TYPE: - switch (type) - { -#if SLANG_HAS_FLOAT - case SLANG_DOUBLE_TYPE: - break; -#endif -#if SLANG_HAS_COMPLEX - case SLANG_COMPLEX_TYPE: - break; -#endif - default: - goto type_mismatch; - } - break; -#if SLANG_HAS_FLOAT - case SLANG_DOUBLE_TYPE: - switch (type) - { - case SLANG_INT_TYPE: - type = SLANG_DOUBLE_TYPE; - break; -# if SLANG_HAS_COMPLEX - case SLANG_COMPLEX_TYPE: - break; -# endif - default: - goto type_mismatch; - } - break; -#endif -#if SLANG_HAS_COMPLEX - case SLANG_COMPLEX_TYPE: - switch (type) - { - case SLANG_INT_TYPE: - case SLANG_DOUBLE_TYPE: - type = SLANG_COMPLEX_TYPE; - break; - - default: - goto type_mismatch; - } - break; -#endif - default: - type_mismatch: - _SLclass_type_mismatch_error (type, this_type); - return -1; - } - count--; - } - - if (count != 0) - { - SLang_Error = SL_STACK_UNDERFLOW; - return -1; - } - - count = SLang_Num_Function_Args; - - if (count == 0) - { - SLang_verror (SL_NOT_IMPLEMENTED, "Empty inline-arrays not supported"); - return -1; - } - - if (type == SLANG_ARRAY_TYPE) - { - if (NULL == (at = concat_arrays (count))) - return -1; - } - else - { - SLang_Object_Type index_obj; - int icount = (int) count; - - if (NULL == (at = SLang_create_array (type, 0, NULL, &icount, 1))) - return -1; - - index_obj.data_type = SLANG_INT_TYPE; - while (count != 0) - { - count--; - index_obj.v.int_val = (int) count; - if (-1 == aput_from_indices (at, &index_obj, 1)) - { - SLang_free_array (at); - SLdo_pop_n (count); - return -1; - } - } - } - - return SLang_push_array (at, 1); -} - -static int array_binary_op_result (int op, unsigned char a, unsigned char b, - unsigned char *c) -{ - (void) op; - (void) a; - (void) b; - *c = SLANG_ARRAY_TYPE; - return 1; -} - -static int array_binary_op (int op, - unsigned char a_type, VOID_STAR ap, unsigned int na, - unsigned char b_type, VOID_STAR bp, unsigned int nb, - VOID_STAR cp) -{ - SLang_Array_Type *at, *bt, *ct; - unsigned int i, num_dims; - int (*binary_fun) (int, - unsigned char, VOID_STAR, unsigned int, - unsigned char, VOID_STAR, unsigned int, - VOID_STAR); - SLang_Class_Type *a_cl, *b_cl, *c_cl; - int no_init; - - if (a_type == SLANG_ARRAY_TYPE) - { - if (na != 1) - { - SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented"); - return -1; - } - - at = *(SLang_Array_Type **) ap; - if (-1 == coerse_array_to_linear (at)) - return -1; - ap = at->data; - a_type = at->data_type; - na = at->num_elements; - } - else - { - at = NULL; - } - - if (b_type == SLANG_ARRAY_TYPE) - { - if (nb != 1) - { - SLang_verror (SL_NOT_IMPLEMENTED, "Binary operation on multiple arrays not implemented"); - return -1; - } - - bt = *(SLang_Array_Type **) bp; - if (-1 == coerse_array_to_linear (bt)) - return -1; - bp = bt->data; - b_type = bt->data_type; - nb = bt->num_elements; - } - else - { - bt = NULL; - } - - if ((at != NULL) && (bt != NULL)) - { - num_dims = at->num_dims; - - if (num_dims != bt->num_dims) - { - SLang_verror (SL_TYPE_MISMATCH, "Arrays must have same dim for binary operation"); - return -1; - } - - for (i = 0; i < num_dims; i++) - { - if (at->dims[i] != bt->dims[i]) - { - SLang_verror (SL_TYPE_MISMATCH, "Arrays must be the same for binary operation"); - return -1; - } - } - } - - a_cl = _SLclass_get_class (a_type); - b_cl = _SLclass_get_class (b_type); - - if (NULL == (binary_fun = _SLclass_get_binary_fun (op, a_cl, b_cl, &c_cl, 1))) - return -1; - - no_init = ((c_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR) - || (c_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR)); - - ct = NULL; -#if _SLANG_USE_TMP_OPTIMIZATION - /* If we are dealing with scalar (or vector) objects, and if the object - * appears to be owned by the stack, then use it instead of creating a - * new version. This can happen with code such as: - * @ x = [1,2,3,4]; - * @ x = __tmp(x) + 1; - */ - if (no_init) - { - if ((at != NULL) - && (at->num_refs == 1) - && (at->data_type == c_cl->cl_data_type)) - { - ct = at; - ct->num_refs = 2; - } - else if ((bt != NULL) - && (bt->num_refs == 1) - && (bt->data_type == c_cl->cl_data_type)) - { - ct = bt; - ct->num_refs = 2; - } - } -#endif /* _SLANG_USE_TMP_OPTIMIZATION */ - - if (ct == NULL) - { - if (at != NULL) ct = at; else ct = bt; - ct = SLang_create_array1 (c_cl->cl_data_type, 0, NULL, ct->dims, ct->num_dims, no_init); - if (ct == NULL) - return -1; - } - - - if ((na == 0) || (nb == 0) /* allow empty arrays */ - || (1 == (*binary_fun) (op, a_type, ap, na, b_type, bp, nb, ct->data))) - { - *(SLang_Array_Type **) cp = ct; - return 1; - } - - SLang_free_array (ct); - return -1; -} - -static void array_where (void) -{ - SLang_Array_Type *at, *bt; - char *a_data; - int *b_data; - unsigned int i, num_elements; - int b_num; - - if (-1 == SLang_pop_array (&at, 1)) - return; - - bt = NULL; - - if (at->data_type != SLANG_CHAR_TYPE) - { - int zero; - SLang_Array_Type *tmp_at; - - tmp_at = at; - zero = 0; - if (1 != array_binary_op (SLANG_NE, - SLANG_ARRAY_TYPE, (VOID_STAR) &at, 1, - SLANG_CHAR_TYPE, (VOID_STAR) &zero, 1, - (VOID_STAR) &tmp_at)) - goto return_error; - - SLang_free_array (at); - at = tmp_at; - if (at->data_type != SLANG_CHAR_TYPE) - { - SLang_Error = SL_TYPE_MISMATCH; - goto return_error; - } - } - - a_data = (char *) at->data; - num_elements = at->num_elements; - - b_num = 0; - for (i = 0; i < num_elements; i++) - if (a_data[i] != 0) b_num++; - - if (NULL == (bt = SLang_create_array1 (SLANG_INT_TYPE, 0, NULL, &b_num, 1, 1))) - goto return_error; - - b_data = (int *) bt->data; - - i = 0; - while (b_num) - { - if (a_data[i] != 0) - { - *b_data++ = i; - b_num--; - } - - i++; - } - - (void) SLang_push_array (bt, 0); - /* drop */ - - return_error: - SLang_free_array (at); - SLang_free_array (bt); -} - -static int do_array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at) -{ - int *dims; - unsigned int i, num_dims; - unsigned int num_elements; - - if ((ind_at->data_type != SLANG_INT_TYPE) - || (ind_at->num_dims != 1)) - { - SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array"); - return -1; - } - - num_dims = ind_at->num_elements; - dims = (int *) ind_at->data; - - num_elements = 1; - for (i = 0; i < num_dims; i++) - { - int d = dims[i]; - if (d < 0) - { - SLang_verror (SL_INVALID_PARM, "reshape: dimension is less then 0"); - return -1; - } - - num_elements = (unsigned int) d * num_elements; - } - - if ((num_elements != at->num_elements) - || (num_dims > SLARRAY_MAX_DIMS)) - { - SLang_verror (SL_INVALID_PARM, "Unable to reshape array to specified size"); - return -1; - } - - for (i = 0; i < num_dims; i++) - at->dims [i] = dims[i]; - - while (i < SLARRAY_MAX_DIMS) - { - at->dims [i] = 1; - i++; - } - - at->num_dims = num_dims; - return 0; -} - -static void array_reshape (SLang_Array_Type *at, SLang_Array_Type *ind_at) -{ - (void) do_array_reshape (at, ind_at); -} - -static void _array_reshape (SLang_Array_Type *ind_at) -{ - SLang_Array_Type *at; - SLang_Array_Type *new_at; - - if (-1 == SLang_pop_array (&at, 1)) - return; - - /* FIXME: Priority=low: duplicate_array could me modified to look at num_refs */ - - /* Now try to avoid the overhead of creating a new array if possible */ - if (at->num_refs == 1) - { - /* Great, we are the sole owner of this array. */ - if ((-1 == do_array_reshape (at, ind_at)) - || (-1 == SLclass_push_ptr_obj (SLANG_ARRAY_TYPE, (VOID_STAR)at))) - SLang_free_array (at); - return; - } - - new_at = SLang_duplicate_array (at); - if (new_at != NULL) - { - if (0 == do_array_reshape (new_at, ind_at)) - (void) SLang_push_array (new_at, 0); - - SLang_free_array (new_at); - } - SLang_free_array (at); -} - -typedef struct -{ - SLang_Array_Type *at; - unsigned int increment; - char *addr; -} -Map_Arg_Type; -/* Usage: array_map (Return-Type, func, args,....); */ -static void array_map (void) -{ - Map_Arg_Type *args; - unsigned int num_args; - unsigned int i, i_control; - SLang_Name_Type *nt; - unsigned int num_elements; - SLang_Array_Type *at; - char *addr; - unsigned char type; - - at = NULL; - args = NULL; - nt = NULL; - - if (SLang_Num_Function_Args < 3) - { - SLang_verror (SL_INVALID_PARM, - "Usage: array_map (Return-Type, &func, args...)"); - SLdo_pop_n (SLang_Num_Function_Args); - return; - } - - num_args = (unsigned int)SLang_Num_Function_Args - 2; - args = (Map_Arg_Type *) SLmalloc (num_args * sizeof (Map_Arg_Type)); - if (args == NULL) - { - SLdo_pop_n (SLang_Num_Function_Args); - return; - } - memset ((char *) args, 0, num_args * sizeof (Map_Arg_Type)); - i = num_args; - i_control = 0; - while (i > 0) - { - i--; - if (-1 == SLang_pop_array (&args[i].at, 1)) - { - SLdo_pop_n (i + 2); - goto return_error; - } - if (args[i].at->num_elements > 1) - i_control = i; - } - - if (NULL == (nt = SLang_pop_function ())) - { - SLdo_pop_n (1); - goto return_error; - } - - num_elements = args[i_control].at->num_elements; - - if (-1 == _SLang_pop_datatype (&type)) - goto return_error; - - if (type == SLANG_UNDEFINED_TYPE) /* Void_Type */ - at = NULL; - else - { - at = args[i_control].at; - - if (NULL == (at = SLang_create_array (type, 0, NULL, at->dims, at->num_dims))) - goto return_error; - } - - - for (i = 0; i < num_args; i++) - { - SLang_Array_Type *ati = args[i].at; - /* FIXME: Priority = low: The actual dimensions should be compared. */ - if (ati->num_elements == num_elements) - args[i].increment = ati->sizeof_type; - /* memset already guarantees increment to be zero */ - - if (ati->num_elements == 0) - { - SLang_verror (0, "array_map: function argument %d of %d is an empty array", - i+1, num_args); - goto return_error; - } - - args[i].addr = (char *) ati->data; - } - - if (at == NULL) - addr = NULL; - else - addr = (char *)at->data; - - for (i = 0; i < num_elements; i++) - { - unsigned int j; - - if (-1 == SLang_start_arg_list ()) - goto return_error; - - for (j = 0; j < num_args; j++) - { - if (-1 == push_element_at_addr (args[j].at, - (VOID_STAR) args[j].addr, - 1)) - { - SLdo_pop_n (j); - goto return_error; - } - - args[j].addr += args[j].increment; - } - - if (-1 == SLang_end_arg_list ()) - { - SLdo_pop_n (num_args); - goto return_error; - } - - if (-1 == SLexecute_function (nt)) - goto return_error; - - if (at == NULL) - continue; - - if (-1 == at->cl->cl_apop (type, (VOID_STAR) addr)) - goto return_error; - - addr += at->sizeof_type; - } - - if (at != NULL) - (void) SLang_push_array (at, 0); - - /* drop */ - - return_error: - SLang_free_array (at); - SLang_free_function (nt); - if (args != NULL) - { - for (i = 0; i < num_args; i++) - SLang_free_array (args[i].at); - - SLfree ((char *) args); - } -} - -static SLang_Intrin_Fun_Type Array_Table [] = -{ - MAKE_INTRINSIC_0("array_map", array_map, SLANG_VOID_TYPE), - MAKE_INTRINSIC_0("array_sort", sort_array, SLANG_VOID_TYPE), - MAKE_INTRINSIC_1("array_to_bstring", array_to_bstring, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE), - MAKE_INTRINSIC_1("bstring_to_array", bstring_to_array, SLANG_VOID_TYPE, SLANG_BSTRING_TYPE), - MAKE_INTRINSIC("init_char_array", init_char_array, SLANG_VOID_TYPE, 0), - MAKE_INTRINSIC("array_info", array_info, SLANG_VOID_TYPE, 0), - MAKE_INTRINSIC("where", array_where, SLANG_VOID_TYPE, 0), - MAKE_INTRINSIC_2("reshape", array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE), - MAKE_INTRINSIC_1("_reshape", _array_reshape, SLANG_VOID_TYPE, SLANG_ARRAY_TYPE), - SLANG_END_INTRIN_FUN_TABLE -}; - -static char *array_string (unsigned char type, VOID_STAR v) -{ - SLang_Array_Type *at; - char buf[512]; - unsigned int i, num_dims; - int *dims; - - at = *(SLang_Array_Type **) v; - type = at->data_type; - num_dims = at->num_dims; - dims = at->dims; - - sprintf (buf, "%s[%d", SLclass_get_datatype_name (type), at->dims[0]); - - for (i = 1; i < num_dims; i++) - sprintf (buf + strlen(buf), ",%d", dims[i]); - strcat (buf, "]"); - - return SLmake_string (buf); -} - -static void array_destroy (unsigned char type, VOID_STAR v) -{ - (void) type; - SLang_free_array (*(SLang_Array_Type **) v); -} - -static int array_push (unsigned char type, VOID_STAR v) -{ - SLang_Array_Type *at; - - (void) type; - at = *(SLang_Array_Type **) v; - return SLang_push_array (at, 0); -} - -/* Intrinsic arrays are not stored in a variable. So, the address that - * would contain the variable holds the array address. - */ -static int array_push_intrinsic (unsigned char type, VOID_STAR v) -{ - (void) type; - return SLang_push_array ((SLang_Array_Type *) v, 0); -} - -int _SLarray_add_bin_op (unsigned char type) -{ - SL_OOBinary_Type *ab; - SLang_Class_Type *cl; - - cl = _SLclass_get_class (type); - ab = cl->cl_binary_ops; - - while (ab != NULL) - { - if (ab->data_type == SLANG_ARRAY_TYPE) - return 0; - ab = ab->next; - } - - if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, type, array_binary_op, array_binary_op_result)) - || (-1 == SLclass_add_binary_op (type, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result))) - return -1; - - return 0; -} - -static SLang_Array_Type * -do_array_math_op (int op, int unary_type, - SLang_Array_Type *at, unsigned int na) -{ - unsigned char a_type, b_type; - int (*f) (int, unsigned char, VOID_STAR, unsigned int, VOID_STAR); - SLang_Array_Type *bt; - SLang_Class_Type *b_cl; - int no_init; - - if (na != 1) - { - SLang_verror (SL_NOT_IMPLEMENTED, "Operation restricted to 1 array"); - return NULL; - } - - a_type = at->data_type; - if (NULL == (f = _SLclass_get_unary_fun (op, at->cl, &b_cl, unary_type))) - return NULL; - b_type = b_cl->cl_data_type; - - if (-1 == coerse_array_to_linear (at)) - return NULL; - - no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR) - || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR)); - -#if _SLANG_USE_TMP_OPTIMIZATION - /* If we are dealing with scalar (or vector) objects, and if the object - * appears to be owned by the stack, then use it instead of creating a - * new version. This can happen with code such as: - * @ x = [1,2,3,4]; - * @ x = UNARY_OP(__tmp(x)); - */ - if (no_init - && (at->num_refs == 1) - && (at->data_type == b_cl->cl_data_type)) - { - bt = at; - bt->num_refs = 2; - } - else -#endif /* _SLANG_USE_TMP_OPTIMIZATION */ - if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init))) - return NULL; - - if (1 != (*f)(op, a_type, at->data, at->num_elements, bt->data)) - { - SLang_free_array (bt); - return NULL; - } - return bt; -} - -static int -array_unary_op_result (int op, unsigned char a, unsigned char *b) -{ - (void) op; - (void) a; - *b = SLANG_ARRAY_TYPE; - return 1; -} - -static int -array_unary_op (int op, - unsigned char a, VOID_STAR ap, unsigned int na, - VOID_STAR bp) -{ - SLang_Array_Type *at; - - (void) a; - at = *(SLang_Array_Type **) ap; - if (NULL == (at = do_array_math_op (op, _SLANG_BC_UNARY, at, na))) - { - if (SLang_Error) return -1; - return 0; - } - *(SLang_Array_Type **) bp = at; - return 1; -} - -static int -array_math_op (int op, - unsigned char a, VOID_STAR ap, unsigned int na, - VOID_STAR bp) -{ - SLang_Array_Type *at; - - (void) a; - at = *(SLang_Array_Type **) ap; - if (NULL == (at = do_array_math_op (op, _SLANG_BC_MATH_UNARY, at, na))) - { - if (SLang_Error) return -1; - return 0; - } - *(SLang_Array_Type **) bp = at; - return 1; -} - -static int -array_app_op (int op, - unsigned char a, VOID_STAR ap, unsigned int na, - VOID_STAR bp) -{ - SLang_Array_Type *at; - - (void) a; - at = *(SLang_Array_Type **) ap; - if (NULL == (at = do_array_math_op (op, _SLANG_BC_APP_UNARY, at, na))) - { - if (SLang_Error) return -1; - return 0; - } - *(SLang_Array_Type **) bp = at; - return 1; -} - -int -_SLarray_typecast (unsigned char a_type, VOID_STAR ap, unsigned int na, - unsigned char b_type, VOID_STAR bp, - int is_implicit) -{ - SLang_Array_Type *at, *bt; - SLang_Class_Type *b_cl; - int no_init; - int (*t) (unsigned char, VOID_STAR, unsigned int, unsigned char, VOID_STAR); - - if (na != 1) - { - SLang_verror (SL_NOT_IMPLEMENTED, "typecast of multiple arrays not implemented"); - return -1; - } - - at = *(SLang_Array_Type **) ap; - a_type = at->data_type; - - if (a_type == b_type) - { - at->num_refs += 1; - *(SLang_Array_Type **) bp = at; - return 1; - } - - if (NULL == (t = _SLclass_get_typecast (a_type, b_type, is_implicit))) - return -1; - - if (-1 == coerse_array_to_linear (at)) - return -1; - - b_cl = _SLclass_get_class (b_type); - - no_init = ((b_cl->cl_class_type == SLANG_CLASS_TYPE_SCALAR) - || (b_cl->cl_class_type == SLANG_CLASS_TYPE_VECTOR)); - - if (NULL == (bt = SLang_create_array1 (b_type, 0, NULL, at->dims, at->num_dims, no_init))) - return -1; - - if (1 == (*t) (a_type, at->data, at->num_elements, b_type, bt->data)) - { - *(SLang_Array_Type **) bp = bt; - return 1; - } - - SLang_free_array (bt); - return 0; -} - -SLang_Array_Type *SLang_duplicate_array (SLang_Array_Type *at) -{ - SLang_Array_Type *bt; - char *data, *a_data; - unsigned int i, num_elements, sizeof_type; - unsigned int size; - int (*cl_acopy) (unsigned char, VOID_STAR, VOID_STAR); - unsigned char type; - - if (-1 == coerse_array_to_linear (at)) - return NULL; - - type = at->data_type; - num_elements = at->num_elements; - sizeof_type = at->sizeof_type; - size = num_elements * sizeof_type; - - if (NULL == (data = SLmalloc (size))) - return NULL; - - if (NULL == (bt = SLang_create_array (type, 0, (VOID_STAR)data, at->dims, at->num_dims))) - { - SLfree (data); - return NULL; - } - - a_data = (char *) at->data; - if (0 == (at->flags & SLARR_DATA_VALUE_IS_POINTER)) - { - SLMEMCPY (data, a_data, size); - return bt; - } - - SLMEMSET (data, 0, size); - - cl_acopy = at->cl->cl_acopy; - for (i = 0; i < num_elements; i++) - { - if (NULL != *(VOID_STAR *) a_data) - { - if (-1 == (*cl_acopy) (type, (VOID_STAR) a_data, (VOID_STAR) data)) - { - SLang_free_array (bt); - return NULL; - } - } - - data += sizeof_type; - a_data += sizeof_type; - } - - return bt; -} - -static int array_dereference (unsigned char type, VOID_STAR addr) -{ - SLang_Array_Type *at; - - (void) type; - at = SLang_duplicate_array (*(SLang_Array_Type **) addr); - if (at == NULL) return -1; - return SLang_push_array (at, 1); -} - -/* This function gets called via, e.g., @Array_Type (Double_Type, [10,20]); - */ -static int -array_datatype_deref (unsigned char type) -{ - SLang_Array_Type *ind_at; - SLang_Array_Type *at; - -#if 0 - /* The parser generated code for this as if a function call were to be - * made. However, the interpreter simply called the deref object routine - * instead of the function call. So, I must simulate the function call. - * This needs to be formalized to hide this detail from applications - * who wish to do the same. So... - * FIXME: Priority=medium - */ - if (0 == _SL_increment_frame_pointer ()) - (void) _SL_decrement_frame_pointer (); -#endif - - if (-1 == SLang_pop_array (&ind_at, 1)) - return -1; - - if ((ind_at->data_type != SLANG_INT_TYPE) - || (ind_at->num_dims != 1)) - { - SLang_verror (SL_TYPE_MISMATCH, "Expecting 1-d integer array"); - goto return_error; - } - - if (-1 == _SLang_pop_datatype (&type)) - goto return_error; - - if (NULL == (at = SLang_create_array (type, 0, NULL, - (int *) ind_at->data, - ind_at->num_elements))) - goto return_error; - - SLang_free_array (ind_at); - return SLang_push_array (at, 1); - - return_error: - SLang_free_array (ind_at); - return -1; -} - -static int array_length (unsigned char type, VOID_STAR v, unsigned int *len) -{ - SLang_Array_Type *at; - - (void) type; - at = *(SLang_Array_Type **) v; - *len = at->num_elements; - return 0; -} - -int -_SLarray_init_slarray (void) -{ - SLang_Class_Type *cl; - - if (-1 == SLadd_intrin_fun_table (Array_Table, NULL)) - return -1; - - if (NULL == (cl = SLclass_allocate_class ("Array_Type"))) - return -1; - - (void) SLclass_set_string_function (cl, array_string); - (void) SLclass_set_destroy_function (cl, array_destroy); - (void) SLclass_set_push_function (cl, array_push); - cl->cl_push_intrinsic = array_push_intrinsic; - cl->cl_dereference = array_dereference; - cl->cl_datatype_deref = array_datatype_deref; - cl->cl_length = array_length; - - if (-1 == SLclass_register_class (cl, SLANG_ARRAY_TYPE, sizeof (VOID_STAR), - SLANG_CLASS_TYPE_PTR)) - return -1; - - if ((-1 == SLclass_add_binary_op (SLANG_ARRAY_TYPE, SLANG_ARRAY_TYPE, array_binary_op, array_binary_op_result)) - || (-1 == SLclass_add_unary_op (SLANG_ARRAY_TYPE, array_unary_op, array_unary_op_result)) - || (-1 == SLclass_add_app_unary_op (SLANG_ARRAY_TYPE, array_app_op, array_unary_op_result)) - || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result)) - || (-1 == SLclass_add_math_op (SLANG_ARRAY_TYPE, array_math_op, array_unary_op_result))) - return -1; - - return 0; -} - -int SLang_pop_array (SLang_Array_Type **at_ptr, int convert_scalar) -{ - if (-1 == pop_array (at_ptr, convert_scalar)) - return -1; - - if (-1 == coerse_array_to_linear (*at_ptr)) - { - SLang_free_array (*at_ptr); - return -1; - } - return 0; -} - -int SLang_pop_array_of_type (SLang_Array_Type **at, unsigned char type) -{ - if (-1 == SLclass_typecast (type, 1, 1)) - return -1; - - return SLang_pop_array (at, 1); -} - -void (*_SLang_Matrix_Multiply)(void); - -int _SLarray_matrix_multiply (void) -{ - if (_SLang_Matrix_Multiply != NULL) - { - (*_SLang_Matrix_Multiply)(); - return 0; - } - SLang_verror (SL_NOT_IMPLEMENTED, "Matrix multiplication not available"); - return -1; -} - -struct _SLang_Foreach_Context_Type -{ - SLang_Array_Type *at; - unsigned int next_element_index; -}; - -SLang_Foreach_Context_Type * -_SLarray_cl_foreach_open (unsigned char type, unsigned int num) -{ - SLang_Foreach_Context_Type *c; - - if (num != 0) - { - SLdo_pop_n (num + 1); - SLang_verror (SL_NOT_IMPLEMENTED, - "%s does not support 'foreach using' form", - SLclass_get_datatype_name (type)); - return NULL; - } - - if (NULL == (c = (SLang_Foreach_Context_Type *) SLmalloc (sizeof (SLang_Foreach_Context_Type)))) - return NULL; - - memset ((char *) c, 0, sizeof (SLang_Foreach_Context_Type)); - - if (-1 == pop_array (&c->at, 1)) - { - SLfree ((char *) c); - return NULL; - } - - return c; -} - -void _SLarray_cl_foreach_close (unsigned char type, SLang_Foreach_Context_Type *c) -{ - (void) type; - if (c == NULL) return; - SLang_free_array (c->at); - SLfree ((char *) c); -} - -int _SLarray_cl_foreach (unsigned char type, SLang_Foreach_Context_Type *c) -{ - SLang_Array_Type *at; - VOID_STAR data; - - (void) type; - - if (c == NULL) - return -1; - - at = c->at; - if (at->num_elements == c->next_element_index) - return 0; - - /* FIXME: Priority = low. The following assumes linear arrays - * or Integer range arrays. Fixing it right requires a method to get the - * nth element of a multidimensional array. - */ - - if (at->flags & SLARR_DATA_VALUE_IS_RANGE) - { - int d = (int) c->next_element_index; - data = range_get_data_addr (at, &d); - } - else - data = (VOID_STAR) ((char *)at->data + (c->next_element_index * at->sizeof_type)); - - c->next_element_index += 1; - - if ((at->flags & SLARR_DATA_VALUE_IS_POINTER) - && (*(VOID_STAR *) data == NULL)) - { - if (-1 == SLang_push_null ()) - return -1; - } - else if (-1 == (*at->cl->cl_apush)(at->data_type, data)) - return -1; - - /* keep going */ - return 1; -} - |