1092 lines
31 KiB
C
1092 lines
31 KiB
C
/**
|
||
* Part of the Lccrt Project, under the Apache License v2.0
|
||
* See http://www.apache.org/licenses/LICENSE-2.0.txt for license information.
|
||
* SPDX-License-Identifier: Apache-2.0
|
||
*
|
||
* lccrt_metadata.c - реализация пользовательского интерфейса метаданных.
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <stdarg.h>
|
||
|
||
#include "lccrt_real.h"
|
||
|
||
/**
|
||
* Получить "нулевое" значение для категории.
|
||
*/
|
||
lccrt_einfo_category_t
|
||
lccrt_einfo_category_empty()
|
||
{
|
||
lccrt_einfo_category_t r = {-1LL};
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_category_empty */
|
||
|
||
/**
|
||
* Проверка категории метаданных на инициализированность.
|
||
*/
|
||
int
|
||
lccrt_einfo_category_is_valued( lccrt_einfo_category_t ecat)
|
||
{
|
||
int r = (ecat.id >= 0);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_category_is_valued */
|
||
|
||
/**
|
||
* Преобразовать внешний дескриптор во внутреннюю реализацию.
|
||
*/
|
||
lccrt_einfo_handle_t
|
||
lccrt_einfo_get_handle( lccrt_einfo_reference_t eref)
|
||
{
|
||
lccrt_einfo_handle_t r;
|
||
|
||
r.type = eref.data[0];
|
||
r.data.i64 = eref.data[1];
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_handle */
|
||
|
||
/**
|
||
* Преобразовать внешний дескриптор во внутреннюю реализацию.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_get_reference( lccrt_einfo_handle_t ehdl)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
|
||
r.data[0] = ehdl.type;
|
||
r.data[1] = ehdl.data.i64;
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_reference */
|
||
|
||
/**
|
||
* Преобразовать внешний дескриптор во внутреннюю реализацию.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_get_block_reference( lccrt_einfo_block_ptr eblock)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
lccrt_einfo_handle_t ehdl;
|
||
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
ehdl.type = eblock->type;
|
||
ehdl.data.ref = eblock;
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_block_reference */
|
||
|
||
/**
|
||
* Проверяем возможность передачи значения в назначение указанного типа.
|
||
*/
|
||
int
|
||
lccrt_einfo_is_value_assignable( lccrt_einfo_tydescr_ptr etyde, lccrt_einfo_reference_t value)
|
||
{
|
||
int i;
|
||
int r = 0;
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( value);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
if ( (ehdl.type == LCCRT_EINFO_NULL) )
|
||
{
|
||
r = 1;
|
||
|
||
} else if ( (ehdl.type == LCCRT_EINFO_INT64) )
|
||
{
|
||
if ( (etyde->type == LCCRT_EINFO_INT64) )
|
||
{
|
||
r = 1;
|
||
} else if ( (etyde->type == LCCRT_EINFO_UNION) )
|
||
{
|
||
for ( i = 0; i < etyde->num_flds; ++i )
|
||
{
|
||
if ( (etyde->types[i]->type == LCCRT_EINFO_INT64) )
|
||
{
|
||
r = 1;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
} else if ( (etyde->type == LCCRT_EINFO_UNION) )
|
||
{
|
||
for ( i = 0; i < etyde->num_flds; ++i )
|
||
{
|
||
lccrt_einfo_tydescr_ptr etydei = etyde->types[i];
|
||
|
||
if ( (etydei->type == eblock->type)
|
||
&& (etydei == eblock->tydescr) )
|
||
{
|
||
r = 1;
|
||
break;
|
||
}
|
||
}
|
||
} else
|
||
{
|
||
if ( (etyde->type == eblock->type)
|
||
&& (etyde == eblock->tydescr) )
|
||
{
|
||
r = 1;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_is_value_assignable */
|
||
|
||
/**
|
||
* Освободить выделенные данные.
|
||
*/
|
||
void
|
||
lccrt_einfo_tydescr_delete( lccrt_einfo_tydescr_ptr etyde)
|
||
{
|
||
if ( etyde )
|
||
{
|
||
int i;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( etyde->m);
|
||
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
if ( etyde->flds )
|
||
{
|
||
for ( i = 0; i < etyde->num_flds; ++i ) lccrt_ctx_free( ctx, etyde->flds[i]);
|
||
}
|
||
lccrt_ctx_free( ctx, etyde->self_name);
|
||
lccrt_ctx_free( ctx, etyde->flds);
|
||
lccrt_ctx_free( ctx, etyde->types);
|
||
lccrt_check_type_done( etyde, lccrt_einfo_tydescr_t);
|
||
lccrt_ctx_free( ctx, etyde);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_einfo_tydescr_delete */
|
||
|
||
/**
|
||
* Проверить описание типа данных на принадлежность к LCCRT_EINFO_INT64.
|
||
*/
|
||
int
|
||
lccrt_einfo_is_tydescr_i64( lccrt_einfo_tydescr_ptr etyde)
|
||
{
|
||
int r = (etyde->type == LCCRT_EINFO_INT64);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_is_tydescr_i64 */
|
||
|
||
/**
|
||
* Проверить описание типа данных на принадлежность к LCCRT_EINFO_RAW.
|
||
*/
|
||
int
|
||
lccrt_einfo_is_tydescr_raw( lccrt_einfo_tydescr_ptr etyde)
|
||
{
|
||
int r = (etyde->type == LCCRT_EINFO_RAW);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_is_tydescr_raw */
|
||
|
||
/**
|
||
* Получить значение поля в описании типа метаданных.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_tydescr_get_elem( lccrt_einfo_tydescr_ptr etyde, int elem_k)
|
||
{
|
||
lccrt_einfo_tydescr_ptr r = 0;
|
||
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
lccrt_assert( (0 <= elem_k) && (elem_k < etyde->num_flds));
|
||
r = etyde->types[elem_k];
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_tydescr_get_elem */
|
||
|
||
/**
|
||
* Создать описание типа данных LCCRT_EINFO_INT64.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_make_tydescr_i64( lccrt_m_ptr m)
|
||
{
|
||
lccrt_einfo_tydescr_ptr r = m->einfo_tyi64;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
lccrt_check_type_assert( m, lccrt_module_t);
|
||
if ( !r )
|
||
{
|
||
r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t);
|
||
m->einfo_tyi64 = r;
|
||
r->next = m->etydescrs_head;
|
||
m->etydescrs_head = r;
|
||
memset( r, 0, sizeof( r[0]));
|
||
lccrt_check_type_init( r, lccrt_einfo_tydescr_t);
|
||
r->type = LCCRT_EINFO_INT64;
|
||
r->m = m;
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_make_tydescr_i64 */
|
||
|
||
/**
|
||
* Создать описание типа данных LCCRT_EINFO_RAW.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_make_tydescr_raw( lccrt_m_ptr m)
|
||
{
|
||
lccrt_einfo_tydescr_ptr r = m->einfo_tyraw;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
lccrt_check_type_assert( m, lccrt_module_t);
|
||
if ( !r )
|
||
{
|
||
r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t);
|
||
m->einfo_tyraw = r;
|
||
r->next = m->etydescrs_head;
|
||
m->etydescrs_head = r;
|
||
memset( r, 0, sizeof( r[0]));
|
||
lccrt_check_type_init( r, lccrt_einfo_tydescr_t);
|
||
r->type = LCCRT_EINFO_RAW;
|
||
r->m = m;
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_make_tydescr_raw */
|
||
|
||
/**
|
||
* Создать описание типа данных LCCRT_EINFO_ARRAY.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_make_tydescr_array( lccrt_m_ptr m, lccrt_einfo_tydescr_ptr etyde)
|
||
{
|
||
int is_new;
|
||
lccrt_einfo_tydescr_ptr r = 0;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
lccrt_he_ptr he = lccrt_hash_push( m->einfo_tyarrs, (intptr_t)etyde, &is_new);
|
||
|
||
lccrt_assert( etyde);
|
||
lccrt_check_type_assert( m, lccrt_module_t);
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
|
||
if ( is_new )
|
||
{
|
||
r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t);
|
||
lccrt_hash_set( he, (intptr_t)r);
|
||
memset( r, 0, sizeof( r[0]));
|
||
r->next = m->etydescrs_head;
|
||
m->etydescrs_head = r;
|
||
lccrt_check_type_init( r, lccrt_einfo_tydescr_t);
|
||
r->type = LCCRT_EINFO_ARRAY;
|
||
r->num_flds = 1;
|
||
r->m = m;
|
||
r->types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, 1);
|
||
r->types[0] = etyde;
|
||
} else
|
||
{
|
||
r = (lccrt_einfo_tydescr_ptr)lccrt_hash_get( he);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_make_tydescr_array */
|
||
|
||
/**
|
||
* Создать описание типа данных LCCRT_EINFO_UNION.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_make_tydescr_union( lccrt_m_ptr m, int num_flds, lccrt_eitd_ptr *flds_types)
|
||
{
|
||
int i;
|
||
lccrt_einfo_tydescr_ptr r = 0;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
lccrt_assert( num_flds >= 0);
|
||
r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t);
|
||
memset( r, 0, sizeof( r[0]));
|
||
r->next = m->etydescrs_head;
|
||
m->etydescrs_head = r;
|
||
lccrt_check_type_init( r, lccrt_einfo_tydescr_t);
|
||
r->type = LCCRT_EINFO_UNION;
|
||
r->num_flds = num_flds;
|
||
r->m = m;
|
||
r->flds = lccrt_ctx_mallocn( ctx, char *, num_flds);
|
||
r->types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, num_flds);
|
||
for ( i = 0; i < num_flds; ++i )
|
||
{
|
||
r->types[i] = flds_types[i];
|
||
lccrt_assert( flds_types[i]->type != LCCRT_EINFO_UNION);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_make_tydescr_union */
|
||
|
||
/**
|
||
* Создать описание типа данных LCCRT_EINFO_STRUCT.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_make_tydescr_struct( lccrt_m_ptr m, const char *name, int num_flds,
|
||
const char **flds_names, lccrt_eitd_ptr *flds_types)
|
||
{
|
||
int i;
|
||
int is_new;
|
||
lccrt_einfo_tydescr_ptr r = 0;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
lccrt_he_ptr he = lccrt_hash_push( m->einfo_tysts, (intptr_t)name, &is_new);
|
||
|
||
lccrt_check_type_assert( m, lccrt_module_t);
|
||
lccrt_assert( num_flds >= 0);
|
||
|
||
if ( is_new )
|
||
{
|
||
r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t);
|
||
lccrt_hash_set( he, (intptr_t)r);
|
||
memset( r, 0, sizeof( r[0]));
|
||
r->next = m->etydescrs_head;
|
||
m->etydescrs_head = r;
|
||
lccrt_check_type_init( r, lccrt_einfo_tydescr_t);
|
||
r->type = LCCRT_EINFO_STRUCT;
|
||
r->num_flds = num_flds;
|
||
r->m = m;
|
||
r->self_name = lccrt_ctx_copy_str( ctx, name);
|
||
r->flds = lccrt_ctx_mallocn( ctx, char *, num_flds);
|
||
r->types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, num_flds);
|
||
for ( i = 0; i < num_flds; ++i )
|
||
{
|
||
r->types[i] = flds_types[i];
|
||
r->flds[i] = lccrt_ctx_copy_str( ctx, flds_names[i]);
|
||
}
|
||
} else
|
||
{
|
||
int is_err = 0;
|
||
|
||
r = (lccrt_einfo_tydescr_ptr)lccrt_hash_get( he);
|
||
if ( (strcmp( r->self_name, name) != 0)
|
||
|| (r->num_flds != num_flds) )
|
||
{
|
||
is_err = 1;
|
||
}
|
||
|
||
for ( i = 0; i < num_flds; ++i )
|
||
{
|
||
if ( (r->types[i] != flds_types[i])
|
||
|| (strcmp( r->flds[i], flds_names[i]) != 0) )
|
||
{
|
||
is_err = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ( is_err )
|
||
{
|
||
r = 0;
|
||
lccrt_ctx_error( ctx, 0, "type description of struct '%s' differs from the early one", name);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_make_tydescr_struct */
|
||
|
||
/**
|
||
* Поиск в описании структурного типа дескриптора поля.
|
||
*/
|
||
lccrt_einfo_field_id_t
|
||
lccrt_einfo_find_tydescr_field( lccrt_einfo_tydescr_ptr etyde, const char *name)
|
||
{
|
||
int i;
|
||
lccrt_einfo_field_id_t r = {{0, 0}};
|
||
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
lccrt_assert( etyde->type == LCCRT_EINFO_STRUCT);
|
||
for ( i = 0; i < etyde->num_flds; ++i )
|
||
{
|
||
if ( (strcmp( name, etyde->flds[i]) == 0) )
|
||
{
|
||
r.data[0] = (intptr_t)etyde;
|
||
r.data[1] = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_find_tydescr_field */
|
||
|
||
/**
|
||
* Создать в рамках модуля новую категорию метаданных.
|
||
*/
|
||
lccrt_einfo_category_t
|
||
lccrt_module_new_einfo_category( lccrt_module_ptr m, const char *name)
|
||
{
|
||
lccrt_einfo_category_t r;
|
||
int is_new = 0;
|
||
lccrt_he_ptr he = lccrt_hash_push( m->einfo_cats, (intptr_t)name, &is_new);
|
||
|
||
lccrt_assert( is_new);
|
||
lccrt_hash_set( he, (intptr_t)m->einfo_ident);
|
||
r.id = m->einfo_ident;
|
||
m->einfo_ident++;
|
||
|
||
return (r);
|
||
} /* lccrt_module_new_einfo_category */
|
||
|
||
/**
|
||
* Поиск в модуле категорию метаданных по имени.
|
||
*/
|
||
lccrt_einfo_category_t
|
||
lccrt_module_find_einfo_category( lccrt_module_ptr m, const char *name)
|
||
{
|
||
lccrt_einfo_category_t r = {-1LL};
|
||
lccrt_hash_entry_ptr he = lccrt_hash_find( m->einfo_cats, (intptr_t)name);
|
||
|
||
if ( he )
|
||
{
|
||
r.id = lccrt_hash_get( he);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_module_find_einfo_category */
|
||
|
||
/**
|
||
* Проверка метаданных на наличие значения.
|
||
*/
|
||
int
|
||
lccrt_einfo_is_valued( lccrt_einfo_reference_t eref)
|
||
{
|
||
int r = 0;
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
|
||
if ( (ehdl.type == LCCRT_EINFO_INT64)
|
||
|| (ehdl.type == LCCRT_EINFO_RAW)
|
||
|| (ehdl.type == LCCRT_EINFO_ARRAY)
|
||
|| (ehdl.type == LCCRT_EINFO_UNION)
|
||
|| (ehdl.type == LCCRT_EINFO_STRUCT) )
|
||
{
|
||
r = 1;
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_is_valued */
|
||
|
||
/**
|
||
* Получить количество элементов в метаданных.
|
||
*/
|
||
int
|
||
lccrt_einfo_get_num_args( lccrt_einfo_reference_t eref)
|
||
{
|
||
int r = 0;
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
|
||
if ( (ehdl.type == LCCRT_EINFO_ARRAY)
|
||
|| (ehdl.type == LCCRT_EINFO_STRUCT)
|
||
|| (ehdl.type == LCCRT_EINFO_RAW) )
|
||
{
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
r = eblock->num_args;
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_num_args */
|
||
|
||
/**
|
||
* Получить элемент массива.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_get_elem( lccrt_einfo_reference_t eref, int elem_k)
|
||
{
|
||
lccrt_einfo_reference_t r = {0};
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_assert( ehdl.type == LCCRT_EINFO_ARRAY);
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
lccrt_assert( (0 <= elem_k) && (elem_k < eblock->num_args));
|
||
r = lccrt_einfo_get_reference( eblock->data.elems[elem_k]);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_elem */
|
||
|
||
/**
|
||
* Получить поле структуры.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_get_field( lccrt_einfo_reference_t eref, lccrt_eifi_t eifi)
|
||
{
|
||
lccrt_einfo_reference_t r = {0};
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_assert( ehdl.type == LCCRT_EINFO_STRUCT);
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
lccrt_assert( (intptr_t)eblock->tydescr == eifi.data[0]);
|
||
lccrt_assert( (0 <= eifi.data[1]) && (eifi.data[1] < eblock->num_args));
|
||
r = lccrt_einfo_get_reference( eblock->data.flds[eifi.data[1]]);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_field */
|
||
|
||
/**
|
||
* Получить значение байтового массива.
|
||
*/
|
||
uint8_t *
|
||
lccrt_einfo_get_raw_data( lccrt_einfo_reference_t eref)
|
||
{
|
||
uint8_t *r = 0;
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_assert( ehdl.type == LCCRT_EINFO_RAW);
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
r = eblock->data.rdata;
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_raw_data */
|
||
|
||
/**
|
||
* Получить для нескалярных метаданных ссылки на описание типа данных.
|
||
*/
|
||
lccrt_einfo_tydescr_ptr
|
||
lccrt_einfo_get_tydescr( lccrt_einfo_reference_t eref)
|
||
{
|
||
lccrt_einfo_tydescr_ptr r = 0;
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
|
||
if ( (ehdl.type == LCCRT_EINFO_ARRAY)
|
||
|| (ehdl.type == LCCRT_EINFO_STRUCT)
|
||
|| (ehdl.type == LCCRT_EINFO_RAW) )
|
||
{
|
||
r = ehdl.data.ref->tydescr;
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_get_tydescr */
|
||
|
||
/**
|
||
* Проверка типа метаданных на передачу по значению.
|
||
*/
|
||
int
|
||
lccrt_einfo_is_scalar( lccrt_einfo_reference_t eref)
|
||
{
|
||
int r = 0;
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
|
||
if ( (ehdl.type == LCCRT_EINFO_INT64) )
|
||
{
|
||
r = 1;
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_is_scalar */
|
||
|
||
/**
|
||
* Удалить данные структуры и саму структуру.
|
||
*/
|
||
void
|
||
lccrt_einfo_block_delete( lccrt_einfo_block_ptr eblock)
|
||
{
|
||
if ( eblock )
|
||
{
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( eblock->tydescr->m);
|
||
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
lccrt_check_type_assert( eblock->tydescr, lccrt_einfo_tydescr_t);
|
||
lccrt_ctx_free( ctx, eblock->data.flds);
|
||
lccrt_check_type_done( eblock, lccrt_einfo_block_t);
|
||
lccrt_ctx_free( ctx, eblock);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_einfo_block_delete */
|
||
|
||
/**
|
||
* Проверить дескриптор на равенство нулевому дескриптору.
|
||
*/
|
||
int
|
||
lccrt_einfo_is_empty( lccrt_einfo_reference_t eref)
|
||
{
|
||
int r = ((eref.data[0] == 0) && (eref.data[1] == 0));
|
||
|
||
lccrt_assert( r != lccrt_einfo_is_valued( eref));
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_is_empty */
|
||
|
||
/**
|
||
* Создать нулевой дескриптор.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_new_empty()
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
lccrt_einfo_handle_t ehdl;
|
||
|
||
ehdl.type = LCCRT_EINFO_NULL;
|
||
ehdl.data.i64 = 0;
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_new_empty */
|
||
|
||
/**
|
||
* Создать дескриптор целочисленных данных.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_new_i64( uint64_t value)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
lccrt_einfo_handle_t ehdl;
|
||
|
||
ehdl.type = LCCRT_EINFO_INT64;
|
||
ehdl.data.i64 = value;
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_new_i64 */
|
||
|
||
/**
|
||
* Создать дескриптор байтового массива.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_new_raw( lccrt_module_ptr m, int length, const uint8_t *data)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
lccrt_einfo_handle_t ehdl;
|
||
lccrt_einfo_block_ptr eblock;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
eblock = lccrt_ctx_malloc( ctx, lccrt_einfo_block_t);
|
||
memset( eblock, 0, sizeof( eblock[0]));
|
||
lccrt_check_type_init( eblock, lccrt_einfo_block_t);
|
||
eblock->next = m->eblocks_head;
|
||
m->eblocks_head = eblock;
|
||
eblock->type = LCCRT_EINFO_RAW;
|
||
eblock->tydescr = lccrt_einfo_make_tydescr_raw( m);
|
||
eblock->num_args = length;
|
||
eblock->data.rdata = lccrt_ctx_mallocn( ctx, uint8_t, length);
|
||
memcpy( eblock->data.rdata, data, length);
|
||
|
||
ehdl.type = LCCRT_EINFO_RAW;
|
||
ehdl.data.ref = eblock;
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_new_raw */
|
||
|
||
/**
|
||
* Создать дескриптор байтового массива на основе строке.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_new_raw_by_string( lccrt_module_ptr m, const char *data)
|
||
{
|
||
lccrt_einfo_reference_t r = lccrt_einfo_new_raw( m, strlen( data) + 1, data);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_new_raw_by_string */
|
||
|
||
/**
|
||
* Создать значение типа массив.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_new_array( lccrt_einfo_tydescr_ptr etyde, int alloc_elems)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
lccrt_einfo_handle_t ehdl;
|
||
lccrt_einfo_block_ptr eblock;
|
||
lccrt_module_ptr m = etyde->m;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
lccrt_assert( alloc_elems >= 0);
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
|
||
eblock = lccrt_ctx_malloc( ctx, lccrt_einfo_block_t);
|
||
memset( eblock, 0, sizeof( eblock[0]));
|
||
lccrt_check_type_init( eblock, lccrt_einfo_block_t);
|
||
eblock->next = m->eblocks_head;
|
||
m->eblocks_head = eblock;
|
||
eblock->type = LCCRT_EINFO_ARRAY;
|
||
eblock->tydescr = etyde;
|
||
//eblock->max_args = (alloc_elems == 0) ? 4 : alloc_elems;
|
||
eblock->num_args = alloc_elems;
|
||
eblock->max_args = alloc_elems;
|
||
eblock->data.elems = lccrt_ctx_mallocn( ctx, lccrt_einfo_handle_t, eblock->max_args);
|
||
memset( eblock->data.flds, 0, eblock->max_args*sizeof( eblock->data.elems[0]));
|
||
|
||
ehdl.type = LCCRT_EINFO_ARRAY;
|
||
ehdl.data.ref = eblock;
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_new_array */
|
||
|
||
/**
|
||
* Создать значение типа структура.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_new_struct( lccrt_einfo_tydescr_ptr etyde)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
lccrt_einfo_handle_t ehdl;
|
||
lccrt_einfo_block_ptr eblock;
|
||
lccrt_module_ptr m = etyde->m;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
lccrt_assert( etyde->type == LCCRT_EINFO_STRUCT);
|
||
eblock = lccrt_ctx_malloc( ctx, lccrt_einfo_block_t);
|
||
memset( eblock, 0, sizeof( eblock[0]));
|
||
lccrt_check_type_init( eblock, lccrt_einfo_block_t);
|
||
eblock->next = m->eblocks_head;
|
||
m->eblocks_head = eblock;
|
||
eblock->type = LCCRT_EINFO_STRUCT;
|
||
eblock->tydescr = etyde;
|
||
eblock->num_args = etyde->num_flds;
|
||
eblock->data.flds = lccrt_ctx_mallocn( ctx, lccrt_einfo_handle_t, eblock->num_args);
|
||
memset( eblock->data.flds, 0, eblock->num_args*sizeof( eblock->data.flds[0]));
|
||
|
||
ehdl.type = LCCRT_EINFO_STRUCT;
|
||
ehdl.data.ref = eblock;
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_new_struct */
|
||
|
||
/**
|
||
* Установить значение элемента в массиве.
|
||
*/
|
||
void
|
||
lccrt_einfo_set_elem( lccrt_eir_t eref, int index, lccrt_eir_t value)
|
||
{
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_assert( (0 <= index) && (index < eblock->num_args));
|
||
lccrt_assert( ehdl.type == LCCRT_EINFO_ARRAY);
|
||
lccrt_assert( lccrt_einfo_is_value_assignable( eblock->tydescr->types[0], value));
|
||
eblock->data.elems[index] = lccrt_einfo_get_handle( value);
|
||
|
||
#if 0
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
elem_ident = (elem_ident < 0) ? eblock->num_args : elem_ident;
|
||
#endif
|
||
|
||
return;
|
||
} /* lccrt_einfo_set_elem */
|
||
|
||
/**
|
||
* Добавить значение в массив, увеличив его длину по необходимости.
|
||
*/
|
||
void
|
||
lccrt_einfo_push_elem( lccrt_eir_t eref, lccrt_eir_t value)
|
||
{
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
int num_args = eblock->num_args;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( eblock->tydescr->m);
|
||
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
lccrt_assert( eblock->type == LCCRT_EINFO_ARRAY);
|
||
lccrt_assert( (0 <= num_args) && (num_args <= eblock->max_args));
|
||
lccrt_assert( lccrt_einfo_is_value_assignable( eblock->tydescr->types[0], value));
|
||
|
||
if ( (num_args == eblock->max_args) )
|
||
{
|
||
lccrt_einfo_handle_t *new_data = 0;
|
||
|
||
if ( (eblock->max_args == 0) )
|
||
{
|
||
eblock->max_args = 4;
|
||
} else
|
||
{
|
||
eblock->max_args = 2*eblock->max_args;
|
||
}
|
||
|
||
new_data = lccrt_ctx_mallocn( ctx, lccrt_einfo_handle_t, eblock->max_args);
|
||
memcpy( new_data, eblock->data.elems, num_args*sizeof( new_data[0]));
|
||
memset( new_data + num_args, 0, (eblock->max_args - num_args)*sizeof( new_data[0]));
|
||
lccrt_ctx_free( ctx, eblock->data.elems);
|
||
eblock->data.elems = new_data;
|
||
}
|
||
|
||
eblock->data.elems[num_args] = lccrt_einfo_get_handle( value);
|
||
eblock->num_args++;
|
||
|
||
return;
|
||
} /* lccrt_einfo_push_elem */
|
||
|
||
/**
|
||
* Установить значение поля структуры.
|
||
*/
|
||
void
|
||
lccrt_einfo_set_field( lccrt_eir_t eref, lccrt_eifi_t eifi, lccrt_eir_t value)
|
||
{
|
||
int index = eifi.data[1];
|
||
lccrt_einfo_tydescr_ptr etyde = (lccrt_einfo_tydescr_ptr)eifi.data[0];
|
||
lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref);
|
||
lccrt_einfo_handle_t ehdl_value = lccrt_einfo_get_handle( value);
|
||
lccrt_einfo_block_ptr eblock = ehdl.data.ref;
|
||
|
||
lccrt_assert( eblock->tydescr == etyde);
|
||
lccrt_assert( (ehdl.type == LCCRT_EINFO_STRUCT) && (eblock->type == LCCRT_EINFO_STRUCT));
|
||
lccrt_assert( (0 <= eifi.data[1]) && (eifi.data[1] < eblock->num_args));
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
lccrt_assert( lccrt_einfo_is_value_assignable( eblock->tydescr->types[index], value));
|
||
|
||
eblock->data.flds[index] = ehdl_value;
|
||
|
||
return;
|
||
} /* lccrt_einfo_set_field */
|
||
|
||
/**
|
||
* Получить значение метаданных из цепочки привязки.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_einfo_link_get_value( lccrt_einfo_link_ptr elink)
|
||
{
|
||
lccrt_einfo_reference_t r;
|
||
|
||
if ( elink )
|
||
{
|
||
r = lccrt_einfo_get_reference( elink->value);
|
||
} else
|
||
{
|
||
lccrt_einfo_handle_t ehdl = {LCCRT_EINFO_NULL};
|
||
|
||
r = lccrt_einfo_get_reference( ehdl);
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_einfo_link_get_value */
|
||
|
||
/**
|
||
* Создать звено для цепочки привязки мета-данные.
|
||
*/
|
||
lccrt_einfo_link_ptr
|
||
lccrt_einfo_link_new( lccrt_m_ptr m, lccrt_eil_ptr elink0, lccrt_eic_t ecat, lccrt_eir_t value)
|
||
{
|
||
lccrt_einfo_link_ptr elink = 0;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( m);
|
||
|
||
elink = lccrt_ctx_malloc( ctx, lccrt_einfo_link_t);
|
||
memset( elink, 0, sizeof( elink[0]));
|
||
lccrt_check_type_init( elink, lccrt_einfo_link_t);
|
||
elink->next = elink0;
|
||
elink->ident = ecat;
|
||
elink->value = lccrt_einfo_get_handle( value);
|
||
|
||
return (elink);
|
||
} /* lccrt_einfo_link_new */
|
||
|
||
/**
|
||
* Поиск звена в цепочке привязки мета-данные по категории.
|
||
*/
|
||
lccrt_einfo_link_ptr
|
||
lccrt_einfo_link_find( lccrt_eil_ptr elink, lccrt_eic_t ecat)
|
||
{
|
||
while ( elink
|
||
&& (elink->ident.id != ecat.id) )
|
||
{
|
||
elink = elink->next;
|
||
}
|
||
|
||
return (elink);
|
||
} /* lccrt_einfo_link_find */
|
||
|
||
/**
|
||
* Добавить в цепочку привязки новые мета-данные, либо изменить значение старых.
|
||
*/
|
||
lccrt_einfo_link_ptr
|
||
lccrt_einfo_link_push_value( lccrt_m_ptr m, lccrt_eil_ptr elink0, lccrt_eic_t ecat, lccrt_eir_t value)
|
||
{
|
||
lccrt_einfo_link_ptr elink = lccrt_einfo_link_find( elink0, ecat);
|
||
|
||
if ( elink )
|
||
{
|
||
/* Мета-данные с таким именем уже существуют. */
|
||
elink->value = lccrt_einfo_get_handle( value);
|
||
} else
|
||
{
|
||
elink0 = lccrt_einfo_link_new( m, elink0, ecat, value);
|
||
}
|
||
|
||
return (elink0);
|
||
} /* lccrt_einfo_link_push_value */
|
||
|
||
/**
|
||
* Удалить звено цепочки привязки einfo-данных.
|
||
*/
|
||
void
|
||
lccrt_einfo_link_delete( lccrt_einfo_link_ptr elink)
|
||
{
|
||
if ( elink )
|
||
{
|
||
lccrt_einfo_block_ptr eblock = elink->value.data.ref;
|
||
|
||
lccrt_check_type_assert( elink, lccrt_einfo_link_t);
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
lccrt_check_type_assert( eblock->tydescr, lccrt_einfo_tydescr_t);
|
||
lccrt_check_type_done( elink, lccrt_einfo_link_t);
|
||
lccrt_ctx_free( lccrt_module_get_context( eblock->tydescr->m), elink);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_einfo_link_delete */
|
||
|
||
/**
|
||
* Удалить цепочку привязки einfo-данных.
|
||
*/
|
||
lccrt_einfo_link_ptr
|
||
lccrt_einfo_link_delete_chain( lccrt_einfo_link_ptr elink)
|
||
{
|
||
while ( elink )
|
||
{
|
||
lccrt_einfo_link_ptr next = elink->next;
|
||
|
||
lccrt_einfo_link_delete( elink);
|
||
elink = next;
|
||
}
|
||
|
||
return (0);
|
||
} /* lccrt_einfo_link_delete_chain */
|
||
|
||
/**
|
||
* Пронумеровать описание типов einfo-данных с помощью указанной хеш-таблицы.
|
||
*/
|
||
static uint64_t
|
||
lccrt_einfo_tydescr_number( uint64_t ident, lccrt_einfo_tydescr_ptr etyde, lccrt_hash_ptr tbl)
|
||
{
|
||
lccrt_hash_entry_ptr he;
|
||
int is_new = 0;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( etyde->m);
|
||
|
||
lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t);
|
||
he = lccrt_hash_push( tbl, (intptr_t)etyde, &is_new);
|
||
if ( !is_new )
|
||
{
|
||
intptr_t cur_ident = lccrt_hash_get( he);
|
||
|
||
if ( (cur_ident < 0) )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Recursive loop in extended information types descriptions");
|
||
}
|
||
} else
|
||
{
|
||
int64_t i;
|
||
|
||
lccrt_hash_set( he, (uintptr_t)(-1LL));
|
||
for ( i = 0; i < etyde->num_flds; ++i )
|
||
{
|
||
ident = lccrt_einfo_tydescr_number( ident, etyde->types[i], tbl);
|
||
}
|
||
|
||
he = lccrt_hash_find( tbl, (intptr_t)etyde);
|
||
lccrt_hash_set( he, (uintptr_t)ident);
|
||
++ident;
|
||
}
|
||
|
||
return (ident);
|
||
} /* lccrt_einfo_tydescr_number */
|
||
|
||
/**
|
||
* Пронумеровать поддерево метаданных с помощью указнной хеш-таблицы.
|
||
*/
|
||
static uint64_t
|
||
lccrt_einfo_block_number( uint64_t ident, lccrt_einfo_block_ptr eblock, lccrt_hash_ptr tbl)
|
||
{
|
||
lccrt_hash_entry_ptr he;
|
||
int is_new = 0;
|
||
lccrt_ctx_ptr ctx = lccrt_module_get_context( eblock->tydescr->m);
|
||
|
||
lccrt_check_type_assert( eblock, lccrt_einfo_block_t);
|
||
he = lccrt_hash_push( tbl, (intptr_t)eblock, &is_new);
|
||
if ( !is_new )
|
||
{
|
||
intptr_t cur_ident = lccrt_hash_get( he);
|
||
|
||
if ( (cur_ident < 0) )
|
||
{
|
||
lccrt_ctx_error( ctx, 0, "Recursive loop in extended information");
|
||
}
|
||
} else
|
||
{
|
||
int64_t i;
|
||
|
||
lccrt_hash_set( he, (uintptr_t)(-1LL));
|
||
if ( (eblock->type == LCCRT_EINFO_STRUCT)
|
||
|| (eblock->type == LCCRT_EINFO_UNION) )
|
||
{
|
||
for ( i = eblock->num_args - 1; i >= 0; --i )
|
||
{
|
||
lccrt_einfo_handle_t q = eblock->data.flds[i];
|
||
|
||
if ( (q.type == LCCRT_EINFO_STRUCT)
|
||
|| (q.type == LCCRT_EINFO_UNION)
|
||
|| (q.type == LCCRT_EINFO_ARRAY)
|
||
|| (q.type == LCCRT_EINFO_RAW) )
|
||
{
|
||
ident = lccrt_einfo_block_number( ident, q.data.ref, tbl);
|
||
}
|
||
}
|
||
} else if ( (eblock->type == LCCRT_EINFO_ARRAY) )
|
||
{
|
||
for ( i = eblock->num_args - 1; i >= 0; --i )
|
||
{
|
||
lccrt_einfo_handle_t q = eblock->data.elems[i];
|
||
|
||
if ( (q.type == LCCRT_EINFO_STRUCT)
|
||
|| (q.type == LCCRT_EINFO_UNION)
|
||
|| (q.type == LCCRT_EINFO_ARRAY)
|
||
|| (q.type == LCCRT_EINFO_RAW) )
|
||
{
|
||
ident = lccrt_einfo_block_number( ident, q.data.ref, tbl);
|
||
}
|
||
}
|
||
} else if ( (eblock->type == LCCRT_EINFO_RAW) )
|
||
{
|
||
} else
|
||
{
|
||
lccrt_assert( 0);
|
||
}
|
||
|
||
he = lccrt_hash_find( tbl, (intptr_t)eblock);
|
||
lccrt_hash_set( he, (uintptr_t)ident);
|
||
++ident;
|
||
}
|
||
|
||
return (ident);
|
||
} /* lccrt_einfo_block_number */
|
||
|
||
/**
|
||
* Для каждого узла дерева метаданных (STRUCT или ARRAY) провести нумерацию
|
||
* с помощью хеширования в указанной хеш-таблице.
|
||
*/
|
||
void
|
||
lccrt_module_einfo_number( lccrt_module_ptr m, lccrt_hash_ptr btbl, lccrt_hash_ptr ttbl)
|
||
{
|
||
lccrt_check_type_assert( m, lccrt_module_t);
|
||
|
||
// Нумеруем блоки.
|
||
if ( btbl )
|
||
{
|
||
lccrt_einfo_block_ptr unit;
|
||
uint64_t ident = 0;
|
||
|
||
for ( unit = m->eblocks_head; unit; unit = unit->next )
|
||
{
|
||
ident = lccrt_einfo_block_number( ident, unit, btbl);
|
||
}
|
||
}
|
||
|
||
// Нумеруем описания типов.
|
||
if ( ttbl )
|
||
{
|
||
lccrt_einfo_tydescr_ptr unit;
|
||
uint64_t ident = 0;
|
||
|
||
for ( unit = m->etydescrs_head; unit; unit = unit->next )
|
||
{
|
||
ident = lccrt_einfo_tydescr_number( ident, unit, ttbl);
|
||
}
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_module_einfo_number */
|