2002-03-27
2002-03-27 20:45:01 by Martin Stjernholm <mast@lysator.liu.se>
-
030813b0fbfbed61280d36818d23c3d97115546e
(328 lines)
(+207/-121)
[
Show
| Annotate
]
Branch: 5.2
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--;