/* |
|| 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 *void_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 *fun) |
{ |
if (l_flag > 2) { |
fprintf(stderr, "%25s(): stack_depth:%-3ld mark_stack_depth:%ld\n", |
fun, (long)(Pike_compiler->type_stackp - type_stack), |
(long)(Pike_compiler->pike_type_mark_stackp - |
pike_type_mark_stack)); |
if (Pike_compiler->type_stackp != type_stack) { |
fprintf(stderr, "%25s : top: ", ""); |
simple_describe_type(peek_type_stack()); |
fprintf(stderr, "\n"); |
} |
} |
} |
#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 (pike_type_mark_stack == Pike_compiler->pike_type_mark_stackp) { |
/* Type mark stack empty. */ |
if (type_stack == Pike_compiler->type_stackp) |
Pike_fatal("Type stack underflow.\n"); |
} else 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 & PIKE_T_MASK) |
{ |
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_FUNCTION_ARG: return "PIKE_T_FUNCTION_ARG"; |
|
case PIKE_T_FIND_LFUN: return "PIKE_T_FIND_LFUN"; |
|
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) |
* OPERATOR type Depends on bit #15. Added in 8.1 |
* FIND_LFUN object type lfun (int) Added in 8.1 |
* TRANSITIVE fun_type fun_type Added in 8.1 |
* |
* 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. |
* |
* TRANSITIVE has a car with the current state, and a cdr with the |
* function type to apply. |
* |
*/ |
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 & PIKE_T_MASK) { |
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: |
case PIKE_T_TRANSITIVE: |
/* 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; |
|
case PIKE_T_OPERATOR: |
/* Free car and maybe cdr. */ |
if (type & 0x8000) { |
/* Free cdr. */ |
free_type(cdr); |
} |
t = car; |
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 & ~PIKE_T_MASK) && ((type & PIKE_T_MASK) != PIKE_T_OPERATOR)) { |
/* 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 & PIKE_T_MASK) { |
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: |
case PIKE_T_TRANSITIVE: |
/* 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; |
|
case PIKE_T_OPERATOR: |
if (type & 0x8000) { |
free_type((struct pike_type *)debug_malloc_pass(cdr)); |
} |
free_type((struct pike_type *)debug_malloc_pass(car)); |
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 & PIKE_T_MASK) { |
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: |
case PIKE_T_TRANSITIVE: |
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 PIKE_T_OPERATOR: |
if (type & 0x8000) { |
debug_malloc_pass(cdr); |
} |
debug_malloc_pass(car); |
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); |
|
TYPE_STACK_DEBUG("push_array_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) |
{ |
/* 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_attribute"); |
} |
|
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"); |
} |
|
static struct pike_type *apply_type_operator(enum PIKE_TYPE op, |
struct pike_type *arg1, |
struct pike_type *arg2); |
|
void debug_push_type_operator(enum PIKE_TYPE op, struct pike_type *arg) |
{ |
struct pike_type *t = *Pike_compiler->type_stackp; |
struct pike_type *tmp; |
int free_arg = 0; |
|
#ifdef PIKE_DEBUG |
if ((op & PIKE_T_MASK) != 0x80) { |
Pike_fatal("Invalid operator for push_operator: 0x%04x\n", op); |
} |
#endif |
if (op & 0x8000) { |
if (!arg) { |
Pike_compiler->type_stackp--; |
arg = *Pike_compiler->type_stackp; |
free_arg = 1; |
*Pike_compiler->type_stackp = t; |
|