/* |
|| This file is part of Pike. For copyright information see COPYRIGHT. |
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING |
|| for more information. |
*/ |
|
#include "global.h" |
#include <ctype.h> |
#include "svalue.h" |
#include "stralloc.h" |
#include "pike_types.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" |
#include "gc_header.h" |
|
#ifdef PIKE_DEBUG |
#define PIKE_TYPE_DEBUG |
#endif /* PIKE_DEBUG */ |
|
|
/* Number of entries in the struct pike_type hash-table. */ |
/* 256Kb */ |
#define PIKE_TYPE_HASH_SIZE 32767 |
|
#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 *int_pos_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; /* array|mapping|multiset|function */ |
struct pike_type *sscanf_type_string; |
PMOD_EXPORT struct pike_type *utf8_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; |
} |
} |
} |
|
void compiler_discard_top_type(void) |
{ |
TYPE_STACK_DEBUG("discard_top_type"); |
#ifdef PIKE_DEBUG |
if (!peek_stack_mark()) |
Pike_fatal("Type stack underflow.\n"); |
#endif |
free_type(*(Pike_compiler->type_stackp--)); |
} |
|
void compiler_discard_type (void) |
{ |
ptrdiff_t len = pop_stack_mark(); |
TYPE_STACK_DEBUG("discard_type"); |
for (;len > 0; len--) { |
/* Get rid of excess junk. */ |
compiler_discard_top_type(); |
} |
} |
|
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 = mixed_type_string); |
type_stack_mark(); |
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 |
/* Let's make it able to describe any type constant in debug mode. */ |
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_LSTRING: return "PIKE_T_LSTRING"; |
case PIKE_T_LARRAY: return "PIKE_T_LARRAY"; |
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); |
|
/* |
* New and improved type representation system. |
* |
* This representation is new in Pike 7.3. |
* |
* Node: Car: Cdr: |
* --------------------------------------------- |
* SCOPE num vars (int) type |
* ASSIGN variable (int) type |
* NAME name (string) type |
* ATTRIBUTE name (string) type Added in 7.7. |
* FUNCTION type FUNCTION|MANY |
* MANY many type return type |
* RING type type Reserved. |
* TUPLE type type Reserved. |
* MAPPING index type value type |
* OR type (not OR) type |
* AND type type |
* ARRAY len type type len added in 8.1 |
* MULTISET type - |
* NOT type - |
* '0'-'9' - - |
* FLOAT - - |
* STRING len type ZERO, INT or OR len:8.1, Range:7.7 |
* TYPE type - |
* PROGRAM type - |
* MIXED - - |
* VOID - - |
* ZERO - - |
* UNKNOWN - - |
* INT min (int) max (int) |
* OBJECT implements/is object id(int) |
* |
* Note that the cdr of a FUNCTION is a valid FUNCTION for the rest of |
* the arguments. |
* |
* Note also that functions that don't take any arguments, or just |
* a many argument just have a MANY node, and no FUNCTION node. |
* |
*/ |
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) { |
struct pike_type *t = ba_alloc(&type_allocator); |
gc_init_marker(t); |
return t; |
} |
|
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) |
{ |
if (!t) return; |
#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 |
/* PIKE_DEBUG code */ |
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); |
} |
/* End PIKE_DEBUG code */ |
#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)); |
|
/* FIXME: Recursion: Should we use a stack? */ |
switch(type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
case T_ARRAY: |
case T_STRING: |
/* Free car & cdr */ |
free_type(car); |
t = (struct pike_type *) cdr; |
debug_free_type_preamble (t); |
goto loop; |
|
case PIKE_T_AUTO: |
if (!car) |
break; |
/* FALLTHRU */ |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
/* Free car */ |
t = (struct pike_type *) car; |
debug_free_type_preamble (t); |
goto loop; |
|
case T_SCOPE: |
case T_ASSIGN: |
/* Free cdr */ |
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) |
{ |
/* FIXME: The hash ought to be based on the tree contents, regardless |
* of what the adresses of the type nodes are. |
*/ |
struct pike_type *t; |
unsigned INT32 index, |
hash = (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 |
/* PIKE_DEBUG code */ |
if (type & ~255) { |
/* The bad type node on OSF/1 seems to be: |
* |
* type: 0xffff |
* car: valid pointer. |
* cdr: 0x400000000 |
* next: 0x100000000 |
*/ |
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); |
} |
/* End PIKE_DEBUG code */ |
#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)) { |
/* Attempt to detect why we get a core-dump on OSF/1 |
* when loading Unicode.so from test_resolv. |
* |
* The problem triggs when the type for normalize() is created. |
* function(string,string:string) |
* /grubba 2005-02-04 |
* |
* Load order: |
* Module Hashtable status Note |
* Nettle.so OK |
* ___Oracle.so - load_module() fails. |
* Image.so - loads ok. |
* Unicode.so FAIL |
* |
* pike_type node: |
* Field Before After |
* t 1404b5020 1404b5020 |
* t->type 4 (function) 65535 (unknown) |
* t->car 1404863f8 (1404863f8) 140557560 (1404863f8) |
* t->cdr 1404b43d8 (1404b43d8) 400000000 (1404b43d8) |
* t->next 0 100000000 |
* /grubba 2005-06-03 |
*/ |
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)) { |
/* Free car & cdr as appropriate. */ |
switch(type) { |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case T_OR: |
case T_AND: |
case PIKE_T_RING: |
case T_ARRAY: |
case T_STRING: |
/* Free car & cdr */ |
free_type((struct pike_type *)debug_malloc_pass(car)); |
free_type((struct pike_type *)debug_malloc_pass(cdr)); |
break; |
|
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
/* Free car */ |
free_type((struct pike_type *)debug_malloc_pass(car)); |
break; |
case PIKE_T_AUTO: |
if( car ) |
free_type((struct pike_type *)debug_malloc_pass(car)); |
break; |
|
case T_SCOPE: |
case T_ASSIGN: |
/* Free cdr */ |
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; |
gc_init_marker(t); |
add_ref(t); /* For DMALLOC... */ |
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) { |
/* The scope blocks propagation of markers. */ |
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: |
case T_ARRAY: |
case T_STRING: |
debug_malloc_pass(car); |
debug_malloc_pass(cdr); |
break; |
|
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
case PIKE_T_AUTO: |
debug_malloc_pass(car); |
break; |
|
case T_ASSIGN: |
t->flags |= PT_FLAG_ASSIGN_0 << PTR_TO_INT(car); |
/* FALLTHRU */ |
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 */ |
|
struct pike_type **type_stack; |
struct pike_type ***pike_type_mark_stack; |
|
ptrdiff_t peek_stack_mark(void) |
{ |
if(Pike_compiler->pike_type_mark_stackp-1 < pike_type_mark_stack) |
Pike_fatal("Type mark stack underflow\n"); |
|
TYPE_STACK_DEBUG("peek_stack_mark"); |
|
return Pike_compiler->type_stackp - Pike_compiler->pike_type_mark_stackp[-1]; |
} |
|
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 |
/* a bit kludgy: should maybe really allow 64 bit INT_TYPE */ |
/* see also extract_type_int */ |
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) { |
/* Special case... */ |
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"); |
} |
|
/** |
* Used with arrays and strings. |
* |
* On entry the type stack contains the value type. |
* |
* Generates an array or string type with no length limits. |
*/ |
void debug_push_unlimited_array_type(enum PIKE_TYPE t) |
{ |
struct compilation * c = MAYBE_THIS_COMPILATION; |
#ifdef PIKE_DEBUG |
if ((t != PIKE_T_ARRAY) && (t != PIKE_T_STRING)) { |
Pike_fatal("Invalid type for push_unlimited_array_type(): %s (%d)\n", |
get_name_of_type(t), t); |
} |
#endif |
if (peek_type_stack()->type == PIKE_T_ZERO) { |
push_type(PIKE_T_ZERO); |
} else { |
push_int_type(0, MAX_INT32); |
} |
push_type(t); |
} |
|
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) |
{ |
/* fprintf(stderr, "push_type_attribute(\"%s\")\n", attr->str); */ |
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) |
{ |
/* fprintf(stderr, "push_type_name(\"%s\")\n", name->str); */ |
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) |
{ |
/* fprintf(stderr, "push_reverse_joiner_type(%d)\n", type); */ |
|
switch(type) { |
case T_OR: |
case T_AND: |
/* Special case: Check if the two top elements are equal. */ |
if (Pike_compiler->type_stackp[-1] == Pike_compiler->type_stackp[0]) { |
free_type(*(Pike_compiler->type_stackp--)); |
return; |
} |
/* Make a new type of the top two types. */ |
--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) |
{ |
/* fprintf(stderr, "push_type(%d)\n", type); */ |
|
switch(type) { |
case T_OR: |
case T_AND: |
/* Special case: Check if the two top elements are equal. */ |
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) { |
/* The top type is the same as our type. |
* Split it and join the parts with the other 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; |
} |
/* FALLTHRU */ |
case T_FUNCTION: |
case T_MANY: |
case T_TUPLE: |
case T_MAPPING: |
case PIKE_T_RING: |
case T_ARRAY: |
case T_STRING: |
/* Make a new type of the top two types. */ |
--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) { |
/* Not a program type, convert it to a type type. */ |
type = T_TYPE; |
} |
} |
/* FALLTHRU */ |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case PIKE_T_AUTO: |
/* Make a new type of the top type, and put it in car. */ |
*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: |
/* Should not occur. */ |
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: |
/* Leaf type. */ |
*(++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': |
/* Marker. */ |
*(++Pike_compiler->type_stackp) = mk_type(type, NULL, NULL, PT_IS_MARKER); |
break; |
} |
|
TYPE_STACK_DEBUG("push_type"); |
} |
|
/* Pop one level of types. This is the inverse of 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); |
/* Special case... */ |
if (top->type == T_MIXED) return; /* Probably due to an earlier error */ |
|
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 */ |
/* OPTIMIZE: It looks like this function is always called with |
* 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: |
/* Both car & cdr. */ |
push_finished_type(top->cdr); |
push_finished_type(top->car); |
break; |
case T_MULTISET: |
case T_NOT: |
case T_TYPE: |
case T_PROGRAM: |
case PIKE_T_AUTO: |
/* car */ |
push_finished_type(top->car); |
break; |
case T_SCOPE: |
case T_ASSIGN: |
case T_ARRAY: |
case T_STRING: |
/* cdr */ |
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': |
/* Leaf */ |
break; |
case PIKE_T_ATTRIBUTE: |
case PIKE_T_NAME: |
/* Pop the name and recurse. */ |
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) |
{ |
/* fprintf(stderr, "push_reverse_type(%d)\n", 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: |
case PIKE_T_ARRAY: |
case PIKE_T_STRING: |
{ |
/* Binary type-node. -- swap the types. */ |
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; |
} |
} |
|
/* The marker_set is used as follows: |
* |
* PT_FLAG_MARKER_n Indicates that marker #n should be kept after |
* expansion. |
* |
* PT_FLAG_ASSIGN_n Indicates that the assign to marker #n should |
* NOT be removed. |
*/ |
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 */ |
/* We need to replace if there are any markers, or if there's a |
* non-masked assign. |
*/ |
if (!(type->flags & (~marker_set | PT_FLAG_MARKER) & PT_FLAG_MARK_ASSIGN)) { |
/* Nothing to replace in this subtree. */ |
#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')) { |
/* Marker. */ |
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]) { |
/* The marker has a value. */ |
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 |
/* FIXME: We probably ought to switch to the other marker set here. */ |
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 { |
/* The marker has not been set. */ |
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "No marker value.\n"); |
} |
#endif |
} |
if (marker_set & (PT_FLAG_MARKER_0 << m)) { |
/* The marker should be kept. */ |
#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) { |
/* 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)) { |
/* The assignment should be kept as-is. */ |
#ifdef PIKE_TYPE_DEBUG |
if (l_flag > 2) { |
fprintf(stderr, "Keep assignment.\n"); |
} |
#endif /* PIKE_TYPE_DEBUG */ |
/* Clear the flag. */ |
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) { |
/* Strip the name, since it won't be correct anymore. */ |
type = type->cdr; |
goto recurse; |
} else if (type->type == PIKE_T_ATTRIBUTE) { |
/* Keep the attribute. */ |
push_finished_type_with_markers(type->cdr, markers, marker_set); |
push_type_attribute((struct pike_string *)type->car); |
goto done; |
} |
/* FIXME: T_SCOPE */ |
|
if (type->car) { |
/* Keep markers for assigns in the car. */ |
cdr_set = marker_set | |
((type->car->flags & PT_FLAG_ASSIGN)>>PT_ASSIGN_SHIFT); |
} else { |
cdr_set = marker_set; |
} |
if (type->cdr) { |
/* Keep assigns for markers in the 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)) { |
/* Special case handling for implicit zero. */ |
/* FIXME: Probably ought to use {or,and}_pike_types() here. |
* Problem is that they may mess with the markers... |
*/ |
|
type_stack_mark(); |
/* We want to keep markers that have assigns in the car. */ |
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 { |
/* Make sure to filter invalid nodes from the marker in case |
* it is a string type. |
*/ |
if (type->type == PIKE_T_STRING) cdr_set |= PT_FLAG_INT_ONLY; |
if (type->cdr) { |
/* In all other cases type->cdr will be a valid node if is not NULL. */ |
push_finished_type_with_markers(type->cdr, markers, cdr_set); |
} |
if (type->car) { |
/* In all other cases type->car will be a valid node if it is not NULL. */ |
push_finished_type_with_markers(type->car, markers, car_set); |
} |
/* push_type has sufficient magic to recreate the type. */ |
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) { |
/* No values. */ |
push_type(T_ZERO); |
} else if (field == (BIT_BASIC|BIT_COMPLEX)) { |
/* All values. */ |
push_type(T_MIXED); |
} else { |
/* Check the bits... */ |
push_type(T_ZERO); |
|
if (field & BIT_COMPLEX) { |
if (field & BIT_ARRAY) { |
push_type(T_MIXED); |
push_unlimited_array_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_unlimited_array_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++; |
} |
} |
/* Skip the colon. */ |
++*s; |
internal_parse_type(_s); /* return type */ |
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 == '(') /* object({,is,implements} {id,this_program}) */ |
{ |
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_unlimited_array_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; |
} |
/* FIXME: Handle type(T) */ |
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_unlimited_array_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); |
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; |
} |
/* FALLTHRU */ |
|
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_unlimited_array_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); |
} |
} |
|
/* This function is used when adding simul efuns so that |
* the types for the functions can be easily stored in strings. |
* It takes a string on the exact same format as Pike and returns a type |
* struct. |
*/ |
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 |
|
/* fprintf(stderr, "parse_type(\"%s\")...\n", s); */ |
|
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 |
/* FIXME: */ |
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 if (min == max) { |
fprintf(stderr, "(%ld)", (long)min); |
} 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) { |
/* fprintf(stderr, "[[[%p]]]", 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 if (min == max) { |
fprintf(stderr, "(%ld)", (long)min); |
} else { |
fprintf(stderr, "(%ld..%ld)",(long)min,(long)max); |
} |
} |
break; |
} |
case T_FLOAT: fprintf(stderr, "float"); break; |
case T_STRING: |
{ |
INT32 min; |
INT32 max; |
fprintf(stderr, "string"); |
if ((s->car == int_pos_type_string) && (s->cdr == int_type_string)) { |
break; |
} |
fprintf(stderr, "("); |
if (s->car != int_pos_type_string) { |
simple_describe_type(s->car); |
fprintf(stderr, ": "); |
} |
s = s->cdr; |
if (s != int_type_string) { |
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) || (max == min)) { |
fprintf(stderr, "%d", min); |
} |
if (max != 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) || (min == max)) { |
fprintf(stderr, "%d", min); |
} |
if (min != max) { |
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("); |
if (s->car != int_pos_type_string) { |
simple_describe_type(s->car); |
fprintf(stderr, ":"); |
} |
simple_describe_type(s->cdr); |
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; |
case PIKE_T_AUTO: |
fprintf(stderr, "auto"); |
if (s->car && (s->car->type != T_ZERO)) { |
fprintf(stderr, "("); |
simple_describe_type(s->car); |
fprintf(stderr, ")"); |
} |
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_int_range(struct string_builder *s, |
struct pike_type *t) |
{ |
if (!t || (t == int_type_string)) return; |
loop: |
switch(t->type) { |
case T_ZERO: |
string_builder_strcat(s, "zero"); |
break; |
case T_INT: |
{ |
INT32 min=CAR_TO_INT(t); |
INT32 max=CDR_TO_INT(t); |
|
if (min == max) { |
string_builder_sprintf(s, "%ld", (long) min); |
} else if (!min && (max != MAX_INT32) && !(max & (max + 1))) { |
int j = 0; |
while (max) { |
max >>= 1; |
j++; |
} |
string_builder_sprintf(s, "%dbit", j); |
} else { |
if (min != MIN_INT32) { |
string_builder_sprintf(s, "%ld..", (long)min); |
} else { |
string_builder_strcat(s, ".."); |
} |
if (max != MAX_INT32) { |
string_builder_sprintf(s, "%ld", (long)max); |
} |
} |
} |
break; |
case T_ASSIGN: |
t = t->cdr; |
goto loop; |
case T_OR: |
low_describe_int_range(s, t->car); |
string_builder_strcat(s, " | "); |
t = t->cdr; |
goto loop; |
default: |
low_describe_type(s, t); |
break; |
} |
} |
|
void low_describe_type(struct string_builder *s, struct pike_type *t) |
{ |
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': |
string_builder_putchar(s, t->type); |
break; |
|
case T_ASSIGN: |
string_builder_sprintf(s, "(%c=%T)", '0' + CAR_TO_INT(t), t->cdr); |
break; |
|
case T_SCOPE: |
string_builder_sprintf(s, "scope(%c,%T)", '0' + CAR_TO_INT(t), t->cdr); |
break; |
|
case T_TUPLE: |
string_builder_sprintf(s, "[%T,%T]", t->car, t->cdr); |
break; |
|
case T_VOID: string_builder_strcat(s, "void"); break; |
case T_ZERO: string_builder_strcat(s, "zero"); break; |
case T_MIXED: string_builder_strcat(s, "mixed"); break; |
case PIKE_T_UNKNOWN: string_builder_strcat(s, "unknown"); break; |
|
case T_INT: |
string_builder_strcat(s, "int"); |
|
if (t == int_type_string) break; |
|
string_builder_putchar(s, '('); |
low_describe_int_range(s, t); |
string_builder_putchar(s, ')'); |
break; |
|
case T_FLOAT: string_builder_strcat(s, "float"); break; |
case T_PROGRAM: |
if ((t->car->type == T_OBJECT) && |
(!t->car->cdr)) { |
string_builder_strcat(s, "program"); |
} else { |
string_builder_sprintf(s, "program(%T)", t->car); |
} |
break; |
case T_OBJECT: |
if (t->cdr) |
{ |
struct svalue sval; |
if (t->car) { |
string_builder_strcat(s, "object(is "); |
} else { |
string_builder_strcat(s, "object(implements "); |
} |
/* We need to save the global buffer, in case id_to_program() |
* starts running Pike code. */ |
sval.u.program = id_to_program(CDR_TO_INT(t)); |
if (sval.u.program) { |
SET_SVAL_TYPE(sval, T_PROGRAM); |
SET_SVAL_SUBTYPE(sval, 0); |
string_builder_sprintf(s, "%O)", &sval); |
} else { |
string_builder_sprintf(s, "%"PRINTPTRDIFFT"d)", CDR_TO_INT(t)); |
} |
}else{ |
string_builder_strcat(s, "object"); |
} |
break; |
|
case T_STRING: |
{ |
string_builder_strcat(s, "string"); |
if ((t->cdr == int_type_string) && (t->car == int_pos_type_string)) { |
break; |
} |
string_builder_putchar(s, '('); |
if (t->car == zero_type_string) { |
/* Zero-length string. */ |
string_builder_strcat(s, "zero"); |
} else { |
if (t->car != int_pos_type_string) { |
low_describe_int_range(s, t->car); |
string_builder_strcat(s, ": "); |
} |
low_describe_int_range(s, t->cdr); |
} |
string_builder_putchar(s, ')'); |
break; |
} |
case T_TYPE: |
string_builder_sprintf(s, "type(%T)", t->car); |
break; |
|
case PIKE_T_NAME: |
string_builder_sprintf(s, "{ %S = %T }", |
(struct pike_string *)t->car, t->cdr); |
break; |
|
case PIKE_T_ATTRIBUTE: |
{ |
struct pike_string *deprecated; |
MAKE_CONST_STRING(deprecated, "deprecated"); |
if (((struct pike_string *)t->car) == deprecated) { |
string_builder_sprintf(s, "__deprecated__(%T)", t->cdr); |
} else if (t == utf8_type_string) { |
string_builder_sprintf(s, "utf8_string"); |
} else { |
struct svalue sval; |
SET_SVAL(sval, PIKE_T_STRING, 0, string, |
(struct pike_string *)t->car); |
string_builder_sprintf(s, "__attribute__(%O, %T)", &sval, t->cdr); |
} |
} |
break; |
|
case T_FUNCTION: |
case T_MANY: |
{ |
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))))) |
{ |
/* function == function(zero...:mixed|void) or |
* function(zero|void...:mixed|void) |
*/ |
string_builder_strcat(s, "function"); |
/* done */ |
break; |
} else { |
int arg = 0; |
string_builder_strcat(s, "function("); |
while(t->type != T_MANY) |
{ |
if(arg++) string_builder_strcat(s, ", "); |
low_describe_type(s, t->car); |
t = t->cdr; |
while(t->type == T_ASSIGN) { |
string_builder_sprintf(s, "%c=", '0' + CAR_TO_INT(t)); |
t = t->cdr; |
} |
} |
if(t->car->type != T_VOID) |
{ |
if(arg++) string_builder_strcat(s, ", "); |
low_describe_type(s, t->car); |
string_builder_strcat(s, " ..."); |
} |
string_builder_sprintf(s, " : %T)", t->cdr); |
} |
break; |
} |
|
case T_ARRAY: |
string_builder_strcat(s, "array"); |
if((t->cdr->type == T_MIXED) && (t->car == int_pos_type_string)) { |
break; |
} |
string_builder_putchar(s, '('); |
if (t->car == zero_type_string) { |
/* Zero-length array. */ |
string_builder_strcat(s, "zero"); |
} else { |
if (t->car != int_pos_type_string) { |
low_describe_int_range(s, t->car); |
string_builder_putchar(s, ':'); |
if (t->cdr->type != T_MIXED) { |
string_builder_putchar(s, ' '); |
} |
} |
} |
if (t->cdr->type != T_MIXED) { |
string_builder_sprintf(s, "%T", t->cdr); |
} |
string_builder_putchar(s, ')'); |
break; |
|
case T_MULTISET: |
if(t->car->type != T_MIXED) { |
string_builder_sprintf(s, "multiset(%T)", t->car); |
} else { |
string_builder_strcat(s, "multiset"); |
} |
break; |
|
case T_NOT: |
if (t->car->type > T_NOT) { |
string_builder_sprintf(s, "!(%T)", t->car); |
} else { |
string_builder_sprintf(s, "!%T", t->car); |
} |
break; |
|
case PIKE_T_RING: |
/* FIXME: Should be renumbered for correct parenthesing. */ |
string_builder_sprintf(s, "(%T)\260(%T)", t->car, t->cdr); |
break; |
|
case T_OR: |
if (t->car->type > T_OR) { |
string_builder_sprintf(s, "(%T)", t->car); |
} else { |
low_describe_type(s, t->car); |
} |
string_builder_strcat(s, " | "); |
if (t->cdr->type > T_OR) { |
string_builder_sprintf(s, "(%T)", t->cdr); |
} else { |
low_describe_type(s, t->cdr); |
} |
break; |
|
case T_AND: |
if (t->car->type > T_AND) { |
string_builder_sprintf(s, "(%T)", t->car); |
} else { |
low_describe_type(s, t->car); |
} |
string_builder_strcat(s, " & "); |
if (t->cdr->type > T_AND) { |
string_builder_sprintf(s, "(%T)", t->cdr); |
} else { |
low_describe_type(s, t->cdr); |
} |
break; |
|
case T_MAPPING: |
if(t->car->type != T_MIXED || t->cdr->type != T_MIXED) { |
string_builder_sprintf(s, "mapping(%T:%T)", t->car, t->cdr); |
} else { |
string_builder_strcat(s, "mapping"); |
} |
break; |
case PIKE_T_AUTO: |
if (t->car->type != T_ZERO) { |
string_builder_sprintf(s, "auto(%T)", t->car); |
} else { |
string_builder_strcat(s, "auto"); |
} |
break; |
default: |
{ |
string_builder_sprintf(s, "unknown code(%d)", t->type); |
break; |
} |
} |
} |
|
struct pike_string *describe_type(struct pike_type *type) |
{ |
struct string_builder s; |
ONERROR err; |
if(!type) return make_shared_string("mixed"); |
init_string_builder(&s, 0); |
SET_ONERROR(err, free_string_builder, &s); |
low_describe_type(&s, type); |
UNSET_ONERROR(err); |
return finish_string_builder(&s); |
} |
|
|
/******/ |
|
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; |
} |
/* FALLTHRU */ |
|
case T_TUPLE: |
/* FIXME: Shouldn't occur/should be converted to array? */ |
/* FALLTHRU */ |
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; |
} |
} |
|
/** |
* Check whether a type is for a __deprecated__ value. |
* |
* @param t |
* Type to check. |
*/ |
int deprecated_typep(struct pike_type *t) |
{ |
struct pike_string *deprecated_string; |
MAKE_CONST_STRING(deprecated_string, "deprecated"); |
|
while (t) { |
switch(t->type) { |
case PIKE_T_ATTRIBUTE: |
if (((struct pike_string*)t->car) == deprecated_string) { |
return 1; |
} |
/* FALLTHRU */ |
case PIKE_T_SCOPE: |
case T_ASSIGN: |
case PIKE_T_NAME: |
t = t->cdr; |
continue; |
} |
break; |
} |
return 0; |
} |
|
int get_int_type_range(struct pike_type *t, INT_TYPE *range) |
{ |
int ret = 0; |
loop: |
switch(t->type) { |
case T_INT: |
{ |
INT_TYPE min = CAR_TO_INT(t); |
INT_TYPE max = CDR_TO_INT(t); |
if (range[0] > min) range[0] = min; |
if (range[1] < max) range[1] = max; |
return 1; |
} |
break; |
case T_ZERO: |
case T_VOID: |
if (range[0] > 0) range[0] = 0; |
if (range[1] < 0) range[1] = 0; |
return 1; |
case T_SCOPE: |
case T_ASSIGN: |
case PIKE_T_NAME: |
case PIKE_T_ATTRIBUTE: |
t = t->cdr; |
goto loop; |
case T_OR: |
case T_AND: |
ret = get_int_type_range(t->car, range); |
t = t->cdr; |
goto loop; |
default: |
break; |
} |
return ret; |
} |
|
static void low_or_pike_types(struct pike_type *t1, |
struct pike_type *t2, |
int zero_implied); |
|
/* Push either t1, t2 or the OR of t1 and t2. |
* Returns -1 if t1 was pushed. |
* 0 if the OR was pushed. (Successful join) |
* 1 if t2 was pushed. |
* |
* zero_implied: One of: |
* 0 the zero type (if any) must be explicit in the result. |
* 1 the zero type is implicit. |
* 3 zero is implicit and integers are regarded as masks (cf enums). |
*/ |
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')) { |
/* Note: Adjusted order to get markers first. */ |
t = t1; |
ret = -1; |
} else if ((t1->type ^ '0') > (t2->type ^ '0')) { |
/* Note: Adjusted order to get markers first. */ |
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->cdr, t2->cdr, 1); |
push_unlimited_array_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: |
if (t1->cdr->type < t2->cdr->type) { |
t = t1; |
ret = -1; |
break; |
} else if (t1->cdr->type > t2->cdr->type) { |
t = t2; |
ret = 1; |
break; |
} |
if (t1 < t2) { |
t = t1; |
ret = -1; |
} else { |
t = t2; |
ret = 1; |
} |
break; |
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; |
} |
/* FALLTHRU */ |
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) { |
/* No need to do anything. */ |
} 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)) { |
/* The zero is implied. */ |
} else { |
push_finished_type(t); |
} |
} else if (t == top) { |
/* No need to do anything. */ |
} else { |
switch(t->type) { |
case T_FLOAT: |
case T_MIXED: |
case T_VOID: |
case T_ZERO: |
/* There can only be one. */ |
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) { |
/* Or between integer masks. |
* This is a bit more lenient than the default further below, |
* and is used for generating the type for enums. |
*/ |
|
/* Ensure that zero is always in the range. |
* This also ensures that there'll be an overlap. |
*/ |
if (max1 < 0) max1 = 0; |
if (max2 < 0) max2 = 0; |
if (min1 > 0) min1 = 0; |
if (min2 > 0) min2 = 0; |
|
/* Both max values are now >= 0, so this or is safe. */ |
max1 |= max2; |
|
if ((min1 < 0) && (min2 < 0)) { |
min1 &= min2; |
} |
} |
} |
|
if ((min1 > max2) && (min1 > max2 + 1)) { |
/* No overlap. */ |
push_finished_type(t); |
#ifdef PIKE_DEBUG |
} else if ((min2 > max1) && (min2 > max1 + 1)) { |
/* No overlap and wrong order! */ |
Pike_fatal("Bad integer ordering in lower_or_pike_types().\n"); |
#endif |
} else { |
Pike_compiler->type_stackp--; |
free_type(top); |
/* Overlap */ |
min1 = MINIMUM(min1, min2); |
max1 = MAXIMUM(max1, max2); |
|
push_int_type(min1, max1); |
} |
} |
break; |
case T_STRING: |
{ |
Pike_compiler->type_stackp--; |
low_or_pike_types(t->cdr, top->cdr, 1); |
push_unlimited_array_type(T_STRING); |
free_type(top); |
} |
break; |
case T_OBJECT: |
if (CDR_TO_INT(top)) { |
push_finished_type(t); |
} |
break; |
case T_ARRAY: |
Pike_compiler->type_stackp--; |
low_or_pike_types(t->cdr, top->cdr, zero_implied); |
push_unlimited_array_type(t->type); |
free_type(top); |
break; |
case T_MULTISET: |
Pike_compiler->type_stackp--; |
low_or_pike_types(t->car, top->car, zero_implied); |
push_type(t->type); |
free_type(top); |
break; |
case T_MAPPING: |
if (t->car == top->car) { |
Pike_compiler->type_stackp--; |
push_finished_type(t->car); |
low_or_pike_types(t->cdr, top->cdr, zero_implied); |
push_reverse_type(T_MAPPING); |
free_type(top); |
break; |
} else if (t->cdr == top->cdr) { |
Pike_compiler->type_stackp--; |
push_finished_type(t->cdr); |
low_or_pike_types(t->car, top->car, zero_implied); |
push_type(T_MAPPING); |
free_type(top); |
break; |
} |
/* FALLTHRU */ |
default: |
if (t < top) { |
Pike_compiler->type_stackp--; |
push_finished_type(t); |
push_finished_type(top); |
free_type(top); |
} else { |
push_finished_type(t); |
} |
break; |
} |
} |
return ret; |
} |
|
static void low_or_pike_types(struct pike_type *t1, |
struct pike_type *t2, |
int zero_implied) |
{ |
#ifdef PIKE_DEBUG |
struct pike_type *arg1 = t1; |
struct pike_type *arg2 = t2; |
#endif |
#if 0 |
fprintf(stderr, " low_or_pike_types("); |
simple_describe_type(t1); |
fprintf(stderr, ", "); |
simple_describe_type(t2); |
fprintf(stderr, ")\n"); |
#endif |
if(!t1) |
{ |
if(!t2) |
push_type(T_VOID); |
else |
push_finished_type(t2); |
} |
else if((!t2) |
|| (t2->type == T_ZERO && zero_implied) |
|
) |
{ |
push_finished_type(t1); |
} |
else if (t1->type == T_ZERO && zero_implied) |
{ |
push_finished_type(t2); |
} |
else if (t1 == t2) { |
push_finished_type(t1); |
} |
else if ((t1->type == T_OR) || (t2->type == T_OR)) { |
int on_stack = 0; |
type_stack_mark(); |
while (t1 || t2) { |
struct pike_type *a = t1; |
struct pike_type *b = t2; |
struct pike_type *n1 = NULL; |
struct pike_type *n2 = NULL; |
int val; |
if (t1 && t1->type == T_OR) { |
a = t1->car; |
n1 = t1->cdr; |
} |
if (t2 && t2->type == T_OR) { |
b = t2->car; |
n2 = t2->cdr; |
} |
#ifdef PIKE_DEBUG |
if (a && b && ((a->type == T_OR) || (b->type == T_OR))) { |
fprintf(stderr, " low_or_pike_types("); |
simple_describe_type(arg1); |
fprintf(stderr, ", "); |
simple_describe_type(arg2); |
fprintf(stderr, ")\n a:"); |
simple_describe_type(a); |
fprintf(stderr, "\n b:"); |
simple_describe_type(b); |
fprintf(stderr, ")\n"); |
Pike_fatal("Invalid type to lower_or_pike_types!\n"); |
} |
#endif |
val = lower_or_pike_types(a, b, zero_implied, on_stack); |
if (val <= 0) t1 = n1; |
if (val >= 0) t2 = n2; |
on_stack = 1; |
} |
on_stack = pop_stack_mark(); |
while (on_stack > 1) { |
push_reverse_joiner_type(T_OR); |
on_stack--; |
} |
} |
else { |
int val; |
type_stack_mark(); |
val = lower_or_pike_types(t1, t2, zero_implied, 0); |
if (val < 0) { |
lower_or_pike_types(NULL, t2, zero_implied, 1); |
} else if (val > 0) { |
lower_or_pike_types(t1, NULL, zero_implied, 1); |
} else { |
pop_stack_mark(); |
return; |
} |
for (val = pop_stack_mark(); val > 1; val--) { |
push_reverse_joiner_type(T_OR); |
} |
} |
} |
|
struct pike_type *or_pike_types(struct pike_type *a, |
struct pike_type *b, |
int zero_implied) |
{ |
struct pike_type *res; |
type_stack_mark(); |
low_or_pike_types(a,b,1|zero_implied); |
res = pop_unfinished_type(); |
#if 0 |
fprintf(stderr, " ==> "); |
simple_describe_type(res); |
fprintf(stderr, "\n"); |
#endif |
return res; |
} |
|
static void even_lower_and_pike_types(struct pike_type *t1, |
struct pike_type *t2) |
{ |
while(t2->type == T_OR) |
{ |
even_lower_and_pike_types(t1, t2->car); |
t2 = t2->cdr; |
} |
if (t1->type == t2->type) { |
if (t1->type == T_INT) { |
INT32 i1, i2; |
INT32 upper_bound, lower_bound; |
i1 = CDR_TO_INT(t1); |
i2 = CDR_TO_INT(t2); |
upper_bound = MINIMUM(i1,i2); |
|
i1 = CAR_TO_INT(t1); |
i2 = CAR_TO_INT(t2); |
lower_bound = MAXIMUM(i1,i2); |
|
if (upper_bound >= lower_bound) { |
push_int_type(lower_bound, upper_bound); |
push_type(T_OR); |
} |
} else if (t1->type == T_STRING) { |
push_type(T_ZERO); |
even_lower_and_pike_types(t1->cdr, t2->cdr); |
push_unlimited_array_type(T_STRING); |
push_type(T_OR); |
} else { |
push_finished_type(t1); |
push_type(T_OR); |
} |
} |
} |
|
static int lower_and_pike_types(struct pike_type *t1, struct pike_type *t2) |
{ |
int is_complex = 0; |
while(t1->type == T_OR) |
{ |
is_complex |= lower_and_pike_types(t1->car, t2); |
t1 = t1->cdr; |
} |
switch(t1->type) { |
case T_ZERO: |
case T_VOID: |
break; |
case T_STRING: |
case T_FLOAT: |
case T_INT: |
even_lower_and_pike_types(t1, t2); |
break; |
default: |
return 1; |
} |
return is_complex; |
} |
|
/* FIXME: T_STRING! */ |
static int low_and_push_complex_pike_type(struct pike_type *type) |
{ |
int is_complex = 0; |
while(type->type == T_OR) |
{ |
int new_complex; |
new_complex = low_and_push_complex_pike_type(type->car); |
if (new_complex) { |
if (is_complex) { |
push_type(T_OR); |
} else { |
is_complex = 1; |
} |
} |
type = type->cdr; |
} |
switch(type->type) { |
case T_VOID: |
case T_ZERO: |
case T_STRING: |
case T_FLOAT: |
case T_INT: |
/* Simple type. Already handled. */ |
break; |
default: |
push_finished_type(type); |
if (is_complex) { |
push_type(T_OR); |
} |
return 1; |
} |
return is_complex; |
} |
|
/* FIXME: T_STRING! */ |
static void low_and_pike_types(struct pike_type *t1, |
struct pike_type *t2) |
{ |
if(!t1 || t1->type == T_VOID || |
!t2 || t2->type == T_VOID) |
{ |
push_type(T_VOID); |
} |
else if(t1->type == T_ZERO || |
t2->type == T_ZERO) |
{ |
push_type(T_ZERO); |
} |
else if(t1->type == T_MIXED) |
{ |
push_finished_type(t2); |
} |
else if(t2->type == T_MIXED) |
{ |
push_finished_type(t1); |
} |
else if(t1->type == T_INT && t2->type == T_INT) |
{ |
INT32 i1,i2; |
INT32 upper_bound, lower_bound; |
i1 = CDR_TO_INT(t1); |
i2 = CDR_TO_INT(t2); |
upper_bound = MINIMUM(i1,i2); |
|
i1 = CAR_TO_INT(t1); |
i2 = CAR_TO_INT(t2); |
lower_bound = MAXIMUM(i1,i2); |
|
if (upper_bound >= lower_bound) { |
push_int_type(lower_bound, upper_bound); |
} else { |
/* No overlap! */ |
/* FIXME: Warn? */ |
push_type(T_VOID); |
} |
} |
else if (t1->type == T_SCOPE) |
{ |
if (t2->type == T_SCOPE) { |
low_and_pike_types(t1->cdr, t2->cdr); |
if (t1->car > t2->car) |
push_scope_type(CAR_TO_INT(t1)); |
else |
push_scope_type(CAR_TO_INT(t2)); |
} else { |
low_and_pike_types(t1->cdr, t2); |
push_scope_type(CAR_TO_INT(t1)); |
} |
} |
else if (t2->type == T_SCOPE) |
{ |
low_and_pike_types(t1, t2->cdr); |
push_scope_type(CAR_TO_INT(t2)); |
} |
else if ((t1->type == T_STRING) && (t2->type == T_STRING)) { |
low_and_pike_types(t1->cdr, t2->cdr); |
push_unlimited_array_type(T_STRING); |
} |
else if((t1->type == T_FLOAT) && (t2->type == T_FLOAT)) |
{ |
push_finished_type(t1); |
} |
else if(low_pike_types_le(t1, t2, 0, 0)) |
{ |
push_finished_type(t1); |
} |
else if(low_pike_types_le(t2, t1, 0, 0)) |
{ |
push_finished_type(t2); |
} |
else |
{ |
push_type(T_ZERO); |
|
if (lower_and_pike_types(t1, t2)) { |
/* t1 contains complex types. */ |
if (low_and_push_complex_pike_type(t2)) { |
/* t2 also contains complex types. */ |
low_and_push_complex_pike_type(t1); |
push_type(T_AND); |
push_type(T_OR); |
} |
} |
/* push_finished_type(t1); */ |
/* very_low_and_pike_types(t2,t1); */ |
} |
} |
|
struct pike_type *and_pike_types(struct pike_type *a, |
struct pike_type *b) |
{ |
type_stack_mark(); |
low_and_pike_types(a, b); |
return pop_unfinished_type(); |
} |
|
static struct pike_type *low_object_lfun_type(struct pike_type *t, short lfun) |
{ |
struct program *p; |
int i; |
while ((t->type == PIKE_T_NAME) || (t->type == PIKE_T_ATTRIBUTE)) { |
t = t->cdr; |
} |
#ifdef PIKE_DEBUG |
if (t->type != T_OBJECT) { |
fprintf(stderr, "Invalid type to low_object_lfun_type("); |
simple_describe_type(t); |
fprintf(stderr, ", \"%s\")\n", lfun_names[lfun]); |
Pike_fatal("Invalid type to low_object_lfun_type: %d (expected OBJECT).\n", |
t->type); |
} |
#endif /* PIKE_DEBUG */ |
p = id_to_program(CDR_TO_INT(t)); |
if(!p) return 0; |
i=FIND_LFUN(p, lfun); |
if(i==-1) return 0; |
return ID_FROM_INT(p, i)->type; |
} |
|
|
|
/******/ |
|
/* |
* match two type strings, return zero if they don't match, and return |
* the part of 'a' that _did_ match if it did. |
*/ |
#ifdef PIKE_TYPE_DEBUG |
static struct pike_type *low_match_types2(struct pike_type *a, |
struct pike_type *b, |
int flags); |
#endif |
static struct pike_type *low_match_types(struct pike_type *a, |
struct pike_type *b, |
int flags) |
#ifdef PIKE_TYPE_DEBUG |
{ |
int e; |
char *s; |
|
if (l_flag>2) { |
fprintf(stderr, "%*slow_match_types(", indent*2, ""); |
simple_describe_type(a); |
fprintf(stderr, ",\n"); |
fprintf(stderr, "%*s%s", indent*2, "", " "); |
simple_describe_type(b); |
fprintf(stderr, ",\n"); |
fprintf(stderr, "%*s%s", indent*2, "", " "); |
|
if (flags) { |
int f = 0; |
if (flags & A_EXACT) { |
fprintf(stderr, "A_EXACT"); |
f = 1; |
} |
if (flags & B_EXACT) { |
if (f) { |
fprintf(stderr, " | "); |
} |
fprintf(stderr, "B_EXACT"); |
f = 1; |
} |
if (flags & NO_MAX_ARGS) { |
if (f) { |
fprintf(stderr," | "); |
} |
fprintf(stderr, "NO_MAX_ARGS"); |
f = 1; |
} |
if (flags & NO_SHORTCUTS) { |
if (f) { |
fprintf(stderr, " | "); |
} |
fprintf(stderr, "NO_SHORTCUTS"); |
f = 1; |
} |
} else { |
fputc('0', stderr); |
} |
fprintf(stderr, ");\n"); |
indent++; |
} |
|
a = low_match_types2(a, b, flags); |
|
if (l_flag>2) { |
indent--; |
fprintf(stderr, "%*s= ", indent*2, ""); |
if(a) |
simple_describe_type(a); |
else |
fprintf(stderr, "NULL"); |
fputc('\n', stderr); < |