Branch: Tag:

2002-03-27

2002-03-27 20:45:01 by Martin Stjernholm <mast@lysator.liu.se>

Extended Context.eval_and_compile a little. Added
Context.alloc_internal_var, which allows tags to allocate temporary
variables in the semi-hidden scope "_internal_". Added a callback to
Value, Scope and Frame to allow the object to control how it's
formatted in RXML backtraces.

Rev: server/etc/modules/RXML.pmod/module.pmod:1.276

2:   //   // Created 1999-07-30 by Martin Stjernholm.   // - // $Id: module.pmod,v 1.275 2002/03/25 16:52:21 mast Exp $ + // $Id: module.pmod,v 1.276 2002/03/27 20:45:01 mast Exp $      // Kludge: Must use "RXML.refs" somewhere for the whole module to be   // loaded correctly.
1336:    //! If the variable value is the same throughout the life of the    //! context, this method should be used instead of @[rxml_var_eval].    +  optional string format_rxml_backtrace_frame ( +  Context ctx, string var, string scope_name); +  //! Define this to control how the variable reference is formatted +  //! in RXML backtraces. The returned string should be one line, +  //! without a trailing newline. It should not contain the " | " +  //! prefix. +  //! +  //! The empty string may be returned to suppress the backtrace frame +  //! altogether. That might be useful for some types of internally +  //! used variables, but it should be used only if there are very +  //! good reasons; the backtrace easily just becomes confusing +  //! instead. +     string _sprintf() {return "RXML.Value";}   }   
1407:    // For compatibility with 2.1.    {_m_delete (var, ctx, scope_name, 1);}    +  optional string format_rxml_backtrace_frame ( +  Context ctx, string var, string scope_name); +  //! Define this to control how the variable reference is formatted +  //! in RXML backtraces. The returned string should be one line, +  //! without a trailing newline. It should not contain the " | " +  //! prefix. +  //! +  //! The empty string may be returned to suppress the backtrace frame +  //! altogether. That might be useful for some types of internally +  //! used variables, but it should be used only if there are very +  //! good reasons; the backtrace easily just becomes confusing +  //! instead. +     private string _in_the_scope (string scope_name)    {    if (scope_name)
1733:    else parse_error ("Unknown scope %O.\n", scope_name);    }    -  array(string) list_scopes() -  //! Returns the names of all defined scopes. +  array(string) list_scopes (void|int list_hidden) +  //! Returns the names of all defined scopes. If @[list_hidden] is +  //! nonzero then internal scopes are also returned.    { -  +  if (list_hidden)    return indices (scopes) - ({"_"}); -  +  else +  return indices (scopes) - ({"_", "_internal_"});    }       int exist_scope (void|string scope_name)
1899:    }    }    +  static int last_internal_var_id = 0; +  +  string alloc_internal_var() +  //! Allocates and returns a unique variable name in the special +  //! scope "_internal_", creating that scope if necessary. After this +  //! it's safe to use that variable for internal purposes in tags +  //! with the normal variable functions. No other variables in the +  //! "_internal_" scope should be accessed. +  //! +  //! @note +  //! The "_internal_" scope is currently hidden by default by +  //! @[list_scope] but otherwise there's no access restriction on it. +  //! Therefore an end user can get at the variables in that scope +  //! directly. On the other hand there's no guarantee that that will +  //! remain possible in the future, so no end user RXML code should +  //! use the "_internal_" scope. +  { +  if (!scopes->_internal_) add_scope ("_internal_", ([])); +  return (string) ++last_internal_var_id; +  } +     void signal_var_change (string var, void|string scope_name)    //! Call this when the variable @[var] in the specified scope has    //! changed in some other way than by calling a function in this
2022:    }       final array(mixed|PCode) eval_and_compile (Type type, string to_parse, -  void|int stale_safe) +  void|int stale_safe, +  void|TagSet tag_set_override)    //! Parses and evaluates @[to_parse] with @[type] in this context.    //! At the same time, p-code is collected to reevaluate it later. An    //! array is returned which contains the result in the first element    //! and the generated @[RXML.PCode] object in the second. If    //! @[stale_safe] is nonzero, the p-code object will be an instance    //! of @[RXML.RenewablePCode] instead, which never fails due to -  //! being stale. +  //! being stale. The tag set defaults to @[tag_set], but it may be +  //! overridden with @[tag_set_override].    {    int orig_make_p_code = make_p_code, orig_state_updated = state_updated;    int orig_top_frame_flags = frame && frame->flags;    PCODE_UPDATE_MSG ("%O: Saved p-code update count %d before eval_and_compile\n",    this_object(), orig_state_updated); -  +  if (!tag_set_override) tag_set_override = tag_set;    make_p_code = 1;    Parser parser = type->get_parser ( -  this_object(), tag_set, 0, stale_safe ? RenewablePCode (0) : PCode (0)); +  this_object(), tag_set_override, 0, stale_safe ? RenewablePCode (0) : PCode (0));       mixed res;    PCode p_code;
2047:    p_code = parser->p_code;    };    -  type->give_back (parser, tag_set); +  type->give_back (parser, tag_set_override);    PCODE_UPDATE_MSG ("%O: Restoring p-code update count from %d to %d "    "after eval_and_compile\n",    this_object(), state_updated, orig_state_updated);
2336:    if (!no_msg) add ("RXML", type ? " " + type : "", " error");    if (context) {    if (!no_msg) add (": ", msg || "(no error message)\n"); -  if (current_var) add (" | &", current_var, ";\n"); +  if (current_var && current_var != "") add (" | ", current_var, "\n");    for (int i = 0; i < sizeof (frames); i++) {    Frame f = frames[i];    string name; -  +  if (f->format_rxml_backtrace_frame) { +  string res = f->format_rxml_backtrace_frame(); +  if (res != "") add (" | ", res, "\n"); +  } +  else {    if (f->tag) name = f->tag->name;    //else if (!f->up) break;    else name = "(unknown)";
2360:    }    }    } +  }    else    if (!no_msg) add (" (no context): ", msg || "(no error message)\n");    return txt->get();
2933:    //! each iteration). This variable is not automatically saved and    //! restored (see @[save] and @[restore]).    +  optional string format_rxml_backtrace_frame(); +  //! Define this to control how the frame is formatted in RXML +  //! backtraces. The returned string should be one line, without a +  //! trailing newline. It should not contain the " | " prefix. +  //! +  //! The empty string may be returned to suppress the backtrace frame +  //! altogether. That might be useful for some types of internally +  //! used frames, but it should be used only if there are very good +  //! reasons; the backtrace easily just becomes confusing instead. +     // Services:       final mixed get_var (string|array(string|int) var, void|string scope_name,
3828:    }    if (flags & FLAG_UNPARSED) content = nil;    eval_state = EVSTAT_ENTERED; -  // Fall through. +        if (TagSet add_tags = [object(TagSet)] this_object()->additional_tags) {    TagSet tset = ctx->tag_set;
3843:    THIS_TAG_DEBUG ("Not installing additional_tags %O "    "since they're already in the tag set\n", add_tags);    } +  // Fall through.       case EVSTAT_ENTERED:    case EVSTAT_LAST_ITER:
4377:    if (arrayp (index)) idxpath = index, index = index[0];    else idxpath = ({0});    +  object val_obj; +  if (mixed err = catch {    for (int i = 1;; i++) {    // stringp was not really a good idea.    if( arrayp( val ) /*|| stringp( val )*/ )
4398:    scope_name, format_short (index));    }    else if( objectp( val ) && val->`[] ) { - #ifdef MODULE_DEBUG -  Scope scope = [object(Scope)] val; - #endif +  val_obj = val;    if (zero_type (    val = ([object(Scope)] val)->`[](    index, ctx, scope_name,
4412: Inside #if defined(MODULE_DEBUG)
   catch (want_type->type_check (val)))    if (objectp (err) && ([object] err)->is_RXML_Backtrace)    fatal_error ("%O->`[] didn't return a value of the correct type:\n%s", -  scope, err->msg); +  val_obj, err->msg);    else throw (err);   #endif -  +  val_obj = 0;    }    else if( mappingp( val ) || objectp (val) ) {    if (zero_type (val = val[ index ])) val = nil;
4446: Inside #if defined(MODULE_DEBUG)
   format_short (val), indices (called));    called[val] = 1;   #endif +  val_obj = val;    if (zero_type (val = ([object(Value)] val)->rxml_var_eval (    ctx, index, scope_name, 0))) {    val = nil; -  +  val_obj = 0;    break;    } -  +  val_obj = 0;    }    }   
