pike.git / src / program.c

version» Context lines:

pike.git/src/program.c:1:   /*   || 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. - || $Id: program.c,v 1.609 2006/08/09 14:03:02 mast Exp $ + || $Id: program.c,v 1.610 2006/10/27 18:45:00 grubba Exp $   */      #include "global.h"   #include "program.h"   #include "object.h"   #include "dynamic_buffer.h"   #include "pike_types.h"   #include "stralloc.h"   #include "las.h"   #include "lex.h"
pike.git/src/program.c:203:    tFuncV(tStr,tVoid,tInt), /* "_is_type", */    tFuncV(tInt tOr(tMap(tStr,tInt),tVoid),tVoid,tStr), /* "_sprintf", */    tFuncV(tMix,tVoid,tInt), /* "_equal", */    tFuncV(tZero,tVoid,tMix), /* "_m_delete", */    tFuncV(tNone,tVoid,tObj), /* "_get_iterator", */    tFuncV(tZero tRangeBound tZero tRangeBound, tVoid, tMix), /* "`[..]" */    /* NOTE: After this point there are only fake lfuns. */    tFuncV(tZero tOr(tZero, tVoid), tVoid, tMix), /* "_search", */   };    + /* These two are not true LFUNs! */ + static struct pike_type *lfun_getter_type_string = NULL; + static struct pike_type *lfun_setter_type_string = NULL; +    /*! @namespace lfun::    *!    *! Callback functions used to overload various builtin functions.    *!    *! The functions can be grouped into a few sets:    *!    *! @ul    *! @item    *! Object initialization and destruction.    *!
pike.git/src/program.c:1092:    */      /*! @decl mixed lfun::_search(mixed needle, mixed|void start)    *!    *! Search callback.    *!    *! @seealso    *! @[predef::search()]    */    + /*! @decl mixed lfun::`->symbol() +  *! +  *! Variable retrieval callback (aka "getter"). +  *! +  *! @note +  *! Note that the @expr{symbol@} in the name can be any symbol. +  *! +  *! @note +  *! This is not a true LFUN, since it is even more low level! +  *! +  *! @note +  *! This function WILL be called even by inheriting programs +  *! when they attempt to access the variable named @expr{symbol@}. +  *! +  *! @seealso +  *! @[lfun::`->symbol=()], @[lfun::`->()] +  */ +  + /*! @decl void lfun::`->symbol=(zero value) +  *! +  *! Variable assignment callback (aka "setter"). +  *! +  *! @note +  *! Note that the @expr{symbol@} in the name can be any symbol. +  *! +  *! @note +  *! This is not a true LFUN, since it is even more low level! +  *! +  *! @note +  *! This function WILL be called even by inheriting programs +  *! when they attempt to set the variable named @expr{symbol@}. +  *! +  *! @seealso +  *! @[lfun::`->symbol()], @[lfun::`->=()] +  */ +    /*! @endnamespace    */      /*! @class MasterObject    */      /*! @decl void unregister(program p)    *!    *! Unregister a program that was only partially compiled.    *!
pike.git/src/program.c:2411:    push_compiler_frame(0);    copy_pike_type(Pike_compiler->compiler_frame->current_return_type,    void_type_string);       debug_malloc_touch(Pike_compiler->fake_object);    debug_malloc_touch(Pike_compiler->fake_object->storage);   }      PMOD_EXPORT void debug_start_new_program(int line, const char *file)   { -  struct pike_string *save_file = lex.current_file; +  struct pike_string *save_file = +  dmalloc_touch(struct pike_string *, lex.current_file);    int save_line = lex.current_line;       { /* Trim off the leading path of the compilation environment. */    const char *p = DEFINETOSTR(PIKE_SRC_ROOT), *f = file;    while (*p && *p == *f) p++, f++;    while (*f == '/' || *f == '\\') f++;       lex.current_file = make_shared_string(f);    lex.current_line = line;    }
pike.git/src/program.c:2433:    CDFPRINTF((stderr,    "th(%ld) start_new_program(%d, %s): "    "threads_disabled:%d, compilation_depth:%d\n",    (long)th_self(), line, file, threads_disabled, compilation_depth));       low_start_new_program(0,1,0,0,0);    store_linenumber(line,lex.current_file);    debug_malloc_name(Pike_compiler->new_program, file, line);       free_string(lex.current_file); -  lex.current_file = save_file; +  lex.current_file = dmalloc_touch(struct pike_string *, save_file);    lex.current_line = save_line;   }         static void exit_program_struct(struct program *p)   {    unsigned e;      #ifdef PIKE_DEBUG    if (p->refs) {
pike.git/src/program.c:2962:    case IDENTIFIER_CONSTANT:    break;       default:    Pike_fatal("Invalid identifier type.\n");    }       if(p->identifiers[e].identifier_flags & ~IDENTIFIER_MASK)    Pike_fatal("Unknown flags in identifier flag field.\n");    -  if(p->identifiers[e].run_time_type!=T_MIXED) +  if((p->identifiers[e].run_time_type!=T_MIXED) && +  (p->identifiers[e].run_time_type!=PIKE_T_GET_SET))    check_type(p->identifiers[e].run_time_type);       if(IDENTIFIER_IS_VARIABLE(p->identifiers[e].identifier_flags))    {    if( (p->identifiers[e].func.offset /* + OFFSETOF(object,storage)*/ ) &    (alignof_variable(p->identifiers[e].run_time_type)-1))    {    Pike_fatal("Variable %s offset is not properly aligned (%ld).\n",    p->identifiers[e].name->str,    PTRDIFF_T_TO_LONG(p->identifiers[e].func.offset));
pike.git/src/program.c:3005:    p->identifier_references[e].identifier_offset,    p->inherits[p->identifier_references[e].inherit_offset].prog->num_identifiers);       i=ID_FROM_INT(p, e);       if(IDENTIFIER_IS_VARIABLE(i->identifier_flags))    {    size_t q, size;    /* Variable */    ptrdiff_t offset = INHERIT_FROM_INT(p, e)->storage_offset+i->func.offset; +  if (i->run_time_type == PIKE_T_GET_SET) { +  struct reference *ref = PTR_FROM_INT(p, e); +  if (!(ref->id_flags & ID_INHERITED)) { +  INT32 *gs_info = (INT32 *)(p->program + i->func.offset); +  if ((gs_info + 2) > (INT32 *)(p->program + p->num_program)) { +  Pike_fatal("Getter/setter variable outside program!\n"); +  } +  if (gs_info[0] >= p->num_identifier_references) { +  Pike_fatal("Getter outside references.\n"); +  } +  if (gs_info[1] >= p->num_identifier_references) { +  Pike_fatal("Setter outside references.\n"); +  } +  } +  continue; +  }    size=sizeof_variable(i->run_time_type);       if((offset+size > (size_t)p->storage_needed) || offset<0)    Pike_fatal("Variable outside storage! (%s)\n",i->name->str);       for(q=0;q<size;q++)    {    if(offset+q >= NELEM(variable_positions)) break;       if(variable_positions[offset+q] != -1)
pike.git/src/program.c:4865:    struct pike_type *type,    unsigned flags,    unsigned function_flags,    union idptr *func,    unsigned opt_flags)   {    struct identifier *funp,fun;    struct reference ref;    struct svalue *lfun_type;    INT32 i; +  INT32 getter_setter_offset = -1;      #ifdef PROGRAM_BUILD_DEBUG    {    struct pike_string *d = describe_type (type);    fprintf (stderr, "%.*sdefining function (pass=%d): %s ",    compilation_depth, " ", Pike_compiler->compiler_pass, d->str);    free_string (d);    push_string (name);    print_svalue (stderr, --Pike_sp);    putc ('\n', stderr);
pike.git/src/program.c:4901:    if (!pike_types_le(type, lfun_type->u.type)) {    if (!match_types(type, lfun_type->u.type)) {    my_yyerror("Type mismatch for callback function %S:", name);    yytype_error(NULL, lfun_type->u.type, type, 0);    } else if (lex.pragmas & ID_STRICT_TYPES) {    yywarning("Type mismatch for callback function %S:", name);    yytype_error(NULL, lfun_type->u.type, type,    YYTE_IS_WARNING);    }    } +  } else if ((name->len > 3) && +  (index_shared_string(name, 0) == '`') && +  (index_shared_string(name, 1) == '-') && +  (index_shared_string(name, 2) == '>')) { +  struct pike_string *symbol = NULL; +  struct pike_type *symbol_type = NULL; +  struct pike_type *gs_type = NULL; +  /* Getter setter. */ +  if (index_shared_string(name, name->len-1) != '=') { +  /* fprintf(stderr, "Got getter: %s\n", name->str); */ +  gs_type = lfun_getter_type_string; +  getter_setter_offset = 0; +  symbol = string_slice(name, 3, name->len-3); +  symbol_type = get_argument_type(type, -1); +  } else if (name->len > 4) { +  /* fprintf(stderr, "Got setter: %s\n", name->str); */ +  gs_type = lfun_setter_type_string; +  getter_setter_offset = +  ((PIKE_OPCODE_T *)(((INT32 *)0) + 1)) - ((PIKE_OPCODE_T *)0); +  symbol = string_slice(name, 3, name->len-4); +  symbol_type = get_argument_type(type, 0);    }    -  +  if (symbol) { +  /* We got a getter or a setter. */ +  struct reference *ref; +  if (!pike_types_le(type, gs_type)) { +  if (!match_types(type, gs_type)) { +  my_yyerror("Type mismatch for callback function %S:", name); +  yytype_error(NULL, gs_type, type, 0); +  } else if (lex.pragmas & ID_STRICT_TYPES) { +  yywarning("Type mismatch for callback function %S:", name); +  yytype_error(NULL, gs_type, type, YYTE_IS_WARNING); +  } +  } +  i = isidentifier(symbol); +  if ((i >= 0) && +  !((ref = Pike_compiler->new_program->identifier_references + i)-> +  id_flags & ID_INHERITED)) { +  /* Not an inherited symbol. */ +  struct identifier *id = ID_FROM_INT(Pike_compiler->new_program, i); +  if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags)) { +  my_yyerror("Illegal to redefine function %S with variable.", symbol); +  getter_setter_offset = -1; +  } else if (id->run_time_type != PIKE_T_GET_SET) { +  my_yyerror("Illegal to redefine a current variable with a getter/setter: %S.", symbol); +  getter_setter_offset = -1; +  } else { +  if (ref->id_flags != flags) { +  if (Pike_compiler->compiler_pass == 1) { +  yywarning("Modifier mismatch for variable %S.", symbol); +  } +  ref->id_flags &= flags; +  } +  getter_setter_offset += id->func.offset; +  } +  } else { +  INT32 offset = Pike_compiler->new_program->num_program; +  getter_setter_offset += offset; +  /* Get/set information. +  * reference number to getter. +  * reference number to setter. +  * NOTE: Only place-holders for now. +  * The proper entry gets set when we have added the function. +  */ +  ins_pointer(-1); +  ins_pointer(-1); +  low_define_variable(symbol, symbol_type, flags, +  offset, PIKE_T_GET_SET); +  } +  /* FIXME: Really ought to be ID_HIDDEN too, +  * but that complicates matters below... +  */ +  flags = ID_STATIC|ID_PRIVATE|ID_INLINE; +  free_type(symbol_type); +  free_string(symbol); +  } +  } +     if(IDENTIFIER_IS_C_FUNCTION(function_flags))    Pike_compiler->new_program->flags |= PROGRAM_HAS_C_METHODS;       if (Pike_compiler->compiler_pass == 1) {    /* Mark the type as tentative by reusing IDENTIFIER_C_FUNCTION.    *    * NOTE: This flag MUST be cleared in the second pass.    */    function_flags |= IDENTIFIER_C_FUNCTION;    }
pike.git/src/program.c:4941:    /* Keep this flag. */    function_flags |= IDENTIFIER_HAS_BODY;       if(!(ref.id_flags & ID_INHERITED)) /* not inherited */    {       if( !( IDENTIFIER_IS_FUNCTION(funp->identifier_flags) &&    ( (!func || func->offset == -1) || (funp->func.offset == -1))))    {    my_yyerror("Identifier %S defined twice.", name); +  +  if (getter_setter_offset >= 0) { +  upd_pointer(getter_setter_offset, i); +  }    return i;    }       if (IDENTIFIER_IS_FUNCTION(funp->identifier_flags) !=    IDENTIFIER_FUNCTION) {    /* match types against earlier prototype or vice versa */    if(!match_types(type, funp->type))    {    if (!(flags & ID_VARIANT)) {    my_yyerror("Prototype doesn't match for function %S.", name);
pike.git/src/program.c:5026:    debug_add_to_identifiers(fun);    }       ref.inherit_offset = 0;    ref.id_flags = flags;    if ((overridden = override_identifier (&ref, name)) >= 0) {   #ifdef PIKE_DEBUG    if(MEMCMP(Pike_compiler->new_program->identifier_references+i, &ref,sizeof(ref)))    Pike_fatal("New function overloading algorithm failed!\n");   #endif +  +  if (getter_setter_offset >= 0) { +  INT32 old_i = (INT32)read_pointer(getter_setter_offset); +  if ((old_i >= 0) && (old_i != overridden)) { +  my_yyerror("Multiple definitions for %S.", name); +  } +  upd_pointer(getter_setter_offset, overridden); +  }    return overridden;    }    /* NOTE: At this point we already have the identifier in the    * new program, and just need to add the reference.    */    } else {    make_a_new_def:      #ifdef PIKE_DEBUG    if(Pike_compiler->compiler_pass==2)
pike.git/src/program.c:5084:    /* Add the reference. */       i=Pike_compiler->new_program->num_identifier_references;    add_to_identifier_references(ref);      #ifdef PROGRAM_BUILD_DEBUG    fprintf(stderr, "%.*sadded new definition #%d\n",    compilation_depth, " ", i);   #endif    +  if (getter_setter_offset >= 0) { +  INT32 old_i = (INT32)read_pointer(getter_setter_offset); +  if (old_i >= 0) { +  my_yyerror("Multiple definitions for %S.", name); +  } +  upd_pointer(getter_setter_offset, i); +  } +     return i;   }      #if 0      int add_ext_ref(struct program_state *state, struct program *target, int i)   {    struct reference ref, *r;    int j;    if (state->new_program == target) return i;
pike.git/src/program.c:7156:    key.type = T_STRING;    key.u.string = lfun_strings[i];    mapping_insert(lfun_ids, &key, &id);       val.type = T_TYPE;    val.u.type = make_pike_type(raw_lfun_types[i]);    mapping_insert(lfun_types, &key, &val);    free_type(val.u.type);    }    +  lfun_getter_type_string = make_pike_type(tFuncV(tNone, tVoid, tMix)); +  lfun_setter_type_string = make_pike_type(tFuncV(tZero, tVoid, tVoid)); +     start_new_program();    debug_malloc_touch(Pike_compiler->fake_object);    debug_malloc_touch(Pike_compiler->fake_object->storage);    ADD_STORAGE(struct pike_trampoline);    ADD_FUNCTION("`()",apply_trampoline,tFunction,0);    ADD_FUNCTION("`!",not_trampoline,tFunc(tVoid,tInt),0);    ADD_FUNCTION("_sprintf", sprintf_trampoline,    tFunc(tInt tOr(tMapping,tVoid),tStr), 0);    set_init_callback(init_trampoline);    set_exit_callback(exit_trampoline);
pike.git/src/program.c:7218:    s.u.object=placeholder_object;    low_add_constant("__placeholder_object",&s);    debug_malloc_touch(placeholder_object);    }   }      void cleanup_program(void)   {    size_t e;    +  free_type(lfun_setter_type_string); +  free_type(lfun_getter_type_string);    free_mapping(lfun_types);    free_mapping(lfun_ids);    for (e=0; e < NELEM(lfun_names); e++) {    free_string(lfun_strings[e]);    }   #ifdef FIND_FUNCTION_HASHSIZE    for(e=0;e<FIND_FUNCTION_HASHSIZE;e++)    {    if(cache[e].name)    {