|
|
|
|
|
|
#include "global.h" |
#include <ctype.h> |
#include "svalue.h" |
#include "stralloc.h" |
#include "pike_types.h" |
#include "stuff.h" |
#include "array.h" |
#include "program.h" |
#include "constants.h" |
#include "object.h" |
#include "multiset.h" |
#include "mapping.h" |
#include "pike_macros.h" |
#include "pike_error.h" |
#include "las.h" |
#include "lex.h" |
#include "pike_memory.h" |
#include "bignum.h" |
#include "main.h" |
#include "opcodes.h" |
#include "cyclic.h" |
#include "gc.h" |
#include "pike_compiler.h" |
#include "block_allocator.h" |
#include "bitvector.h" |
|
#ifdef PIKE_DEBUG |
#define PIKE_TYPE_DEBUG |
#endif /* PIKE_DEBUG */ |
|
|
|
|
#define A_EXACT 1 |
#define B_EXACT 2 |
#define NO_MAX_ARGS 4 |
#define NO_SHORTCUTS 8 |
|
#define TYPE_GROUPING |
|
|
|
|
#define LE_WEAK_OBJECTS 1 /* Perform weaker checking of objects. */ |
#define LE_A_B_SWAPPED 2 /* Argument A and B have been swapped. |
* Relevant for markers. |
*/ |
#ifdef TYPE_GROUPING |
#define LE_A_GROUPED 4 /* Argument A has been grouped. |
* Perform weaker checking for OR-nodes. */ |
#define LE_B_GROUPED 8 /* Argument B has been grouped. |
* Perform weaker checking for OR-nodes. */ |
#define LE_A_B_GROUPED 12 /* Both the above two flags. */ |
#endif |
#define LE_USE_HANDLERS 16 /* Call handlers if appropriate. */ |
#define LE_EXPLICIT_ZERO 32 /* Zero is not subtype of all others. */ |
|
#define LE_STRICT_FUN 64 /* Require all arguments to functions. */ |
|
|
|
|
|
|
#define FILTER_KEEP_VOID 1 /* Keep void during the filtering. */ |
|
|
|
|
#define PT_COPY_CAR 1 |
#define PT_COPY_CDR 2 |
#define PT_COPY_BOTH 3 |
#define PT_IS_MARKER 4 /* The node is a marker. */ |
|
|
#define PIKE_TYPE_HASH_SIZE 65535 |
|
|
#ifdef PIKE_TYPE_DEBUG |
static int indent=0; |
#endif |
|
int max_correct_args; |
|
PMOD_EXPORT struct pike_type *string0_type_string; |
PMOD_EXPORT struct pike_type *string_type_string; |
PMOD_EXPORT struct pike_type *int_type_string; |
PMOD_EXPORT struct pike_type *float_type_string; |
PMOD_EXPORT struct pike_type *function_type_string; |
PMOD_EXPORT struct pike_type *object_type_string; |
PMOD_EXPORT struct pike_type *program_type_string; |
PMOD_EXPORT struct pike_type *array_type_string; |
PMOD_EXPORT struct pike_type *multiset_type_string; |
PMOD_EXPORT struct pike_type *mapping_type_string; |
PMOD_EXPORT struct pike_type *type_type_string; |
PMOD_EXPORT struct pike_type *mixed_type_string; |
PMOD_EXPORT struct pike_type *void_type_string; |
PMOD_EXPORT struct pike_type *zero_type_string; |
PMOD_EXPORT struct pike_type *inheritable_type_string; |
PMOD_EXPORT struct pike_type *typeable_type_string; |
PMOD_EXPORT struct pike_type *enumerable_type_string; |
PMOD_EXPORT struct pike_type *any_type_string; |
PMOD_EXPORT struct pike_type *weak_type_string; |
struct pike_type *sscanf_type_string; |
struct pike_type *sscanf_76_type_string; |
|
PMOD_EXPORT struct pike_string *literal_string_string; |
PMOD_EXPORT struct pike_string *literal_int_string; |
PMOD_EXPORT struct pike_string *literal_float_string; |
PMOD_EXPORT struct pike_string *literal_function_string; |
PMOD_EXPORT struct pike_string *literal_object_string; |
PMOD_EXPORT struct pike_string *literal_program_string; |
PMOD_EXPORT struct pike_string *literal_array_string; |
PMOD_EXPORT struct pike_string *literal_multiset_string; |
PMOD_EXPORT struct pike_string *literal_mapping_string; |
PMOD_EXPORT struct pike_string *literal_type_string; |
PMOD_EXPORT struct pike_string *literal_mixed_string; |
|
|
#ifdef DO_PIKE_CLEANUP |
struct pike_type_location *all_pike_type_locations = NULL; |
#endif /* DO_PIKE_CLEANUP */ |
|
static struct pike_type *a_markers[10], *b_markers[10]; |
|
static struct program *implements_a; |
static struct program *implements_b; |
static int implements_mode; |
|
#ifdef PIKE_DEBUG |
void TYPE_STACK_DEBUG(const char *UNUSED(fun)) |
{ |
#if 0 |
fprintf(stderr, "%25s(): stack_depth:%ld mark_stack_depth:%ld\n", |
fun, (long)(Pike_compiler->type_stackp - type_stack), |
(long)(Pike_compiler->pike_type_mark_stackp - pike_type_mark_stack)); |
#endif /* 0 */ |
} |
#endif /* PIKE_DEBUG */ |
|
static void clear_markers(void) |
{ |
unsigned int e; |
for(e=0;e<NELEM(a_markers);e++) |
{ |
if(a_markers[e]) |
{ |
free_type(a_markers[e]); |
a_markers[e]=0; |
} |
if(b_markers[e]) |
{ |
free_type(b_markers[e]); |
b_markers[e]=0; |
} |
} |
} |
|
static void low_discard_type (void) |
{ |
ptrdiff_t len = pop_stack_mark(); |
TYPE_STACK_DEBUG("discard_type"); |
for (;len > 0; len--) { |
|
free_type(*(Pike_compiler->type_stackp--)); |
} |
} |
|
void compiler_discard_type (void) |
{ |
low_discard_type(); |
type_stack_mark(); |
} |
|
struct pike_type *debug_pop_type(void) |
{ |
struct pike_type *t = pop_unfinished_type(); |
TYPE_STACK_DEBUG("pop_type"); |
type_stack_mark(); |
return t; |
} |
|
struct pike_type *debug_compiler_pop_type(void) |
{ |
TYPE_STACK_DEBUG("compiler_pop_type"); |
if(Pike_compiler->num_parse_error) |
{ |
struct pike_type *res; |
compiler_discard_type(); |
add_ref(res = any_type_string); |
return res; |
}else{ |
return debug_pop_type(); |
} |
} |
|
PMOD_EXPORT char *get_name_of_type(TYPE_T t) |
{ |
switch(t) |
{ |
case T_ARRAY: return "array"; |
case T_MAPPING: return "mapping"; |
case T_MULTISET: return "multiset"; |
case T_OBJECT: return "object"; |
case T_FUNCTION: return "function"; |
case T_PROGRAM: return "program"; |
case T_STRING: return "string"; |
case T_TYPE: return "type"; |
case T_INT: return "int"; |
case T_FLOAT: return "float"; |
case T_ZERO: return "zero"; |
case T_VOID: return "void"; |
case T_MIXED: return "mixed"; |
default: return "unknown"; |
|
#ifdef PIKE_DEBUG |
|
case T_UNFINISHED: return "T_UNFINISHED"; |
case T_MANY: return "T_MANY"; |
case PIKE_T_INT_UNTYPED: return "PIKE_T_INT_UNTYPED"; |
case PIKE_T_GET_SET: return "PIKE_T_GET_SET"; |
case PIKE_T_FREE: return "PIKE_T_FREE"; |
case PIKE_T_ATTRIBUTE: return "PIKE_T_ATTRIBUTE"; |
case PIKE_T_NSTRING: return "PIKE_T_NSTRING"; |
case PIKE_T_RING: return "PIKE_T_RING"; |
case PIKE_T_NAME: return "PIKE_T_NAME"; |
case PIKE_T_SCOPE: return "PIKE_T_SCOPE"; |
case PIKE_T_TUPLE: return "PIKE_T_TUPLE"; |
case T_ASSIGN: return "T_ASSIGN"; |
case T_DELETED: return "T_DELETED"; |
case PIKE_T_UNKNOWN: return "PIKE_T_UNKNOWN"; |
case T_OBJ_INDEX: return "T_OBJ_INDEX"; |
case T_SVALUE_PTR: return "T_SVALUE_PTR"; |
case T_ARRAY_LVALUE: return "T_ARRAY_LVALUE"; |
case T_NOT: return "T_NOT"; |
case T_AND: return "T_AND"; |
case T_OR: return "T_OR"; |
|
case T_STORAGE: return "object storage"; |
case T_MAPPING_DATA: return "mapping_data"; |
case T_PIKE_FRAME: return "pike_frame"; |
case T_MULTISET_DATA: return "multiset_data"; |
case T_STRUCT_CALLABLE: return "callable"; |
#endif |
} |
} |
|
|
#define TWOT(X,Y) (((X) << 8)+(Y)) |
|
static int low_pike_types_le(struct pike_type *a, struct pike_type *b, |
int array_cnt, unsigned int flags); |
static int low_check_indexing(struct pike_type *type, |
struct pike_type *index_type, |
node *n); |
static void internal_parse_type(const char **s); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct block_allocator type_allocator = BA_INIT(sizeof(struct pike_type), 128); |
|
PMOD_EXPORT void really_free_pike_type(struct pike_type * t) { |
ba_free(&type_allocator, t); |
} |
|
ATTRIBUTE((malloc)) |
PMOD_EXPORT struct pike_type * alloc_pike_type(void) { |
return ba_alloc(&type_allocator); |
} |
|
PMOD_EXPORT void count_memory_in_pike_types(size_t *n, size_t *s) { |
ba_count_all(&type_allocator, n, s); |
} |
|
struct pike_type **pike_type_hash = NULL; |
size_t pike_type_hash_size = 0; |
|
void debug_free_type(struct pike_type *t) |
{ |
#ifdef DEBUG_MALLOC |
if (t == (struct pike_type *)(size_t)0x55555555) { |
Pike_fatal("Freeing dead type.\n"); |
} |
#endif /* DEBUG_MALLOC */ |
loop: |
if (!sub_ref(t)) { |
unsigned INT32 hash = t->hash & pike_type_hash_size; |
struct pike_type **t2 = pike_type_hash + hash; |
struct pike_type *car, *cdr; |
unsigned INT32 type; |
#ifdef PIKE_DEBUG |
|
if (hash > pike_type_hash_size) { |
Pike_fatal("Modulo operation failed for hash:%u, index:%u, size:%u.\n", |
t->hash, hash, pike_type_hash_size); |
} |
|
#endif |
while (*t2) { |
if (*t2 == t) { |
*t2 = t->next; |
break; |
} |
t2 = &((*t2)->next); |
} |
|
car = t->car; |
cdr = t->cdr; |
type = t->type; |
|
really_free_pike_type((struct pike_type*)debug_malloc_pass(t)); |
|
|
switch(type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
|
free_type(car); |
t = (struct pike_type *) cdr; |
debug_free_type_preamble (t); |
goto loop; |
|
case T_ARRAY: |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
case T_STRING: |
|
t = (struct pike_type *) car; |
debug_free_type_preamble (t); |
goto loop; |
|
case T_SCOPE: |
case T_ASSIGN: |
|
t = (struct pike_type *) cdr; |
debug_free_type_preamble (t); |
goto loop; |
|
case PIKE_T_ATTRIBUTE: |
case PIKE_T_NAME: |
free_string((struct pike_string *)car); |
t = (struct pike_type *) cdr; |
debug_free_type_preamble (t); |
goto loop; |
|
#ifdef PIKE_DEBUG |
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
case PIKE_T_UNKNOWN: |
case T_INT: |
case T_OBJECT: |
break; |
|
default: |
Pike_fatal("free_type(): Unhandled type-node: %d\n", type); |
break; |
#endif /* PIKE_DEBUG */ |
} |
} |
} |
|
static inline struct pike_type *debug_mk_type(unsigned INT32 type, |
struct pike_type *car, |
struct pike_type *cdr, |
int flag_method) |
{ |
|
|
|
struct pike_type *t; |
unsigned INT32 index, |
hash = DO_NOT_WARN((unsigned INT32) |
((ptrdiff_t)type*0x10204081)^ |
(0x8003*PTR_TO_INT(car))^ |
~(0x10001*PTR_TO_INT(cdr))); |
|
hash ^= (hash >> 20) ^ (hash >> 12); |
hash ^= (hash >> 7) ^ (hash >> 4); |
|
index = hash & pike_type_hash_size; |
#ifdef PIKE_EXTRA_DEBUG |
static unsigned INT32 extra_debug_index = (unsigned INT32)~0; |
#endif /* PIKE_EXTRA_DEBUG */ |
#ifdef PIKE_DEBUG |
|
if (type & ~255) { |
|
|
|
|
|
|
|
Pike_fatal("Attempt to create an invalid type node: %d(%s)\n" |
" car: %p\n" |
" cdr: %p\n", |
type, get_name_of_type(type), |
car, cdr); |
} |
if (index > pike_type_hash_size) { |
Pike_fatal("Modulo operation failed for hash:%u, index:%u, " |
"size:%"PRINTSIZET"d.\n", |
hash, index, pike_type_hash_size); |
} |
|
#endif |
#ifdef PIKE_EXTRA_DEBUG |
if ((!~extra_debug_index) && |
(type == T_FUNCTION) && |
(car->type == T_STRING) && |
(cdr->type == T_FUNCTION) && |
(cdr->car->type == T_STRING) && |
(cdr->cdr->type == T_MANY) && |
(cdr->cdr->car->type == T_VOID) && |
(cdr->cdr->cdr->type == T_STRING)) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extra_debug_index = index; |
} |
#endif /* PIKE_EXTRA_DEBUG */ |
for(t = pike_type_hash[index]; t; t = t->next) { |
#ifdef PIKE_EXTRA_DEBUG |
if (index == extra_debug_index) { |
fprintf(stderr, |
" %s:%d:PIKE_EXTRA_DEBUG:\n" |
" t: %p\n", |
__FILE__, __LINE__, |
t); |
fprintf(stderr, |
" t->type:%d (%s)\n" |
" t->car: %p (%p)\n" |
" t->cdr: %p (%p)\n" |
" t->next:%p\n", |
t->type, get_name_of_type(t->type), |
t->car, car, |
t->cdr, cdr, |
t->next); |
} |
#endif /* PIKE_EXTRA_DEBUG */ |
if ((t->hash == hash) && (t->type == type) && |
(t->car == car) && (t->cdr == cdr)) { |
|
switch(type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
|
free_type((struct pike_type *)debug_malloc_pass(car)); |
free_type((struct pike_type *)debug_malloc_pass(cdr)); |
break; |
|
case T_ARRAY: |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
case T_STRING: |
|
free_type((struct pike_type *)debug_malloc_pass(car)); |
break; |
|
case T_SCOPE: |
case T_ASSIGN: |
|
free_type((struct pike_type *)debug_malloc_pass(cdr)); |
break; |
|
case PIKE_T_ATTRIBUTE: |
case PIKE_T_NAME: |
free_string((struct pike_string *)debug_malloc_pass(car)); |
free_type((struct pike_type *)debug_malloc_pass(cdr)); |
break; |
#ifdef PIKE_DEBUG |
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
case PIKE_T_UNKNOWN: |
case T_INT: |
case T_OBJECT: |
break; |
|
default: |
Pike_fatal("mk_type(): Unhandled type-node: %d\n", type); |
break; |
#endif /* PIKE_DEBUG */ |
} |
add_ref((struct pike_type *)debug_malloc_pass(t)); |
return t; |
} |
} |
|
#ifdef PIKE_DEBUG |
if ((type == T_OR) && (car->type == T_OR)) { |
Pike_fatal("Invalid CAR to OR node.\n"); |
} |
#endif |
|
debug_malloc_pass(t = ba_alloc(&type_allocator)); |
|
t->refs = 0; |
add_ref(t); |
t->type = type; |
t->flags = 0; |
t->car = car; |
t->cdr = cdr; |
|
t->hash = hash; |
t->next = pike_type_hash[index]; |
pike_type_hash[index] = t; |
|
if (flag_method) { |
if (flag_method == PT_IS_MARKER) { |
t->flags = PT_FLAG_MARKER_0 << (type-'0'); |
} else if (type == PIKE_T_SCOPE) { |
|
t->flags = cdr->flags & ~(PT_FLAG_MARKER|PT_FLAG_ASSIGN); |
} else { |
if (car && (flag_method & PT_COPY_CAR)) { |
t->flags |= car->flags; |
} |
if (cdr && (flag_method & PT_COPY_CDR)) { |
t->flags |= cdr->flags; |
} |
} |
} |
|
#ifdef DEBUG_MALLOC |
switch(type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
debug_malloc_pass(car); |
debug_malloc_pass(cdr); |
break; |
|
case T_ARRAY: |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
case T_STRING: |
debug_malloc_pass(car); |
break; |
|
case T_ASSIGN: |
t->flags |= PT_FLAG_ASSIGN_0 << PTR_TO_INT(car); |
|
case T_SCOPE: |
debug_malloc_pass(cdr); |
break; |
|
case PIKE_T_ATTRIBUTE: |
case PIKE_T_NAME: |
debug_malloc_pass(car); |
debug_malloc_pass(cdr); |
break; |
|
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
case PIKE_T_UNKNOWN: |
case T_INT: |
case T_OBJECT: |
break; |
|
default: |
Pike_fatal("mk_type(): Unhandled type-node: %d\n", type); |
break; |
} |
#else /* !DEBUG_MALLOC */ |
if (type == T_ASSIGN) { |
t->flags |= PT_FLAG_ASSIGN_0 << PTR_TO_INT(car); |
} |
#endif /* DEBUG_MALLOC */ |
|
return t; |
} |
|
#ifdef DEBUG_MALLOC |
#define mk_type(T,CAR,CDR,FLAG) ((struct pike_type *)debug_malloc_pass(debug_mk_type(T,CAR,CDR,FLAG))) |
#else /* !DEBUG_MALLOC */ |
#define mk_type debug_mk_type |
#endif /* DEBUG_MALLOC */ |
|
#ifdef PIKE_DEBUG |
void debug_check_type_string(struct pike_type *s) |
{ |
|
} |
|
#endif /* PIKE_DEBUG */ |
|
struct pike_type **type_stack; |
struct pike_type ***pike_type_mark_stack; |
|
ptrdiff_t pop_stack_mark(void) |
{ |
Pike_compiler->pike_type_mark_stackp--; |
if(Pike_compiler->pike_type_mark_stackp<pike_type_mark_stack) |
Pike_fatal("Type mark stack underflow\n"); |
|
TYPE_STACK_DEBUG("pop_stack_mark"); |
|
return Pike_compiler->type_stackp - *Pike_compiler->pike_type_mark_stackp; |
} |
|
void type_stack_pop_to_mark(void) |
{ |
pop_stack_mark(); |
while(Pike_compiler->type_stackp > *Pike_compiler->pike_type_mark_stackp) { |
free_type(*(Pike_compiler->type_stackp--)); |
} |
|
TYPE_STACK_DEBUG("type_stack_pop_to_mark"); |
} |
|
struct pike_type *debug_peek_type_stack(void) |
{ |
return *(Pike_compiler->type_stackp); |
} |
|
void debug_push_int_type(INT_TYPE min, INT_TYPE max) |
{ |
#if SIZEOF_INT_TYPE > 4 |
|
|
if (min<MIN_INT32) min=MIN_INT32; |
else if (min>MAX_INT32) min=MAX_INT32; |
if (max<MIN_INT32) max=MIN_INT32; |
else if (max>MAX_INT32) max=MAX_INT32; |
#endif |
|
#ifdef PIKE_DEBUG /* FIXME: Kludge to support 2^32-1 */ |
if (((min>0 && max>0) || (min<0 && max<0)) && min > max) |
Pike_fatal("push_int_type(): Bad integer range:" |
" min:%"PRINTPIKEINT"d, max:%"PRINTPIKEINT"d.\n", |
min, max); |
#endif /* PIKE_DEBUG */ |
|
if (!min && !max) { |
|
push_type(T_ZERO); |
} else { |
*(++Pike_compiler->type_stackp) = mk_type(T_INT, |
(void *)(ptrdiff_t)min, |
(void *)(ptrdiff_t)max, 0); |
} |
TYPE_STACK_DEBUG("push_int_type"); |
} |
|
static int (*program_id_to_id)(int) = NULL; |
|
PMOD_EXPORT void set_program_id_to_id( int (*to)(int) ) |
{ |
program_id_to_id = to; |
} |
|
void debug_push_object_type(int flag, INT32 id) |
{ |
if( program_id_to_id ) |
id = program_id_to_id(id); |
*(++Pike_compiler->type_stackp) = mk_type(T_OBJECT, |
(void *)(ptrdiff_t)flag, |
(void *)(ptrdiff_t)id, 0); |
|
TYPE_STACK_DEBUG("push_object_type"); |
} |
|
void debug_push_object_type_backwards(int flag, INT32 id) |
{ |
push_object_type(flag, id); |
} |
|
void debug_push_scope_type(int level) |
{ |
*Pike_compiler->type_stackp = mk_type(T_SCOPE, |
(void *)(ptrdiff_t)level, |
*Pike_compiler->type_stackp, |
PT_COPY_CDR); |
|
TYPE_STACK_DEBUG("push_scope_type"); |
} |
|
void debug_push_assign_type(int marker) |
{ |
marker -= '0'; |
#ifdef PIKE_DEBUG |
if ((marker < 0) || (marker > 9)) { |
Pike_fatal("Bad assign marker: %d\n", marker); |
} |
#endif /* PIKE_DEBUG */ |
|
*Pike_compiler->type_stackp = mk_type(T_ASSIGN, |
(void *)(ptrdiff_t)marker, |
*Pike_compiler->type_stackp, |
PT_COPY_CDR); |
TYPE_STACK_DEBUG("push_assign_type"); |
} |
|
void debug_push_type_attribute(struct pike_string *attr) |
{ |
|
add_ref(attr); |
*Pike_compiler->type_stackp = mk_type(PIKE_T_ATTRIBUTE, |
(void *)attr, |
*Pike_compiler->type_stackp, |
PT_COPY_CDR); |
TYPE_STACK_DEBUG("push_type_name"); |
} |
|
void debug_push_type_name(struct pike_string *name) |
{ |
|
add_ref(name); |
*Pike_compiler->type_stackp = mk_type(PIKE_T_NAME, |
(void *)name, |
*Pike_compiler->type_stackp, |
PT_COPY_CDR); |
TYPE_STACK_DEBUG("push_type_name"); |
} |
|
void debug_push_finished_type(struct pike_type *t) |
{ |
copy_pike_type(*(++Pike_compiler->type_stackp), t); |
|
TYPE_STACK_DEBUG("push_finished_type"); |
} |
|
static void push_reverse_joiner_type(unsigned int type) |
{ |
|
|
switch(type) { |
case T_OR: |
case T_AND: |
|
if (Pike_compiler->type_stackp[-1] == Pike_compiler->type_stackp[0]) { |
free_type(*(Pike_compiler->type_stackp--)); |
return; |
} |
|
--Pike_compiler->type_stackp; |
#ifdef PIKE_DEBUG |
if ((*Pike_compiler->type_stackp)->type == type) { |
Pike_fatal("Invalid CAR to push_reverse_joiner_type().\n"); |
} |
#endif /* PIKE_DEBUG */ |
*Pike_compiler->type_stackp = mk_type(type, |
*Pike_compiler->type_stackp, |
*(Pike_compiler->type_stackp+1), |
PT_COPY_BOTH); |
break; |
default: |
Pike_fatal("Illegal reverse joiner type: %d\n", type); |
} |
} |
|
static void low_or_pike_types(struct pike_type *t1, |
struct pike_type *t2, |
int zero_implied); |
|
void debug_push_type(unsigned int type) |
{ |
|
|
switch(type) { |
case T_OR: |
case T_AND: |
|
if (Pike_compiler->type_stackp[-1] == Pike_compiler->type_stackp[0]) { |
free_type(*(Pike_compiler->type_stackp--)); |
return; |
} |
if (Pike_compiler->type_stackp[0]->type == type) { |
|
|
|
struct pike_type *top = *(Pike_compiler->type_stackp--); |
push_finished_type(top->cdr); |
push_type(type); |
push_finished_type(top->car); |
push_type(type); |
free_type(top); |
return; |
} |
if (type == T_OR) { |
struct pike_type *t1 = *(Pike_compiler->type_stackp--); |
struct pike_type *t2 = *(Pike_compiler->type_stackp--); |
low_or_pike_types(t1, t2, 0); |
free_type(t2); |
free_type(t1); |
return; |
} |
|
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case PIKE_T_RING: |
|
--Pike_compiler->type_stackp; |
*Pike_compiler->type_stackp = mk_type(type, |
*(Pike_compiler->type_stackp+1), |
*Pike_compiler->type_stackp, |
PT_COPY_BOTH); |
break; |
|
case T_PROGRAM: |
if ((*Pike_compiler->type_stackp)->type != T_OBJECT) { |
struct pike_type *t = (*Pike_compiler->type_stackp); |
while ((t->type == PIKE_T_NAME) || (t->type == PIKE_T_ATTRIBUTE)) { |
t = t->cdr; |
} |
if (t->type != T_OBJECT) { |
|
type = T_TYPE; |
} |
} |
|
case T_ARRAY: |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_STRING: |
|
*Pike_compiler->type_stackp = mk_type(type, |
*Pike_compiler->type_stackp, NULL, |
PT_COPY_CAR); |
break; |
|
case T_SCOPE: |
case T_ASSIGN: |
case T_INT: |
case T_OBJECT: |
case PIKE_T_ATTRIBUTE: |
case PIKE_T_NAME: |
default: |
|
Pike_fatal("Unsupported argument to push_type(): %d\n", type); |
break; |
|
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
case PIKE_T_UNKNOWN: |
|
*(++Pike_compiler->type_stackp) = mk_type(type, NULL, NULL, 0); |
break; |
|
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
|
*(++Pike_compiler->type_stackp) = mk_type(type, NULL, NULL, PT_IS_MARKER); |
break; |
} |
|
TYPE_STACK_DEBUG("push_type"); |
} |
|
|
void debug_pop_type_stack(unsigned int expected) |
{ |
struct pike_type *top; |
if(Pike_compiler->type_stackp<type_stack) |
Pike_fatal("Type stack underflow\n"); |
|
top = *(Pike_compiler->type_stackp); |
|
if ((top->type == T_MIXED) || |
((top == any_type_string) && (expected != T_OR))) { |
|
return; |
} |
|
Pike_compiler->type_stackp--; |
#ifdef PIKE_DEBUG |
if ((top->type != expected) && |
(top->type != PIKE_T_NAME) && |
(top->type != PIKE_T_ATTRIBUTE)) { |
Pike_fatal("Unexpected type on stack: %d (expected %d)\n", top->type, expected); |
} |
#endif /* PIKE_DEBUG */ |
|
* expected == T_ARRAY. |
*/ |
switch(top->type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
|
push_finished_type(top->cdr); |
push_finished_type(top->car); |
break; |
case T_ARRAY: |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
case T_STRING: |
|
push_finished_type(top->car); |
break; |
case T_SCOPE: |
case T_ASSIGN: |
|
push_finished_type(top->cdr); |
break; |
case T_INT: |
case T_OBJECT: |
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
case PIKE_T_UNKNOWN: |
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
|
break; |
case PIKE_T_ATTRIBUTE: |
case PIKE_T_NAME: |
|
push_finished_type(top->cdr); |
pop_type_stack(expected); |
break; |
default: |
Pike_error("pop_type_stack(): Unhandled node type: %d\n", top->type); |
} |
free_type(top); |
|
TYPE_STACK_DEBUG("pop_type_stack"); |
} |
|
void debug_push_reverse_type(unsigned int type) |
{ |
|
|
switch(type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
{ |
|
struct pike_type *tmp = Pike_compiler->type_stackp[0]; |
Pike_compiler->type_stackp[0] = Pike_compiler->type_stackp[-1]; |
Pike_compiler->type_stackp[-1] = tmp; |
break; |
} |
} |
push_type(type); |
|
TYPE_STACK_DEBUG("push_reverse_type"); |
} |
|
static int is_int_type(struct pike_type *t) |
{ |
loop: |
switch(t->type) { |
case T_INT: |
case T_ZERO: |
case T_VOID: |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
return 1; |
case T_OR: |
case T_AND: |
return is_int_type(t->car) && is_int_type(t->cdr); |
case PIKE_T_NAME: |
case PIKE_T_ATTRIBUTE: |
case PIKE_T_SCOPE: |
case T_ASSIGN: |
t = t->cdr; |
goto loop; |
default: |
return 0; |
} |
} |
|
|
|
|
|
|
|
|
|
static void debug_push_finished_type_with_markers(struct pike_type *type, |
struct pike_type **markers, |
INT32 marker_set) |
{ |
INT32 car_set, cdr_set; |
recurse: |
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "push_finished_type_with_markers(("); |
simple_describe_type(type); |
fprintf(stderr, "),..., 0x%08x)...\n", marker_set); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
|
* non-masked assign. |
*/ |
if (!(type->flags & (~marker_set | PT_FLAG_MARKER) & PT_FLAG_MARK_ASSIGN)) { |
|
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Nothing to replace in this subtree.\n"); |
simple_describe_type(type); |
fprintf(stderr, "\n"); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
if ((marker_set & PT_FLAG_INT_ONLY) && !is_int_type(type)) { |
push_finished_type(int_type_string); |
} else { |
push_finished_type(type); |
} |
return; |
} |
if ((type->type >= '0') && (type->type <= '9')) { |
|
unsigned int m = type->type - '0'; |
#ifdef PIKE_TYPE_DEBUG |
if ((l_flag > 2) && m) { |
fprintf(stderr, "Marker %d: %p.\n", m, markers[m]); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
if (markers[m]) { |
|
struct pike_type *type = dmalloc_touch(struct pike_type *, markers[m]); |
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Marker value.\n"); |
} |
#endif |
|
markers[m] = NULL; |
push_finished_type_with_markers(type, markers, |
marker_set & PT_FLAG_INT_ONLY); |
if (type->flags & (PT_FLAG_MARKER|PT_FLAG_ASSIGN)) { |
push_scope_type(0); |
} |
if (markers[m]) free_type(markers[m]); |
markers[m] = dmalloc_touch(struct pike_type *, type); |
} else { |
|
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "No marker value.\n"); |
} |
#endif |
} |
if (marker_set & (PT_FLAG_MARKER_0 << m)) { |
|
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Keep marker.\n"); |
} |
#endif |
push_type(type->type); |
if (markers[m]) push_type(T_OR); |
} else if (!markers[m]) { |
push_type(T_ZERO); |
} |
TYPE_STACK_DEBUG("push_finished_type_with_markers"); |
return; |
} else if (type->type == T_ASSIGN) { |
|
int marker = PTR_TO_INT(type->car); |
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Assign to marker %"PRINTPTRDIFFT"d.\n", |
CAR_TO_INT(type)); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
if (marker_set & (PT_FLAG_ASSIGN_0 << marker)) { |
|
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Keep assignment.\n"); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
|
push_finished_type_with_markers(type->cdr, markers, |
marker_set & |
~(PT_FLAG_ASSIGN_0 << marker)); |
push_assign_type('0' + marker); |
TYPE_STACK_DEBUG("push_finished_type_with_markers"); |
return; |
} else { |
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Strip assignment.\n"); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
type = type->cdr; |
goto recurse; |
} |
} else if (type->type == PIKE_T_NAME) { |
|
type = type->cdr; |
goto recurse; |
} else if (type->type == PIKE_T_ATTRIBUTE) { |
|
push_finished_type_with_markers(type->cdr, markers, marker_set); |
push_type_attribute((struct pike_string *)type->car); |
goto done; |
} |
|
|
if (type->car) { |
|
cdr_set = marker_set | |
((type->car->flags & PT_FLAG_ASSIGN)>>PT_ASSIGN_SHIFT); |
} else { |
cdr_set = marker_set; |
} |
if (type->cdr) { |
|
car_set = marker_set | |
((type->cdr->flags & PT_FLAG_MARKER)<<PT_ASSIGN_SHIFT); |
} else { |
car_set = marker_set; |
} |
|
if ((type->type == T_OR) || (type->type == T_AND)) { |
|
|
|
|
|
type_stack_mark(); |
|
push_finished_type_with_markers(type->cdr, markers, cdr_set); |
if (type->type == T_OR) { |
struct pike_type *first = pop_type(); |
struct pike_type *second; |
struct pike_type *res; |
push_finished_type_with_markers(type->car, markers, car_set); |
second = pop_unfinished_type(); |
push_finished_type(res = or_pike_types(first, second, 1)); |
free_type(second); |
free_type(first); |
free_type(res); |
} else if (peek_type_stack() == zero_type_string) { |
pop_stack_mark(); |
} else { |
type_stack_mark(); |
push_finished_type_with_markers(type->car, markers, car_set); |
if (peek_type_stack() == zero_type_string) { |
free_type(pop_unfinished_type()); |
free_type(pop_unfinished_type()); |
push_finished_type(zero_type_string); |
} else { |
pop_stack_mark(); |
pop_stack_mark(); |
push_type(T_AND); |
} |
} |
} else { |
if (type->cdr) { |
|
push_finished_type_with_markers(type->cdr, markers, cdr_set); |
} |
|
|
|
if (type->type == PIKE_T_STRING) car_set |= PT_FLAG_INT_ONLY; |
|
push_finished_type_with_markers(type->car, markers, car_set); |
|
push_type(type->type); |
} |
done: |
TYPE_STACK_DEBUG("push_finished_type_with_markers"); |
} |
|
static void push_type_field(TYPE_FIELD field) |
{ |
field &= (BIT_BASIC|BIT_COMPLEX); |
if (!field) { |
|
push_type(T_ZERO); |
} else if (field == (BIT_BASIC|BIT_COMPLEX)) { |
|
push_type(T_MIXED); |
} else { |
|
push_type(T_ZERO); |
|
if (field & BIT_COMPLEX) { |
if (field & BIT_ARRAY) { |
push_type(T_MIXED); |
push_type(T_ARRAY); |
push_type(T_OR); |
} |
if (field & BIT_MAPPING) { |
push_type(T_MIXED); |
push_type(T_MIXED); |
push_type(T_MAPPING); |
push_type(T_OR); |
} |
if (field & BIT_MULTISET) { |
push_type(T_MIXED); |
push_type(T_MULTISET); |
push_type(T_OR); |
} |
if (field & BIT_OBJECT) { |
push_object_type(0, 0); |
push_type(T_OR); |
} |
if (field & BIT_FUNCTION) { |
push_type(T_ZERO); |
push_type(T_ZERO); |
push_type(T_MIXED); |
push_type(T_OR); |
push_type(T_MANY); |
push_type(T_OR); |
} |
if (field & BIT_PROGRAM) { |
push_object_type(0, 0); |
push_type(T_PROGRAM); |
push_type(T_OR); |
} |
} |
if (field & BIT_BASIC) { |
if (field & BIT_STRING) { |
push_int_type(MIN_INT32, MAX_INT32); |
push_type(T_STRING); |
push_type(T_OR); |
} |
if (field & BIT_TYPE) { |
push_type(T_MIXED); |
push_type(T_TYPE); |
push_type(T_OR); |
} |
if (field & BIT_INT) { |
push_int_type(MIN_INT32, MAX_INT32); |
push_type(T_OR); |
} |
if (field & BIT_FLOAT) { |
push_type(T_FLOAT); |
push_type(T_OR); |
} |
} |
} |
} |
|
INT32 extract_type_int(char *p) |
{ |
return get_unaligned_be32(p); |
} |
|
struct pike_type *debug_pop_unfinished_type(void) |
{ |
ptrdiff_t len; |
|
len = pop_stack_mark(); |
|
if (len != 1) { |
Pike_fatal("pop_unfinished_type(): Unexpected len: %"PRINTPTRDIFFT"d\n", len); |
} |
|
TYPE_STACK_DEBUG("pop_unfinished_type"); |
|
return *(Pike_compiler->type_stackp--); |
} |
|
|
|
static struct pike_string *internal_parse_type_string(const char **_s) |
{ |
const unsigned char **s = (const unsigned char **)_s; |
const unsigned char *p; |
struct string_builder tmp; |
while(isspace(**s)) ++*s; |
if(**s != '\"') yyerror("Expected '\"'."); |
else |
++*s; |
init_string_builder(&tmp, 0); |
p = *s; |
while(1) { |
int c; |
do { |
c = *p++; |
} while ((c > '\\') || ((c != '\"') && (c != '\\') && (c != '\n'))); |
string_builder_binary_strcat(&tmp, *_s, p - (1 + *s)); |
if (c == '"') { |
*s = ++p; |
break; |
} else if (c == '\\') { |
p_wchar2 buf; |
ptrdiff_t len = 0; |
if (!parse_esc_seq0((p_wchar0 *)p, &buf, &len)) { |
string_builder_putchar(&tmp, buf); |
p += len; |
} else { |
yyerror("Invalid \\-escape."); |
} |
} else { |
yyerror("Expected '\"'."); |
break; |
} |
*s = p; |
} |
return finish_string_builder(&tmp); |
} |
|
static void internal_parse_typeA(const char **_s) |
{ |
char buf[80]; |
unsigned int len; |
const unsigned char **s = (const unsigned char **)_s; |
|
while(isspace(**s)) ++*s; |
|
for(len=0;isidchar(EXTRACT_UCHAR(s[0]+len));len++) |
{ |
if(len>=sizeof(buf)-1) { |
my_yyerror("Buffer overflow in parse_type(\"%s\") (limit %"PRINTSIZET"d).", |
*s, sizeof(buf)); |
push_type(T_MIXED); |
return; |
} |
buf[len] = s[0][len]; |
} |
buf[len]=0; |
*s += len; |
|
switch(buf[0]) |
{ |
case 'z': |
if(!strcmp(buf,"zero")) { push_type(T_ZERO); break; } |
goto bad_type; |
|
case 'i': |
if(!strcmp(buf,"int")) |
{ |
while(isspace(**s)) ++*s; |
if(**s=='(') |
{ |
INT32 min,max; |
++*s; |
while(isspace(**s)) ++*s; |
if (**s != '.') { |
min=strtol((const char *)*s,(char **)s,0); |
while(isspace(**s)) ++*s; |
} else { |
min = MIN_INT32; |
} |
if(s[0][0]=='.' && s[0][1]=='.') |
s[0]+=2; |
else { |
yyerror("Missing .. in integer type."); |
} |
|
while(isspace(**s)) ++*s; |
if (**s != ')') { |
max=strtol((const char *)*s,(char **)s,0); |
while(isspace(**s)) ++*s; |
} else { |
max = MAX_INT32; |
} |
|
if(**s != ')') yyerror("Missing ')' in integer range."); |
else |
++*s; |
push_int_type(min, max); |
}else{ |
push_int_type(MIN_INT32, MAX_INT32); |
} |
break; |
} |
goto bad_type; |
|
case 'f': |
if(!strcmp(buf,"function")) |
{ |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
int nargs = 0; |
++*s; |
while(isspace(**s)) ++*s; |
while(1) |
{ |
if(**s == ':') |
{ |
push_type(T_VOID); |
break; |
} |
internal_parse_type(_s); |
if(**s==',') |
{ |
nargs++; |
++*s; |
while(isspace(**s)) ++*s; |
} |
else if(s[0][0]=='.' && s[0][1]=='.' && s[0][2]=='.') |
{ |
*s+=3; |
while(isspace(**s)) ++*s; |
if(**s != ':') { |
yyerror("Missing ':' after ... in function type."); |
--*s; |
} |
break; |
} else { |
nargs++; |
} |
} |
|
++*s; |
internal_parse_type(_s); |
push_reverse_type(T_MANY); |
|
while (nargs-- > 0) { |
push_reverse_type(T_FUNCTION); |
} |
|
if(**s != ')') yyerror("Missing ')' in function type."); |
else |
++*s; |
}else{ |
push_type(T_VOID); |
push_type(T_MIXED); |
push_type(T_OR); |
push_type(T_VOID); |
push_type(T_ZERO); |
push_type(T_OR); |
push_type(T_MANY); |
} |
break; |
} |
if(!strcmp(buf,"float")) { push_type(T_FLOAT); break; } |
goto bad_type; |
|
case 'o': |
if(!strcmp(buf,"object")) |
{ |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
int is = 0, id; |
++*s; |
while(isspace(**s)) ++*s; |
if( **s != 'i' ) |
goto no_is_implements; |
++*s; |
if( **s == 's' ) { |
++*s; |
if (**s != ' ') { |
goto bad_type; |
} |
is = 1; |
++*s; |
} else { |
if (strncmp((const char *)*s, "mplements ", 10)) { |
goto bad_type; |
} |
*s += 10; |
} |
while(isspace(**s)) ++*s; |
no_is_implements: |
if( !**s ) |
goto bad_type; |
if (!strncmp((const char *)*s, "this_program", 12)) { |
id = Pike_compiler->new_program->id; |
*s += 12; |
} else { |
id = atoi( (const char *)*s ); |
while( **s >= '0' && **s <= '9' ) |
++*s; |
} |
while(isspace(**s)) ++*s; |
if( !**s || **s != ')' ) |
goto bad_type; |
++*s; |
push_object_type(is, id); |
} |
else |
push_object_type(0, 0); |
break; |
} |
goto bad_type; |
|
|
case 'p': |
if(!strcmp(buf,"program")) { |
push_object_type(0, 0); |
push_type(T_PROGRAM); |
break; |
} |
goto bad_type; |
|
|
case 's': |
if(!strcmp(buf,"string")) { |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
INT32 min,max; |
++*s; |
while(isspace(**s)) ++*s; |
if (**s != '.') { |
min=strtol((const char *)*s,(char **)s,0); |
while(isspace(**s)) ++*s; |
} else { |
min = MIN_INT32; |
} |
if(s[0][0]=='.' && s[0][1]=='.') |
s[0]+=2; |
else { |
yyerror("Missing .. in integer type."); |
} |
|
while(isspace(**s)) ++*s; |
if (**s != ')') { |
max=strtol((const char *)*s,(char **)s,0); |
while(isspace(**s)) ++*s; |
} else { |
max = MAX_INT32; |
} |
if(**s != ')') yyerror("Missing ')' in string width."); |
else |
++*s; |
push_int_type(min, max); |
} else { |
push_finished_type(int_type_string); |
} |
push_type(T_STRING); |
break; |
} |
goto bad_type; |
|
case 'v': |
if(!strcmp(buf,"void")) { push_type(T_VOID); break; } |
goto bad_type; |
|
case 't': |
if (!strcmp(buf,"tuple")) |
{ |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
++*s; |
internal_parse_type(_s); |
if(**s != ',') yyerror("Expected ','."); |
else |
++*s; |
internal_parse_type(_s); |
if(**s != ')') yyerror("Expected ')'."); |
else |
++*s; |
}else{ |
push_type(T_MIXED); |
push_type(T_MIXED); |
} |
push_reverse_type(T_TUPLE); |
break; |
} |
|
if(!strcmp(buf,"type")) { push_type(T_MIXED); push_type(T_TYPE); break; } |
goto bad_type; |
|
case 'm': |
if(!strcmp(buf,"mixed")) { push_type(T_MIXED); break; } |
if(!strcmp(buf,"mapping")) |
{ |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
++*s; |
internal_parse_type(_s); |
if(**s != ':') yyerror("Expected ':'."); |
else |
++*s; |
internal_parse_type(_s); |
if(**s != ')') yyerror("Expected ')'."); |
else |
++*s; |
}else{ |
push_type(T_MIXED); |
push_type(T_MIXED); |
} |
push_reverse_type(T_MAPPING); |
break; |
} |
if(!strcmp(buf,"multiset")) |
{ |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
++*s; |
internal_parse_type(_s); |
if(**s != ')') yyerror("Expected ')'."); |
else |
++*s; |
}else{ |
push_type(T_MIXED); |
} |
push_type(T_MULTISET); |
break; |
} |
goto bad_type; |
|
case 'u': |
if(!strcmp(buf,"unknown")) { push_type(PIKE_T_UNKNOWN); break; } |
goto bad_type; |
|
case 'a': |
if(!strcmp(buf,"array")) |
{ |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
++*s; |
internal_parse_type(_s); |
if(**s != ')') yyerror("Expected ')'."); |
else |
++*s; |
}else{ |
push_type(T_MIXED); |
} |
push_type(T_ARRAY); |
break; |
} |
goto bad_type; |
|
case '_': |
if (!strcmp(buf, "__attribute__")) { |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
struct pike_string *attr; |
++*s; |
attr = internal_parse_type_string(_s); |
while(isspace(**s)) ++*s; |
if(**s != ',') yyerror("Expected ','."); |
else |
++*s; |
internal_parse_type(_s); |
if(**s != ')') yyerror("Expected ')'."); |
else |
++*s; |
push_type_attribute(attr); |
free_string(attr); |
}else{ |
push_type(T_MIXED); |
} |
break; |
} else if (!strcmp(buf, "__deprecated__")) { |
struct pike_string *deprecated_string; |
MAKE_CONST_STRING(deprecated_string, "deprecated"); |
while(isspace(**s)) ++*s; |
if(**s == '(') |
{ |
++*s; |
internal_parse_type(_s); |
if(**s != ')') yyerror("Expected ')'."); |
else |
++*s; |
}else{ |
push_type(T_MIXED); |
} |
push_type_attribute(deprecated_string); |
free_string(deprecated_string); |
break; |
} |
goto bad_type; |
|
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
if(atoi(buf)<10) |
{ |
while(isspace(**s)) ++*s; |
if(**s=='=') |
{ |
++*s; |
internal_parse_type(_s); |
push_assign_type(buf[0]); |
}else{ |
push_type(buf[0]); |
} |
break; |
} |
|
default: |
bad_type: |
push_type(T_MIXED); |
my_yyerror("Couldn't parse type. (%s).", buf); |
} |
|
while(isspace(**s)) ++*s; |
} |
|
|
static void internal_parse_typeB(const char **s) |
{ |
while(isspace(EXTRACT_UCHAR(*s))) ++*s; |
switch(**s) |
{ |
case '!': |
++*s; |
internal_parse_typeB(s); |
push_type(T_NOT); |
break; |
|
case '(': |
++*s; |
internal_parse_type(s); |
while(isspace(EXTRACT_UCHAR(*s))) ++*s; |
if(**s != ')') { |
yyerror("Expected ')' in type."); |
} |
++*s; |
break; |
|
default: |
|
internal_parse_typeA(s); |
} |
} |
|
static void internal_parse_typeCC(const char **s) |
{ |
internal_parse_typeB(s); |
|
while(isspace(EXTRACT_UCHAR(*s))) ++*s; |
|
while(**s == '*') |
{ |
++*s; |
while(isspace(EXTRACT_UCHAR(*s))) ++*s; |
push_type(T_ARRAY); |
} |
} |
|
static void internal_parse_typeC(const char **s) |
{ |
internal_parse_typeCC(s); |
|
if(**s == '&') |
{ |
++*s; |
internal_parse_typeC(s); |
push_reverse_type(T_AND); |
} |
} |
|
static void internal_parse_type(const char **s) |
{ |
internal_parse_typeC(s); |
|
while(**s == '|') |
{ |
++*s; |
internal_parse_typeC(s); |
push_type(T_OR); |
} |
} |
|
|
|
|
|
|
struct pike_type *parse_type(const char *s) |
{ |
struct pike_type *ret; |
#ifdef PIKE_DEBUG |
struct pike_type **ts=Pike_compiler->type_stackp; |
struct pike_type ***ptms=Pike_compiler->pike_type_mark_stackp; |
#endif |
|
|
|
TYPE_STACK_DEBUG("parse_type"); |
|
type_stack_mark(); |
|
internal_parse_type(&s); |
|
if( *s ) |
yyerror("Extra junk at end of type definition."); |
|
ret=pop_unfinished_type(); |
|
#ifdef PIKE_DEBUG |
if(ts!=Pike_compiler->type_stackp || ptms!=Pike_compiler->pike_type_mark_stackp) |
Pike_fatal("Type stack whacked in parse_type.\n"); |
#endif |
|
return ret; |
} |
|
#ifdef PIKE_DEBUG |
|
void stupid_describe_type_string(char *a, ptrdiff_t len) |
{ |
ptrdiff_t e; |
for(e=0;e<len;e++) |
{ |
if(e) fprintf(stderr, " "); |
switch(EXTRACT_UCHAR(a+e)) |
{ |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
fprintf(stderr, "%c",EXTRACT_UCHAR(a+e)); |
break; |
|
case T_SCOPE: fprintf(stderr, "scope"); break; |
case T_TUPLE: fprintf(stderr, "tuple"); break; |
case T_ASSIGN: fprintf(stderr, "="); break; |
case T_INT: |
{ |
INT32 min=extract_type_int(a+e+1); |
INT32 max=extract_type_int(a+e+1+sizeof(INT32)); |
fprintf(stderr, "int"); |
if(min!=MIN_INT32 || max!=MAX_INT32) { |
if (!min && max && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
fprintf(stderr, "(%dbit)", j); |
} else { |
fprintf(stderr, "(%ld..%ld)",(long)min,(long)max); |
} |
} |
e+=sizeof(INT32)*2; |
break; |
} |
case T_FLOAT: fprintf(stderr, "float"); break; |
case T_STRING: fprintf(stderr, "string"); break; |
case T_TYPE: fprintf(stderr, "type"); break; |
case T_PROGRAM: fprintf(stderr, "program"); break; |
case T_OBJECT: |
fprintf(stderr, "object(%s %ld)", |
EXTRACT_UCHAR(a+e+1)?"is":"implements", |
(long)extract_type_int(a+e+2)); |
e+=sizeof(INT32)+1; |
break; |
case T_FUNCTION: fprintf(stderr, "function"); break; |
case T_ARRAY: fprintf(stderr, "array"); break; |
case T_MAPPING: fprintf(stderr, "mapping"); break; |
case T_MULTISET: fprintf(stderr, "multiset"); break; |
|
case PIKE_T_UNKNOWN: fprintf(stderr, "unknown"); break; |
case T_MANY: fprintf(stderr, "many"); break; |
case T_OR: fprintf(stderr, "or"); break; |
case T_AND: fprintf(stderr, "and"); break; |
case T_NOT: fprintf(stderr, "not"); break; |
case T_VOID: fprintf(stderr, "void"); break; |
case T_ZERO: fprintf(stderr, "zero"); break; |
case T_MIXED: fprintf(stderr, "mixed"); break; |
|
default: fprintf(stderr, "%d",EXTRACT_UCHAR(a+e)); break; |
} |
} |
fprintf(stderr, "\n"); |
} |
#endif |
|
void simple_describe_type(struct pike_type *s) |
{ |
if (s) { |
|
switch(s->type) { |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
fprintf(stderr, "%d", s->type-'0'); |
break; |
|
case PIKE_T_NAME: |
fprintf(stderr, "{ %s = ", ((struct pike_string *)s->car)->str); |
simple_describe_type(s->cdr); |
fprintf(stderr, " }"); |
break; |
|
case PIKE_T_ATTRIBUTE: |
{ |
struct pike_string *deprecated; |
MAKE_CONST_STRING(deprecated, "deprecated"); |
if (((struct pike_string *)s->car) == deprecated) { |
fprintf(stderr, "__deprecated__("); |
} else { |
fprintf(stderr, "__attribute__(\"%s\", ", |
((struct pike_string *)s->car)->str); |
} |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
} |
break; |
|
case T_SCOPE: |
fprintf(stderr, "scope(%"PRINTPTRDIFFT"d, ", CAR_TO_INT(s)); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_TUPLE: |
fprintf(stderr, "tuple("); |
simple_describe_type(s->car); |
fprintf(stderr, ", "); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_ASSIGN: |
fprintf(stderr, "(%"PRINTPTRDIFFT"d = ", CAR_TO_INT(s)); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_INT: |
{ |
INT32 min = CAR_TO_INT(s); |
INT32 max = CDR_TO_INT(s); |
fprintf(stderr, "int"); |
if(min!=MIN_INT32 || max!=MAX_INT32) { |
if (!min && max && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
fprintf(stderr, "(%dbit)", j); |
} else { |
fprintf(stderr, "(%ld..%ld)",(long)min,(long)max); |
} |
} |
break; |
} |
case T_FLOAT: fprintf(stderr, "float"); break; |
case T_STRING: |
{ |
INT32 min; |
INT32 max; |
s = s->car; |
fprintf(stderr, "string"); |
if (s != int_type_string) { |
fprintf(stderr, "("); |
while (s->type == T_OR) { |
struct pike_type *char_type = s->car; |
while(char_type->type == T_ASSIGN) { |
char_type = char_type->cdr; |
} |
|
if (char_type->type == T_ZERO) { |
fprintf(stderr, "zero | "); |
s = s->cdr; |
continue; |
} |
if ((char_type->type >= '0') && (char_type->type <= '9')) { |
fprintf(stderr, "$%c | ", char_type->type); |
s = s->cdr; |
continue; |
} |
#ifdef PIKE_DEBUG |
if (char_type->type != T_INT) { |
Pike_fatal("Invalid node type (%d:%s) in string type.\n", |
char_type->type, get_name_of_type(char_type->type)); |
} |
#endif /* PIKE_DEBUG */ |
min = CAR_TO_INT(char_type); |
max = CDR_TO_INT(char_type); |
if (!min && max && max != MAX_INT32 && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
fprintf(stderr, "%dbit", j); |
} else { |
if (min != MIN_INT32) { |
fprintf(stderr, "%d", min); |
} |
fprintf(stderr, ".."); |
if (max != MAX_INT32) { |
fprintf(stderr, "%d", max); |
} |
} |
fprintf(stderr, " | "); |
s = s->cdr; |
} |
while(s->type == T_ASSIGN) { |
s = s->cdr; |
} |
if (s->type == T_ZERO) { |
fprintf(stderr, "zero"); |
} else if ((s->type >= '0') && (s->type <= '9')) { |
fprintf(stderr, "$%c", s->type); |
} else { |
#ifdef PIKE_DEBUG |
if (s->type != T_INT) { |
Pike_fatal("Invalid node type (%d:%s) in string type.\n", |
s->type, get_name_of_type(s->type)); |
} |
#endif /* PIKE_DEBUG */ |
min = CAR_TO_INT(s); |
max = CDR_TO_INT(s); |
if (!min && max && max != MAX_INT32 && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
fprintf(stderr, "%dbit", j); |
} else { |
if (min != MIN_INT32) { |
fprintf(stderr, "%d", min); |
} |
fprintf(stderr, ".."); |
if (max != MAX_INT32) { |
fprintf(stderr, "%d", max); |
} |
} |
} |
fprintf(stderr, ")"); |
} |
break; |
} |
case T_TYPE: |
fprintf(stderr, "type("); |
simple_describe_type(s->car); |
fprintf(stderr, ")"); |
break; |
case T_PROGRAM: |
fprintf(stderr, "program("); |
simple_describe_type(s->car); |
fprintf(stderr, ")"); |
break; |
case T_OBJECT: |
fprintf(stderr, "object(%s %"PRINTPTRDIFFT"d)", |
s->car?"is":"implements", |
CDR_TO_INT(s)); |
break; |
case T_FUNCTION: |
case T_MANY: |
fprintf(stderr, "function("); |
while(s->type == T_FUNCTION) { |
simple_describe_type(s->car); |
s = s->cdr; |
while(s->type == T_ASSIGN) { |
fprintf(stderr, "%"PRINTPTRDIFFT"d = ", CAR_TO_INT(s)); |
s = s->cdr; |
} |
if ((s->type == T_FUNCTION) || |
(s->car->type != T_VOID)) { |
fprintf(stderr, ", "); |
} |
} |
if (s->car->type != T_VOID) { |
simple_describe_type(s->car); |
fprintf(stderr, "..."); |
} |
fprintf(stderr, ":"); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_ARRAY: |
fprintf(stderr, "array("); |
simple_describe_type(s->car); |
fprintf(stderr, ")"); |
break; |
case T_MAPPING: |
fprintf(stderr, "mapping("); |
simple_describe_type(s->car); |
fprintf(stderr, ":"); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_MULTISET: |
fprintf(stderr, "multiset("); |
simple_describe_type(s->car); |
fprintf(stderr, ")"); |
break; |
|
case PIKE_T_UNKNOWN: fprintf(stderr, "unknown"); break; |
case PIKE_T_RING: |
fprintf(stderr, "ring("); |
simple_describe_type(s->car); |
fprintf(stderr, "\260"); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_OR: |
fprintf(stderr, "or("); |
simple_describe_type(s->car); |
fprintf(stderr, "|"); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_AND: |
fprintf(stderr, "and("); |
simple_describe_type(s->car); |
fprintf(stderr, "&"); |
simple_describe_type(s->cdr); |
fprintf(stderr, ")"); |
break; |
case T_NOT: |
fprintf(stderr, "not("); |
simple_describe_type(s->car); |
fprintf(stderr, ")"); |
break; |
case T_VOID: fprintf(stderr, "void"); break; |
case T_ZERO: fprintf(stderr, "zero"); break; |
case T_MIXED: fprintf(stderr, "mixed"); break; |
|
default: |
fprintf(stderr, "Unknown type node: %d, %p:%p", |
s->type, s->car, s->cdr); |
#ifdef DEBUG_MALLOC |
debug_malloc_dump_references(s, 0, 2, 0); |
#endif |
break; |
} |
if (s->flags) { |
fprintf(stderr, "[%06x]", s->flags); |
} |
} else { |
fprintf(stderr, "NULL"); |
} |
} |
|
static void low_describe_type(struct pike_type *t) |
{ |
char buffer[100]; |
|
check_c_stack(1024); |
|
switch(t->type) |
{ |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
my_putchar(t->type); |
break; |
|
case T_ASSIGN: |
my_putchar('('); |
my_putchar('0' + CAR_TO_INT(t)); |
my_putchar('='); |
my_describe_type(t->cdr); |
my_putchar(')'); |
break; |
|
case T_SCOPE: |
my_strcat("scope("); |
my_putchar('0' + CAR_TO_INT(t)); |
my_putchar(','); |
my_describe_type(t->cdr); |
my_putchar(')'); |
break; |
|
case T_TUPLE: |
my_putchar('['); |
my_describe_type(t->car); |
my_putchar(','); |
my_describe_type(t->cdr); |
my_putchar(']'); |
break; |
|
case T_VOID: my_strcat("void"); break; |
case T_ZERO: my_strcat("zero"); break; |
case T_MIXED: my_strcat("mixed"); break; |
case PIKE_T_UNKNOWN: my_strcat("unknown"); break; |
case T_INT: |
{ |
INT32 min=CAR_TO_INT(t); |
INT32 max=CDR_TO_INT(t); |
my_strcat("int"); |
|
if (!min && max && max != MAX_INT32 && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
sprintf(buffer, "(%dbit)", j); |
my_strcat(buffer); |
} else if(min!=MIN_INT32 || max!=MAX_INT32) { |
sprintf(buffer,"(%ld..%ld)",(long)min,(long)max); |
my_strcat(buffer); |
} |
break; |
} |
case T_FLOAT: my_strcat("float"); break; |
case T_PROGRAM: |
if ((t->car->type == T_OBJECT) && |
(!t->car->cdr)) { |
my_strcat("program"); |
} else { |
my_strcat("program("); |
my_describe_type(t->car); |
my_strcat(")"); |
} |
break; |
case T_OBJECT: |
if (t->cdr) |
{ |
dynamic_buffer save_buf; |
ONERROR err; |
struct svalue s; |
if (t->car) { |
my_strcat("object(is "); |
} else { |
my_strcat("object(implements "); |
} |
|
|
save_buffer(&save_buf); |
SET_ONERROR(err, restore_buffer, &save_buf); |
s.u.program = id_to_program(CDR_TO_INT(t)); |
CALL_AND_UNSET_ONERROR(err); |
if (s.u.program) { |
SET_SVAL_TYPE(s, T_PROGRAM); |
SET_SVAL_SUBTYPE(s, 0); |
describe_svalue(&s, 0, NULL); |
my_strcat(")"); |
} else { |
char buffer[100]; |
sprintf(buffer,"%"PRINTPTRDIFFT"d)", |
CDR_TO_INT(t)); |
my_strcat(buffer); |
} |
}else{ |
my_strcat("object"); |
} |
break; |
|
case T_STRING: |
{ |
INT32 min; |
INT32 max; |
t = t->car; |
my_strcat("string"); |
if (t->type == T_ZERO) { |
my_strcat("(zero)"); |
} else if (t != int_type_string) { |
my_strcat("("); |
while (t->type == T_OR) { |
struct pike_type *char_type = t->car; |
while(char_type->type == T_ASSIGN) { |
char_type = char_type->cdr; |
} |
if (char_type->type != T_INT) { |
low_describe_type(char_type); |
} else { |
min = CAR_TO_INT(char_type); |
max = CDR_TO_INT(char_type); |
if (!min && max && max != MAX_INT32 && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
sprintf(buffer, "%dbit", j); |
my_strcat(buffer); |
} else { |
if (min != MIN_INT32) { |
sprintf(buffer, "%d", min); |
my_strcat(buffer); |
} |
my_strcat(".."); |
if (max != MAX_INT32) { |
sprintf(buffer, "%d", max); |
my_strcat(buffer); |
} |
} |
} |
my_strcat(" | "); |
t = t->cdr; |
} |
while(t->type == T_ASSIGN) { |
t = t->cdr; |
} |
if (t->type != T_INT) { |
low_describe_type(t); |
} else { |
min = CAR_TO_INT(t); |
max = CDR_TO_INT(t); |
if (!min && max && max != MAX_INT32 && !(max & (max+1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
sprintf(buffer, "%dbit", j); |
my_strcat(buffer); |
} else { |
if (min != MIN_INT32) { |
sprintf(buffer, "%d", min); |
my_strcat(buffer); |
} |
my_strcat(".."); |
if (max != MAX_INT32) { |
sprintf(buffer, "%d", max); |
my_strcat(buffer); |
} |
} |
} |
my_strcat(")"); |
} |
break; |
} |
case T_TYPE: |
my_strcat("type("); |
my_describe_type(t->car); |
my_strcat(")"); |
break; |
|
case PIKE_T_NAME: |
if (!((struct pike_string *)t->car)->size_shift) { |
my_strcat("{ "); |
my_binary_strcat(((struct pike_string *)t->car)->str, |
((struct pike_string *)t->car)->len); |
my_strcat(" = "); |
my_describe_type(t->cdr); |
my_strcat(" }"); |
} else { |
my_describe_type(t->cdr); |
} |
break; |
|
case PIKE_T_ATTRIBUTE: |
if (!((struct pike_string *)t->car)->size_shift) { |
struct pike_string *deprecated; |
MAKE_CONST_STRING(deprecated, "deprecated"); |
if (((struct pike_string *)t->car) == deprecated) { |
my_strcat("__deprecated__("); |
} else { |
my_strcat("__attribute__(\""); |
my_binary_strcat(((struct pike_string *)t->car)->str, |
((struct pike_string *)t->car)->len); |
my_strcat("\", "); |
} |
my_describe_type(t->cdr); |
my_strcat(")"); |
} else { |
my_describe_type(t->cdr); |
} |
break; |
|
case T_FUNCTION: |
case T_MANY: |
{ |
int s; |
my_strcat("function"); |
if(t->type == T_MANY && |
t->cdr->type == T_OR && |
((t->cdr->car->type == T_MIXED && t->cdr->cdr->type == T_VOID) || |
(t->cdr->cdr->type == T_MIXED && t->cdr->car->type == T_VOID)) && |
(t->car->type == T_ZERO || |
(t->car->type == T_OR && |
((t->car->car->type == T_ZERO && t->car->cdr->type == T_VOID) || |
(t->car->cdr->type == T_ZERO && t->car->car->type == T_VOID))))) |
{ |
|
|
|
|
} else { |
my_strcat("("); |
s=0; |
while(t->type != T_MANY) |
{ |
if(s++) my_strcat(", "); |
my_describe_type(t->car); |
t = t->cdr; |
while(t->type == T_ASSIGN) { |
my_putchar('0' + CAR_TO_INT(t)); |
my_putchar('='); |
t = t->cdr; |
} |
} |
if(t->car->type != T_VOID) |
{ |
if(s++) my_strcat(", "); |
my_describe_type(t->car); |
my_strcat(" ..."); |
} |
my_strcat(" : "); |
my_describe_type(t->cdr); |
my_strcat(")"); |
} |
break; |
} |
|
case T_ARRAY: |
my_strcat("array"); |
if(t->car->type != T_MIXED) { |
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(")"); |
} |
break; |
|
case T_MULTISET: |
my_strcat("multiset"); |
if(t->car->type != T_MIXED) { |
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(")"); |
} |
break; |
|
case T_NOT: |
my_strcat("!"); |
if (t->car->type > T_NOT) { |
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(")"); |
} else { |
my_describe_type(t->car); |
} |
break; |
|
case PIKE_T_RING: |
|
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(")\260("); |
my_describe_type(t->cdr); |
my_strcat(")"); |
break; |
|
case T_OR: |
if (t->car->type > T_OR) { |
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(")"); |
} else { |
my_describe_type(t->car); |
} |
my_strcat(" | "); |
if (t->cdr->type > T_OR) { |
my_strcat("("); |
my_describe_type(t->cdr); |
my_strcat(")"); |
} else { |
my_describe_type(t->cdr); |
} |
break; |
|
case T_AND: |
if (t->car->type > T_AND) { |
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(")"); |
} else { |
my_describe_type(t->car); |
} |
my_strcat(" & "); |
if (t->cdr->type > T_AND) { |
my_strcat("("); |
my_describe_type(t->cdr); |
my_strcat(")"); |
} else { |
my_describe_type(t->cdr); |
} |
break; |
|
case T_MAPPING: |
my_strcat("mapping"); |
if(t->car->type != T_MIXED || t->cdr->type != T_MIXED) { |
my_strcat("("); |
my_describe_type(t->car); |
my_strcat(":"); |
my_describe_type(t->cdr); |
my_strcat(")"); |
} |
break; |
default: |
{ |
char buf[20]; |
my_strcat("unknown code("); |
sprintf(buf, "%d", t->type); |
my_strcat(buf); |
my_strcat(")"); |
break; |
} |
} |
} |
|
void my_describe_type(struct pike_type *type) |
{ |
low_describe_type(type); |
} |
|
struct pike_string *describe_type(struct pike_type *type) |
{ |
dynamic_buffer save_buf; |
check_type_string(type); |
if(!type) return make_shared_string("mixed"); |
init_buf(&save_buf); |
low_describe_type(type); |
return free_buf(&save_buf); |
} |
|
|
|
|
TYPE_T compile_type_to_runtime_type(struct pike_type *t) |
{ |
switch(t->type) |
{ |
case PIKE_T_RING: |
return compile_type_to_runtime_type(t->car); |
|
case T_OR: |
{ |
TYPE_T tmp = compile_type_to_runtime_type(t->car); |
if(tmp == compile_type_to_runtime_type(t->cdr)) |
return tmp; |
|
|
} |
case T_TUPLE: |
|
|
default: |
return T_MIXED; |
|
case T_ZERO: |
return T_INT; |
|
case T_SCOPE: |
case PIKE_T_NAME: |
case PIKE_T_ATTRIBUTE: |
return compile_type_to_runtime_type(t->cdr); |
|
case T_MANY: |
return T_FUNCTION; |
|
case T_ARRAY: |
case T_MAPPING: |
case T_MULTISET: |
|
case T_OBJECT: |
case T_PROGRAM: |
case T_FUNCTION: |
|
case T_STRING: |
case T_TYPE: |
case T_INT: |
case T_FLOAT: |
return t->type; |
} |
} |
|
static void low_or_pike_types(struct pike_type *t1, |
struct pike_type *t2, |
int zero_implied); |
|
|
|
|
|
|
|
|
|
|
|
static int lower_or_pike_types(struct pike_type *t1, |
struct pike_type *t2, |
int zero_implied, |
int elem_on_stack) |
{ |
int ret = 0; |
struct pike_type *t = NULL; |
struct pike_type *top = NULL; |
#if 0 |
fprintf(stderr, " lower_or_pike_types("); |
simple_describe_type(t1); |
fprintf(stderr, ", "); |
simple_describe_type(t2); |
fprintf(stderr, ")\n"); |
#endif |
if (t1 == t2) { |
t = t1; |
} else if (!t1) { |
t = t2; |
ret = 1; |
} else if (!t2) { |
t = t1; |
ret = -1; |
} else if (zero_implied && (t1->type == T_ZERO)) { |
t = t2; |
} else if (zero_implied && (t2->type == T_ZERO)) { |
t = t1; |
} else if ((t1->type ^ '0') < (t2->type ^ '0')) { |
|
t = t1; |
ret = -1; |
} else if ((t1->type ^ '0') > (t2->type ^ '0')) { |
|
t = t2; |
ret = 1; |
} else { |
#ifdef PIKE_DEBUG |
if (t1->type != t2->type) { |
Pike_fatal("Lost track of types t1->type: %d, t2->type: %d\n", |
t1->type, t2->type); |
} |
#endif /* PIKE_DEBUG */ |
switch(t1->type) { |
case T_INT: |
if (CAR_TO_INT(t1) < CAR_TO_INT(t2)) { |
t = t1; |
ret = -1; |
} else { |
t = t2; |
ret = 1; |
} |
break; |
case T_STRING: |
{ |
low_or_pike_types(t1->car, t2->car, 1); |
push_type(T_STRING); |
return 0; |
} |
break; |
case T_OBJECT: |
if (!CDR_TO_INT(t1)) { |
t = t1; |
} else if (!CDR_TO_INT(t2)) { |
t = t2; |
} else if (CDR_TO_INT(t1) < CDR_TO_INT(t2)) { |
t = t1; |
ret = -1; |
} else { |
t = t2; |
ret = 1; |
} |
break; |
case T_MAPPING: |
if (t1->car->type < t2->car->type) { |
t = t1; |
ret = -1; |
break; |
} |
if (t1->car->type > t2->car->type) { |
t = t2; |
ret = 1; |
break; |
} |
if (t1->cdr->type < t2->cdr->type) { |
t = t1; |
ret = -1; |
break; |
} |
if (t1->cdr->type > t2->cdr->type) { |
t = t2; |
ret = 1; |
break; |
} |
t = t1; |
ret = -1; |
break; |
case T_ARRAY: |
case T_MULTISET: |
if (t1->car->type < t2->car->type) { |
t = t1; |
ret = -1; |
break; |
} else if (t1->car->type > t2->car->type) { |
t = t2; |
ret = 1; |
break; |
} |
|
default: |
#if 0 |
if (pike_types_le(t1, t2)) { |
t = t2; |
} else if (pike_types_le(t2, t1)) { |
t = t1; |
} else |
#endif /* 0 */ |
if (t1 < t2) { |
t = t1; |
ret = -1; |
} else { |
t = t2; |
ret = 1; |
} |
break; |
} |
} |
if (!elem_on_stack) { |
if (t) { |
push_finished_type(t); |
} else { |
push_type(T_ZERO); |
} |
} else if (!t) { |
|
} else if ((top = peek_type_stack())->type != t->type) { |
if (zero_implied && (top->type == T_ZERO)) { |
Pike_compiler->type_stackp--; |
free_type(top); |
push_finished_type(t); |
} else if (zero_implied && (t->type == T_ZERO)) { |
|
} else { |
push_finished_type(t); |
} |
} else if (t == top) { |
|
} else { |
switch(t->type) { |
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
|
break; |
case T_INT: |
{ |
INT32 min1 = CAR_TO_INT(t); |
INT32 max1 = CDR_TO_INT(t); |
INT32 min2 = CAR_TO_INT(top); |
INT32 max2 = CDR_TO_INT(top); |
|
if (zero_implied) { |
if (min1 == 1) min1 = 0; |
if (min2 == 1) min2 = 0; |
if (max1 == -1) max1 = 0; |
if (max2 == -1) max2 = 0; |
|
if (zero_implied == 3) { |
|
|
|
|
|
|
|
|
if (max1 < 0) max1 = 0; |
if (max2 < 0) max2 = 0; |
if (min1 > 0) min1 = 0; |
if (min2 > 0) min2 = 0; |
|
|
max1 |= max2; |
|
if ((min1 < 0) && (min2 < 0)) { |
min1 &= min2; |
} |
} |
} |
|
if ((max2 < MAX_INT32) && (min1 > max2 + 1)) { |
|
push_finished_type(t); |
#ifdef PIKE_DEBUG |
} else if ((max1 < MAX_INT32) && (min2 > max1 + 1)) { |
|
Pike_fatal("Bad integer ordering in lower_or_pike_types().\n"); |
#endif |
} |