4474: Inside #if defined(MODULE_DEBUG)
   "All called objects:%{ %O%}\n",    format_short (val), indices (called));    called[val] = 1; -  Value val_obj = [object(Value)] val; +    #endif -  +  val_obj = val;    if (zero_type (val = ([object(Value)] val)->rxml_var_eval (    ctx, index, scope_name, want_type)) ||    val == nil)
4489:   #endif    } while (objectp (val) && ([object] val)->rxml_var_eval);    return val; +  +  }) { +  if (objectp (err) && ([object] err)->is_RXML_Backtrace && +  val_obj && val_obj->format_rxml_backtrace_frame) +  if (mixed err2 = catch { +  err->current_var = val_obj->format_rxml_backtrace_frame (ctx, index, scope_name); +  }) +  master()->handle_error (err2); +  throw (err);    } -  + }      final void tag_debug (string msg, mixed... args)   //! Writes the message to the debug log if the innermost tag being
4545:   final class parse_frame   {    inherit Frame; -  constant name = "(parse_frame)"; // Only for debug output, like rxml backtraces. +     int flags = FLAG_UNPARSED|FLAG_PROC_INSTR; // Make it a PI so we avoid the argmap.       static void create (Type type, string to_parse)
4701:    catch (parse_error ("No scope in variable reference.\n"    "(Use ':' in front to quote a "    "character reference containing dots.)\n")); -  err->current_var = varref; +  err->current_var = "&" + varref + ";";    context->handle_exception (err, this_object(), 1);    val = nil;    }
4737:   #endif       }) { -  if (objectp (err) && err->is_RXML_Backtrace) err->current_var = varref; +  if (objectp (err) && err->is_RXML_Backtrace && !err->current_var) +  err->current_var = "&" + varref + ";";    if ((err = catch {    context->handle_exception (err, this_object()); // May throw.    })) {
6373:    return val;    };    -  if (objectp (err) && err->is_RXML_Backtrace) err->current_var = VAR_STRING; +  if (objectp (err) && err->is_RXML_Backtrace) +  err->current_var = "&" + VAR_STRING + ";";    FRAME_DEPTH_MSG ("%*s%O frame_depth decrease line %d\n",    ctx->frame_depth, "", this_object(), __LINE__);    ctx->frame_depth--;