2006-10-27
2006-10-27 18:45:00 by Henrik Grubbström (Grubba) <grubba@grubba.org>
-
6fa59e3f5945c6e74cca4a696890f7ec25560111
(170 lines)
(+166/-4)
[
Show
| Annotate
]
Branch: 7.9
First try at implementing getter/setter variables. Seems to work.
Rev: src/program.c:1.610
2:
|| 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"
210:
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.
1099:
*! @[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
*/
2418:
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. */
2440:
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;
}
2969:
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))
3012:
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)
4872:
struct reference ref;
struct svalue *lfun_type;
INT32 i;
+ INT32 getter_setter_offset = -1;
#ifdef PROGRAM_BUILD_DEBUG
{
4908:
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;
4948:
( (!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;
}
5033: Inside #if defined(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
5091:
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;
}
7163:
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);
7225:
{
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++) {