/*
* Inheritance: An object X can inherit from another object Y. This is done
* with the statement 'inherit "file";' The inherit statement will clone a
* copy of that file, call reset in it, and set a pointer to Y from X. Y has
* to be removed from the linked list of all objects. All variables declared
* by Y will be copied to X, so that X has access to them.
*
* If Y isn't loaded when it is needed, X will be discarded, and Y will be
* loaded separately. X will then be reloaded again.
*/
/*
* Information about assignments of values:
*
* There are three types of l-values: Local variables, global variables and
* vector elements.
*
* The local variables are stored in a vector, with pointers to values of the
* 'Val type'. Because they are local, they can all be freed from
* the stack afterwards. When a local variable is used, the pointer can
* be directly returned, as these values will never be changed.
*
* The global variables are similar except must keep their values between
* executions.
*
* Elements in vectors are similar to global variables. There is a reference
* count to the whole vector, that states when to deallocate the vector. The
* elements consists of 'Val' types, and will thus have to be freed
* immediately when over written.
*/
#include <stdlib.h>
#include "value.h"
#include "stralloc.h"
#include "stack_alloc.h"
#ifdef ARRAY_STATS
unsigned int total_array_size = 0, num_arrays = 0;
#endif
Val * make_string(const char *str)
{
Val *ret = alloc_stack_value();
ret->type = T_STRING;
ret->u.string = string_copy(str);
return ret;
}
Val * make_nstring(const char *str, int len)
{
Val *ret = alloc_stack_value();
ret->type = T_STRING;
ret->u.string = string_ncopy(str, len);
return ret;
}
Val *share_string(Shared * str)
{
Val *ret = alloc_stack_value();
ret->type = T_STRING;
ret->u.string = shared_string_copy(str);
return ret;
}
/*
* Extended to handle large numbers of constant ints (coz
* I reckon it's easier, that's why). The init routine is
* called by the opcode stuffing routine.
*/
Val staticints[MAXFIXEDINT - MINFIXEDINT + 1];
Vec constvec0;
int initfixedints()
{
int x;
for (x = 0; x < sizeof(staticints) / sizeof(staticints[1]); x++)
{
staticints[x].type = T_NUMBER;
staticints[x].u.number = x + MINFIXEDINT;
}
constvec0.size = 0;
constvec0.ref = 1;
return 0;
}
Val *make_number(int n)
{
Val *ret;
#if 0
/* doesn't work because staticints could end
* up as lvalues (ie. string[1]) and be assigned to! */
if (!n)
return Const(0); /* still use these by default */
if (n == 1)
return Const(1);
if (n >= MINFIXEDINT && n <= MAXFIXEDINT)
return &staticints[n - MINFIXEDINT];
#endif
ret = alloc_stack_value();
ret->type = T_NUMBER;
ret->u.number = n;
#if 0
gl_ints++;
cr_ints++;
#endif
return ret;
}
Val *make_handle(void * n)
{
Val *ret;
ret = alloc_stack_value();
ret->type = T_HANDLE;
ret->u.handle = n;
return ret;
}
Val *make_vector(Vec * p)
{
Val *ret = alloc_stack_value();
ret->type = T_POINTER;
ret->u.vec = p;
ret->u.vec->ref++;
return ret;
}
Val *make_object(Obj * n)
{
Val *ret = alloc_stack_value();
ret->type = T_OBJECT;
ret->u.ob = n;
//add_ref(ret->u.ob, "make_object()");
ret->u.ob->ref++;
return ret;
}
Val *make_real(float n)
{
Val *ret = alloc_stack_value();
ret->type = T_REAL;
ret->u.real = n;
return ret;
}
Vec *create_vector(int n, const char * from)
{
Vec *p;
int i;
if (n < 0 || n > MAX_ARRAY_SIZE)
{
#if 0
debug_message("Illegal array size (%d) from %s.\n", (char *) n, from);
#endif
n = 0;
}
if (!n)
{
p = &constvec0;
}
else
{
p = ALLOC_VECTOR(n);
p->size = n;
p->ref = 1;
/* slow.. */
for (i = 0; i < n; i++)
{
p->item[i].type = T_NUMBER;
p->item[i].u.number = 0;
}
#ifdef ARRAY_STATS
num_arrays++;
total_array_size += (p->size * sizeof(Val));
#endif
//if (p->size == 11) printf("vector: created 0x%x %d\n", p, p->ref);
}
return p;
}
Val *copy_value(Val * arg)
{
switch (arg->type)
{
case T_STRING:
return share_string(arg->u.string);
case T_OBJECT:
if (arg->u.ob->destructed)
make_space(0);
return make_object(arg->u.ob);
case T_NUMBER:
return make_number(arg->u.number);
case T_REAL:
return make_real(arg->u.real);
case T_POINTER:
return make_vector(arg->u.vec);
}
fatal("FATAL: Copy_value() - type is buggered (was %d)\n",
(char *) arg->type);
return 0;
}
/*
* Allocate an array.
*/
Val *allocate_array(int n)
{
Val *v;
Vec *p;
p = create_vector(n, "allocate array");
v = alloc_stack_value();
v->type = T_POINTER;
v->u.vec = p;
//if (p->size == 11) printf("vector: array allocated 0x%x %d\n", v->u.vec, v->u.vec->ref);
return v;
}
void free_vector(Vec * p)
{
int i;
if (p != &constvec0)
{
//if (p->size == 11) printf("vector: free 0x%x %d\n", p, p->ref);
p->ref--;
if (p->ref > 0) return;
#if 1
if (p->ref < 0)
{
fatal("FATAL: spastic value in free_vector\n");
}
#endif
for (i = 0; i < p->size; i++)
{
free_value(&p->item[i]);
}
#ifdef ARRAY_STATS
num_arrays--;
total_array_size -= (p->size * sizeof(Val));
#endif
free((char *) p);
}
}
/*
* Free the data that an value is pointing to. Not the value itself.
*/
void free_value(Val * v)
{
switch (v->type)
{
default:
/* fatal("Bad type in free_value\n"); */
case T_REAL:
case T_NUMBER:
break;
case T_STRING:
free_string(v->u.string);
break;
case T_OBJECT:
/* FIX !! */ free_object(v->u.ob, "free_value");
break;
case T_POINTER:
free_vector(v->u.vec);
break;
}
v->u.number = 0;
v->type = T_NUMBER;
}
/*
* Assign a value to an value. This is done either when element in vector,
* or when to an identifier (as all identifiers are kept in a vector pointed
* to by the object).
*/
void clear_assign(Val * dest, Val * v)
{
free_value(dest);
assign_value(dest, v);
}
void assign_value(Val * dest, Val * v)
{
#if 0
if (dest > staticints && dest < (&staticints[MAXFIXEDINT - MINFIXEDINT]))
{
extern int overflow_flag;
// overflow_flag = 1;
stack_error("Assigning to staticint\n");
}
#endif
if (v == 0)
{
dest->type = T_NUMBER;
dest->u.number = 0;
return;
}
dest->type = v->type;
switch (v->type)
{
case T_STRING:
dest->u.string = shared_string_copy(v->u.string);
break;
case T_OBJECT:
dest->u.ob = v->u.ob;
//add_ref(dest->u.ob, "assign_value");
dest->u.ob->ref++;
break;
case T_NUMBER:
dest->u.number = v->u.number;
break;
case T_POINTER:
dest->u.vec = v->u.vec;
dest->u.vec->ref++;
break;
case T_REAL:
dest->u.real = v->u.real;
break;
case T_HANDLE:
dest->u.handle = v->u.handle;
break;
default:
fatal("FATAL: Bad type in assign_value\n");
}
}
#if 0
/*
* Check that an assignment to an array item is not cyclic.
*/
static void check_for_recursion(Vec * vec, Vec * v)
{
register int i;
if (v == vec)
{
efun_error("Recursive asignment of vectors.\n");
return;
}
for (i = 0; i < v->size; i++)
{
if (v->item[i].type == T_POINTER)
check_for_recursion(vec, v->item[i].u.vec);
}
}
#endif
/*
* Free all values previously allocated.
*/
Val * alloc_value()
{
register Val *tmp;
tmp = (Val *) malloc(sizeof(Val));
return tmp;
}
char *typename(int ty)
{
char *x = "<unknown>";
switch (ty)
{
case T_NUMBER:
x = "int";
break;
case T_REAL:
x = "real";
break;
case T_STRING:
x = "string";
break;
case T_OBJECT:
x = "object";
break;
case T_POINTER:
x = "array";
break;
}
return x;
}
Val *concatenate(Val * a, Val * b)
{
int az = 0;
struct vector *p;
Val *ret;
if (a->type == T_POINTER)
az = a->u.vec->size;
else
az = 1;
if (b->type == T_POINTER)
az += b->u.vec->size;
else
az += 1;
ret = allocate_array(az);
p = ret->u.vec;
if (a->type != T_POINTER)
{
assign_value(&p->item[0], a);
az = 1;
}
else
{
copy_in_vector(p, a->u.vec, 0, 0, a->u.vec->size);
az = a->u.vec->size;
}
if (b->type != T_POINTER)
assign_value(&p->item[az], b);
else
copy_in_vector(p, b->u.vec, az, 0, b->u.vec->size);
return ret;
}
int copy_in_vector(struct vector *a, struct vector *b,
int startto, int startfrom, int len)
{
int i, s, x;
s = b->size - startfrom;
x = a->size - startto;
if (len > x)
len = x;
if (len > s)
len = s;
for (i = 0; i < len; i++)
{
/* copy_in_value(&a->item[i + startto], &b->item[i + startfrom]); */
assign_value(&a->item[i + startto], &b->item[i + startfrom]);
}
return 0;
}