/* Structure type implementation */ #include "config.h" #include "sl-feat.h" #include "slang.h" #include "_slang.h" void _SLstruct_delete_struct (_SLang_Struct_Type *s) { _SLstruct_Field_Type *field, *field_max; if (s == NULL) return; if (s->num_refs > 1) { s->num_refs -= 1; return; } field = s->fields; if (field != NULL) { field_max = field + s->nfields; while (field < field_max) { SLang_free_object (&field->obj); SLang_free_slstring (field->name); /* could be NULL */ field++; } SLfree ((char *) s->fields); } SLfree ((char *) s); } static _SLang_Struct_Type *allocate_struct (unsigned int nfields) { _SLang_Struct_Type *s; _SLstruct_Field_Type *f; unsigned int i, size; s = (_SLang_Struct_Type *) SLmalloc (sizeof (_SLang_Struct_Type)); if (s == NULL) return NULL; SLMEMSET((char *) s, 0, sizeof (_SLang_Struct_Type)); size = nfields * sizeof(_SLstruct_Field_Type); if (NULL == (f = (_SLstruct_Field_Type *) SLmalloc (size))) { SLfree ((char *) s); return NULL; } SLMEMSET ((char *) f, 0, size); s->nfields = nfields; s->fields = f; /* By default, all structs will be created with elements set to NULL. I * do not know whether or not it is better to use SLANG_UNDEFINED_TYPE. */ for (i = 0; i < nfields; i++) f[i].obj.data_type = SLANG_NULL_TYPE; return s; } static int push_struct_of_type (unsigned char type, _SLang_Struct_Type *s) { SLang_Object_Type obj; obj.data_type = type; obj.v.struct_val = s; s->num_refs += 1; if (0 == SLang_push (&obj)) return 0; s->num_refs -= 1; return -1; } int _SLang_push_struct (_SLang_Struct_Type *s) { return push_struct_of_type (SLANG_STRUCT_TYPE, s); } int _SLang_pop_struct (_SLang_Struct_Type **sp) { SLang_Object_Type obj; SLang_Class_Type *cl; unsigned char type; if (0 != SLang_pop (&obj)) return -1; type = obj.data_type; if (type != SLANG_STRUCT_TYPE) { cl = _SLclass_get_class (type); if (cl->cl_struct_def == NULL) { *sp = NULL; SLang_free_object (&obj); SLang_verror (SL_TYPE_MISMATCH, "Expecting struct type object. Found %s", cl->cl_name); return -1; } } *sp = obj.v.struct_val; return 0; } static void struct_destroy (unsigned char type, VOID_STAR vs) { (void) type; _SLstruct_delete_struct (*(_SLang_Struct_Type **) vs); } static int struct_push (unsigned char type, VOID_STAR ptr) { return push_struct_of_type (type, *(_SLang_Struct_Type **) ptr); } static _SLstruct_Field_Type *pop_field (_SLang_Struct_Type *s, char *name) { _SLstruct_Field_Type *f, *fmax; f = s->fields; fmax = f + s->nfields; while (f < fmax) { /* Since both these are slstrings, only compare pointer */ if (name == f->name) return f; f++; } SLang_verror (SL_SYNTAX_ERROR, "struct has no field named %s", name); return NULL; } SLang_Object_Type *_SLstruct_get_assign_obj (char *name) { _SLang_Struct_Type *s; _SLstruct_Field_Type *f; SLang_Object_Type *obj; if (-1 == _SLang_pop_struct (&s)) return NULL; if (s->num_refs <= 1) { SLang_doerror ("struct is orphaned-- assignment invalid"); _SLstruct_delete_struct (s); return NULL; } if (NULL == (f = pop_field (s, name))) obj = NULL; else obj = &f->obj; _SLstruct_delete_struct (s); return obj; } int _SLstruct_create_struct (unsigned int nfields, char **field_names, unsigned char *field_types, VOID_STAR *field_values) { _SLang_Struct_Type *s; _SLstruct_Field_Type *f; unsigned int i; if (NULL == (s = allocate_struct (nfields))) return -1; f = s->fields; for (i = 0; i < nfields; i++) { unsigned char type; SLang_Class_Type *cl; VOID_STAR value; char *name = field_names [i]; if (NULL == (f->name = SLang_create_slstring (name))) goto return_error; if ((field_values == NULL) || (NULL == (value = field_values [i]))) { f++; continue; } type = field_types[i]; cl = _SLclass_get_class (type); if ((-1 == (cl->cl_push (type, value))) || (-1 == SLang_pop (&f->obj))) goto return_error; f++; } if (0 == _SLang_push_struct (s)) return 0; /* drop */ return_error: _SLstruct_delete_struct (s); return -1; } /* Interpreter interface */ int _SLstruct_get_field (char *name) { _SLang_Struct_Type *s; _SLstruct_Field_Type *f; int ret; if (-1 == _SLang_pop_struct (&s)) return -1; if (NULL == (f = pop_field (s, name))) { _SLstruct_delete_struct (s); return -1; } ret = _SLpush_slang_obj (&f->obj); _SLstruct_delete_struct (s); return ret; } int _SLstruct_define_struct (void) { int nfields; _SLang_Struct_Type *s; _SLstruct_Field_Type *f; if (-1 == SLang_pop_integer (&nfields)) return -1; if (nfields <= 0) { SLang_verror (SL_INVALID_PARM, "Number of struct fields must be > 0"); return -1; } if (NULL == (s = allocate_struct (nfields))) return -1; f = s->fields; while (nfields) { char *name; nfields--; if (-1 == SLang_pop_slstring (&name)) { _SLstruct_delete_struct (s); return -1; } f[nfields].name = name; } if (-1 == _SLang_push_struct (s)) { _SLstruct_delete_struct (s); return -1; } return 0; } /* Simply make a struct that contains the same fields as struct s. Do not * duplicate the field values. */ static _SLang_Struct_Type *make_struct_shell (_SLang_Struct_Type *s) { _SLang_Struct_Type *new_s; _SLstruct_Field_Type *new_f, *old_f; unsigned int i, nfields; nfields = s->nfields; if (NULL == (new_s = allocate_struct (nfields))) return NULL; new_f = new_s->fields; old_f = s->fields; for (i = 0; i < nfields; i++) { if (NULL == (new_f[i].name = SLang_create_slstring (old_f[i].name))) { _SLstruct_delete_struct (new_s); return NULL; } } return new_s; } static int struct_init_array_object (unsigned char type, VOID_STAR addr) { SLang_Class_Type *cl; _SLang_Struct_Type *s; cl = _SLclass_get_class (type); if (NULL == (s = make_struct_shell (cl->cl_struct_def))) return -1; s->num_refs = 1; *(_SLang_Struct_Type **) addr = s; return 0; } static int typedefed_struct_datatype_deref (unsigned char type) { SLang_Class_Type *cl; _SLang_Struct_Type *s; cl = _SLclass_get_class (type); if (NULL == (s = make_struct_shell (cl->cl_struct_def))) return -1; if (-1 == push_struct_of_type (type, s)) { _SLstruct_delete_struct (s); return -1; } return 0; } static _SLang_Struct_Type *duplicate_struct (_SLang_Struct_Type *s) { _SLang_Struct_Type *new_s; _SLstruct_Field_Type *new_f, *f, *fmax; new_s = make_struct_shell (s); if (new_s == NULL) return NULL; f = s->fields; fmax = f + s->nfields; new_f = new_s->fields; while (f < fmax) { SLang_Object_Type *obj; obj = &f->obj; if (obj->data_type != SLANG_UNDEFINED_TYPE) { if ((-1 == _SLpush_slang_obj (obj)) || (-1 == SLang_pop (&new_f->obj))) { _SLstruct_delete_struct (new_s); return NULL; } } new_f++; f++; } return new_s; } static int struct_dereference (unsigned char type, VOID_STAR addr) { _SLang_Struct_Type *s; if (NULL == (s = duplicate_struct (*(_SLang_Struct_Type **) addr))) return -1; if (-1 == push_struct_of_type (type, s)) { _SLstruct_delete_struct (s); return -1; } return 0; } int _SLstruct_define_typedef (void) { char *type_name; _SLang_Struct_Type *s; SLang_Class_Type *cl; if (-1 == SLang_pop_slstring (&type_name)) return -1; if (-1 == _SLang_pop_struct (&s)) { SLang_free_slstring (type_name); return -1; } if (NULL == (cl = SLclass_allocate_class (type_name))) { SLang_free_slstring (type_name); _SLstruct_delete_struct (s); return -1; } SLang_free_slstring (type_name); if (NULL == (cl->cl_struct_def = make_struct_shell (s))) { _SLstruct_delete_struct (s); /* FIXME!! cl needs to be freed */ return -1; } _SLstruct_delete_struct (s); cl->cl_init_array_object = struct_init_array_object; cl->cl_datatype_deref = typedefed_struct_datatype_deref; cl->cl_destroy = struct_destroy; cl->cl_push = struct_push; cl->cl_dereference = struct_dereference; if (-1 == SLclass_register_class (cl, SLANG_VOID_TYPE, /* any open slot */ sizeof (_SLang_Struct_Type), SLANG_CLASS_TYPE_PTR)) { return -1; } return 0; } static int register_struct (void) { SLang_Class_Type *cl; if (NULL == (cl = SLclass_allocate_class ("Struct_Type"))) return -1; (void) SLclass_set_destroy_function (cl, struct_destroy); (void) SLclass_set_push_function (cl, struct_push); cl->cl_dereference = struct_dereference; if (-1 == SLclass_register_class (cl, SLANG_STRUCT_TYPE, sizeof (_SLang_Struct_Type), SLANG_CLASS_TYPE_PTR)) return -1; return 0; } static SLang_Intrin_Fun_Type Struct_Table [] = { SLANG_END_TABLE }; int _SLstruct_init (void) { if ((-1 == SLadd_intrin_fun_table (Struct_Table, NULL)) || (-1 == register_struct ())) return -1; return 0; }