2001-06-20
2001-06-20 23:27:24 by Martin Stjernholm <mast@lysator.liu.se>
-
446bfa73f2de9e323fac50d58f5658b2dc104cf4
(576 lines)
(+305/-271)
[
Show
| Annotate
]
Branch: 5.2
Various p-code fixes, especially wrt error handling. The known bug with
compiled-in rxml backtraces is now fixed.
Rev: server/etc/modules/RXML.pmod/PEnt.pike:1.22
Rev: server/etc/modules/RXML.pmod/PXml.pike:1.58
Rev: server/etc/modules/RXML.pmod/module.pmod:1.169
Rev: server/etc/modules/RXML.pmod/utils.pmod:1.25
2:
//
// Created 1999-07-30 by Martin Stjernholm.
//
- // $Id: module.pmod,v 1.168 2001/06/19 00:24:21 mast Exp $
+ // $Id: module.pmod,v 1.169 2001/06/20 23:27:24 mast Exp $
// Kludge: Must use "RXML.refs" somewhere for the whole module to be
// loaded correctly.
68:
#define MAGIC_HELP_ARG
// #define OBJ_COUNT_DEBUG
// #define RXML_VERBOSE
- // #define PROFILE_PARSER
+
#ifdef RXML_OBJ_DEBUG
97:
# define OBJ_COUNT ""
#endif
- #ifdef PROFILE_PARSER
-
- #define PROFILE_ENTER(ctx, what) do { \
- ctx->profile[what] -= gethrtime(); \
- /* if (what == "rxml internal") trace (1); */ \
- } while (0)
-
- #define PROFILE_LEAVE(ctx, what) do { \
- /* if (what == "rxml internal") trace (0); */ \
- ctx->profile[what] += gethrtime(); \
- } while (0)
-
- #define PROFILE_SWITCH(ctx, from, to) do { \
- /* if (from == "rxml internal") trace (0); */ \
- int now = gethrtime(); \
- ctx->profile[from] += now; \
- ctx->profile[to] -= now; \
- /* if (to == "rxml internal") trace (1); */ \
- } while (0)
-
- #else
- # define PROFILE_ENTER(ctx, what) do ; while (0)
- # define PROFILE_LEAVE(ctx, what) do ; while (0)
- # define PROFILE_SWITCH(ctx, from, to) do ; while (0)
- #endif
-
+
#ifdef RXML_VERBOSE
# define TAG_DEBUG_TEST(flags) 1
#elif defined (DEBUG)
358:
#define EVAL_FRAME(_frame, _ctx, _parser, _type, _args, _content, _res) \
eval_frame: do { \
+ EVAL_ARGS_FUNC argfunc = 0; \
+ \
mixed err = catch { \
- EVAL_ARGS_FUNC argfunc; \
+
if (!_frame->args) \
argfunc = _frame->_prepare (_ctx, _type, _args); \
_res = _frame->_eval (_ctx, _parser, _type, _content || ""); \
370:
break eval_frame; \
}; \
\
+ if (_parser->p_code) { \
+ /* Make an unparsed frame in the p-code if the evaluation \
+ * fails. */ \
+ _frame->flags |= FLAG_UNPARSED; \
+ _frame->args = _args, _frame->content = _content || ""; \
+ _parser->p_code->add (_frame); \
+ } \
+ \
if (objectp (err) && ([object] err)->thrown_at_unwind) { \
UNWIND_STATE ustate = _ctx->unwind_state; \
if (!ustate) ustate = _ctx->unwind_state = ([]); \
414:
void|string content)
{
Type type = parser->type;
- if (type->handle_literals) parser->handle_literal();
- else if (parser->p_code) parser->p_code_literal();
+ parser->drain_output();
Context ctx = parser->context;
428:
mixed result;
EVAL_FRAME (frame, ctx, parser, type, args, content, result);
- if (result != nil) {
- if (type->free_text && !parser->p_code) return ({result});
- parser->add_value (result);
- }
+ if (result != nil) parser->add_value (result);
return ({});
}
final array _p_xml_handle_pi_tag (object/*(PXml)*/ parser, string content)
{
Type type = parser->type;
- if (type->handle_literals) parser->handle_literal();
- else if (parser->p_code) parser->p_code_literal();
+ parser->drain_output();
sscanf (content, "%[ \t\n\r]%s", string ws, string rest);
if (ws == "" && rest != "") {
461:
mixed result;
EVAL_FRAME (frame, ctx, parser, type, 0, content, result);
- if (result != nil) {
- if (type->free_text && !parser->p_code) return ({result});
- parser->add_value (result);
- }
+ if (result != nil) parser->add_value (result);
return ({});
}
794:
final Parser `() (Type top_level_type, void|RequestID id, void|int make_p_code)
//! For compatibility. Use @[get_parser] instead.
{
- // Temporary measure to catch places to update.
- werror ("Old RXML.TagSet.`() used:\n" + describe_backtrace (backtrace()));
+
return get_parser (top_level_type, id, make_p_code);
}
1187:
//! set.
#endif
- #ifdef PROFILE_PARSER
- mapping(string:int) profile = ([]);
- #endif
-
+
array(string|int) parse_user_var (string var, void|string|int scope_name)
//! Parses the var string for scope and/or subindexes according to
//! the RXML rules, e.g. @tt{"scope.var.1.foo"@}. Returns an array
1551:
return unwind_state && unwind_state->reason == "streaming";
}
- void handle_exception (mixed err, PCode|Parser evaluator)
+ void handle_exception (mixed err, PCode|Parser evaluator, void|int compile_error)
//! This function gets any exception that is catched during
//! evaluation. evaluator is the object that catched the error.
{
1574:
}
else
msg = err->msg;
- if (evaluator->report_error (msg))
+ if (evaluator->report_error (msg)) {
+ if (compile_error && evaluator->p_code)
+ evaluator->p_code->add (CompiledError (err));
return;
}
-
+ }
throw (err);
}
else throw_fatal (err);
1597:
Frame prev_top_frame = frame;
frame = 0;
mixed err = catch {
- Parser parser = type->get_pcode_parser (this_object(), tag_set);
+ Parser parser = type->get_parser (this_object(), tag_set, 0, 1);
parser->write_end (to_parse);
res = parser->eval();
p_code = parser->p_code;
1610:
//(!) Internals:
- string current_var;
- // Used to get the parsed variable into the RXML error backtrace.
-
+
final Parser new_parser (Type top_level_type, void|int make_p_code)
// Returns a new parser object to start parsing with this context.
// Normally TagSet.`() should be used instead of this.
1620: Inside #if defined(MODULE_DEBUG)
#ifdef MODULE_DEBUG
if (in_use || frame) fatal_error ("Context already in use.\n");
#endif
- return make_p_code ?
- top_level_type->get_pcode_parser (this_object(), tag_set) :
- top_level_type->get_parser (this_object(), tag_set);
+ return top_level_type->get_parser (this_object(), tag_set, 0, make_p_code);
}
#ifdef DEBUG
private int eval_finished = 0;
-
+ private mixed foo;
#endif
final void eval_finish()
1634:
{
if (!frame_depth && tag_set) {
#ifdef DEBUG
- if (eval_finished) fatal_error ("Context already finished.\n");
+ if (eval_finished) fatal_error ("Context already finished.\n" + foo);
eval_finished = 1;
-
+ foo = describe_backtrace (backtrace());
#endif
tag_set->call_eval_finish_funs (this_object());
}
1805:
{
type = _type;
msg = _msg;
- if (context = _context || RXML_CONTEXT) {
+ if (context = _context || RXML_CONTEXT)
frame = context->frame;
- current_var = context->current_var;
- }
+
if (_backtrace) backtrace = _backtrace;
else {
backtrace = predef::backtrace();
1820:
//! Returns a formatted RXML frame backtrace.
{
String.Buffer txt = String.Buffer();
- txt->add (no_msg ? "" : "RXML" + (type ? " " + type : "") + " error");
+ function(string:void) add = txt->add;
+ add (no_msg ? "" : "RXML" + (type ? " " + type : "") + " error");
if (context) {
- if (!no_msg) txt->add (": " + (msg || "(no error message)\n"));
- if (current_var) txt->add (" | &" + current_var + ";\n");
+ if (!no_msg) add (": " + (msg || "(no error message)\n"));
+ if (current_var) add (" | &" + current_var + ";\n");
for (Frame f = frame; f; f = f->up) {
string name;
if (f->tag) name = f->tag->name;
else if (!f->up) break;
else name = "(unknown)";
if (f->flags & FLAG_PROC_INSTR)
- txt->add (" | <?" + name + "?>\n");
+ add (" | <?" + name + "?>\n");
else {
- txt->add (" | <" + name);
+ add (" | <" + name);
if (mappingp (f->args))
foreach (sort (indices (f->args)), string arg) {
mixed val = f->args[arg];
- txt->add (" " + arg + "=");
- if (arrayp (val)) txt->add (map (val, error_print_val) * ",");
- else txt->add (error_print_val (val));
+ add (" " + arg + "=");
+ if (arrayp (val)) add (map (val, error_print_val) * ",");
+ else add (error_print_val (val));
}
- else txt->add (" (no argmap)");
- txt->add (">\n");
+ else add (" (no argmap)");
+ add (">\n");
}
}
}
else
- if (!no_msg) txt->add (" (no context): " + (msg || "(no error message)\n"));
+ if (!no_msg) add (" (no context): " + (msg || "(no error message)\n"));
return txt->get();
}
1900:
if (ctx->in_use && ctx->in_use != this_thread()) \
fatal_error ("Attempt to use context asynchronously.\n"); \
ctx->in_use = this_thread(); \
- } \
- PROFILE_ENTER (ctx, "rxml internal");
+ }
#define LEAVE_CONTEXT() \
- PROFILE_LEAVE (RXML_CONTEXT, "rxml internal"); \
+
if (Context ctx = RXML_CONTEXT) \
if (__old_ctx != ctx) ctx->in_use = 0; \
SET_RXML_CONTEXT (__old_ctx);
1913:
#define ENTER_CONTEXT(ctx) \
Context __old_ctx = RXML_CONTEXT; \
- SET_RXML_CONTEXT (ctx); \
- PROFILE_ENTER (ctx, "rxml internal");
+ SET_RXML_CONTEXT (ctx);
#define LEAVE_CONTEXT() \
- PROFILE_LEAVE (RXML_CONTEXT, "rxml internal"); \
+
SET_RXML_CONTEXT (__old_ctx);
#endif
2697:
#define LOW_CALL_CALLBACK(res, cb, args...) \
do { \
THIS_TAG_DEBUG ("Calling " #cb "\n"); \
- PROFILE_SWITCH (ctx, "rxml internal", "tag:" + tag->name); \
+
COND_PROF_ENTER(tag,tag->name,"tag"); \
res = (cb) (args); /* Might unwind. */ \
COND_PROF_LEAVE(tag,tag->name,"tag"); \
- PROFILE_SWITCH (ctx, "tag:" + tag->name, "rxml internal"); \
+
} while (0)
#define EXEC_CALLBACK(ctx, evaler, exec, cb, args...) \
2808:
#endif
up = ctx->frame;
ctx->frame = this; // Push the frame to get proper backtraces.
- if (ctx->frame_depth++ >= ctx->max_frame_depth) {
- ctx->frame_depth--;
+ if (ctx->frame_depth++ >= ctx->max_frame_depth)
_run_error ("Too deep recursion -- exceeding %d nested tags.\n",
ctx->max_frame_depth);
- }
+
EVAL_ARGS_FUNC func;
2855:
if (splice_arg) {
// Note: This assumes an XML-like parser.
- Parser p = splice_arg_type->get_pcode_parser (ctx, 0, 0);
+ Parser p = splice_arg_type->get_parser (ctx, 0, 0, 1);
THIS_TAG_DEBUG ("Evaluating splice argument %s\n",
utils->format_short (splice_arg));
#ifdef MODULE_DEBUG
2877:
comp->bind (_eval_args),
p->p_code->_compile_text (comp),
comp->bind (splice_req_types)));
- p->p_code = 0;
+
splice_arg_type->give_back (p);
args = _eval_args (ctx, xml_tag_parser->parse_tag_args (splice_arg || ""),
splice_req_types);
2893:
foreach (indices (raw_args), string arg) {
Type t = atypes[arg] || tag->def_arg_type;
if (t->parser_prog != PNone) {
- Parser parser = t->get_pcode_parser (ctx, 0, 0);
+ Parser parser = t->get_parser (ctx, 0, 0, 1);
THIS_TAG_DEBUG ("Evaluating argument value %s with %O\n",
utils->format_short (raw_args[arg]), parser);
parser->finish (raw_args[arg]); // Should not unwind.
2903:
utils->format_short (args[arg]));
fn_text->add (sprintf ("%O: %s,\n", arg,
parser->p_code->_compile_text (comp)));
- parser->p_code = 0;
+
t->give_back (parser);
}
else {
3051:
#endif
#undef PRE_INIT_ERROR
+ // Known punt: Sometimes _prepare is run below, which increases
+ // this too. So frame_depth might be off by one sometimes, but
+ // it's not worth the bother.
+ ctx->frame_depth++;
+
mixed conv_result = nil; // Result converted to the expected type.
mixed err1 = 0;
3063:
fatal_error ("Can't feed new content when resuming parse.\n");
#endif
ctx->frame = this;
- ctx->frame_depth++;
+
object ignored;
[ignored, eval_state, in_args, in_content, iter,
subevaler, piece, exec, orig_tag_set, ctx->new_runtime_tags
3089:
#endif
}
- if (in_content) {
- THIS_TAG_TOP_DEBUG ("Evaluating\n");
- ctx->frame = this;
- ctx->frame_depth++;
- if (functionp (args)) {
- THIS_TAG_DEBUG ("Evaluating compiled arguments\n");
- in_args = args;
- args = in_args (ctx);
- }
- content = nil;
- }
- else if (flags & FLAG_UNPARSED) {
+ if (flags & FLAG_UNPARSED) {
#ifdef DEBUG
if (args && !mappingp (args))
fatal_error ("args is not a mapping in unparsed frame.\n");
3110:
THIS_TAG_TOP_DEBUG ("Evaluating unparsed\n");
in_args = _prepare (ctx, type, args);
ctx->frame = this;
- ctx->frame_depth++;
+
in_content = content;
content = nil;
flags &= ~FLAG_UNPARSED;
}
-
+ else if (in_content) {
+ THIS_TAG_TOP_DEBUG ("Evaluating\n");
+ ctx->frame = this;
+ if (functionp (args)) {
+ THIS_TAG_DEBUG ("Evaluating compiled arguments\n");
+ in_args = args;
+ args = in_args (ctx);
+ }
+ content = nil;
+ }
else {
_prepare (ctx, type, 0);
ctx->frame = this;
- ctx->frame_depth++;
+
THIS_TAG_TOP_DEBUG ("Evaluating with constant arguments and content.\n");
}
3232:
parse_error ("This tag doesn't handle content.\n");
else { // The nested content is not yet parsed.
if (this->local_tags) {
- subevaler = content_type->get_pcode_parser (
- ctx, [object(TagSet)] this->local_tags, evaler);
+ subevaler = content_type->get_parser (
+ ctx, [object(TagSet)] this->local_tags, evaler, 1);
subevaler->_local_tag_set = 1;
THIS_TAG_DEBUG ("Iter[%d]: Parsing and evaluating content %s "
"with %O from local_tags\n", debug_iter,
utils->format_short (in_content), subevaler);
}
else {
- subevaler = content_type->get_pcode_parser (ctx, 0, evaler);
+ subevaler = content_type->get_parser (ctx, 0, evaler, 1);
#ifdef DEBUG
if (content_type->parser_prog != PNone)
THIS_TAG_DEBUG ("Iter[%d]: Parsing and evaluating content %s "
3248:
utils->format_short (in_content), subevaler);
#endif
}
- if (evaler->recover_errors && !(flags & FLAG_DONT_RECOVER))
+ if (evaler->recover_errors && !(flags & FLAG_DONT_RECOVER)) {
subevaler->recover_errors = 1;
-
+ subevaler->p_code->recover_errors = 1;
+ }
subevaler->finish (in_content); // Might unwind.
(in_content = subevaler->p_code)->finish();
finished = 1;
3895:
throw_fatal (err);
}
LEAVE_CONTEXT();
- #ifdef PROFILE_PARSER
- werror ("Profile for %s: %O\n", context->id->not_query, context->profile);
- #endif
+
}
mixed handle_var (TagSetParser|PCode evaler, string varref, Type want_type)
// Parses and evaluates a possible variable reference, with the
// appropriate error handling.
{
- if (mixed err = catch {
+ string encoding;
+ array(string|int) splitted;
+ mixed val;
+
// It's intentional that we split on the first ':' for now, to
// allow for future enhancements of this syntax. Scope and
// variable names containing ':' are thus not accessible this way.
- sscanf (varref, "%[^:]:%s", varref, string encoding);
- context->current_var = varref;
+ sscanf (varref, "%[^:]:%s", varref, encoding);
context->frame_depth++;
- array(string|int) splitted = context->parse_user_var (varref, 1);
- if (splitted[0] == 1)
- parse_error (
- "No scope in variable reference.\n"
- "(Use ':' in front to quote a character reference containing dots.)\n");
+ splitted = context->parse_user_var (varref, 1);
+ if (splitted[0] == 1) {
+ Backtrace err =
+ catch (parse_error ("No scope in variable reference.\n"
+ "(Use ':' in front to quote a "
+ "character reference containing dots.)\n"));
+ err->current_var = varref;
+ context->handle_exception (err, this_object(), 1);
+ val = nil;
+ }
+
+ else {
+ if (mixed err = catch {
#ifdef DEBUG
if (context->frame)
TAG_DEBUG (context->frame, " Looking up variable %s in context of type %s\n",
splitted * ".", (encoding ? t_any_text : want_type)->name);
#endif
- mixed val;
- PROFILE_SWITCH (context, "rxml internal", "var:" + varref);
+
COND_PROF_ENTER(mixed id=context->id,varref,"entity");
if (zero_type (val = context->get_var ( // May throw.
splitted[1..], splitted[0],
encoding ? t_any_text : want_type)))
val = nil;
COND_PROF_LEAVE(mixed id=context->id,varref,"entity");
- PROFILE_SWITCH (context, "var:" + varref, "rxml internal");
+
if (encoding) {
if (!(val = Roxen->roxen_encode (val + "", encoding)))
3948:
TAG_DEBUG (context->frame, " Got value %s\n", utils->format_short (val));
#endif
- context->current_var = 0;
- context->frame_depth--;
- if (evaler->p_code)
- evaler->p_code->add (VarRef (splitted[0], splitted[1..], encoding));
- return val;
-
+
}) {
- context->current_var = 0;
- context->frame_depth--;
+ if (err->is_RXML_Backtrace) err->current_var = varref;
context->handle_exception (err, this_object()); // May throw.
- return nil;
+ val = nil;
}
-
+
+ if (evaler->p_code)
+ evaler->p_code->add (VarRef (splitted[0], splitted[1..], encoding));
}
-
+ context->frame_depth--;
+ return val;
+ }
//(!) Interface:
4027:
//! The implementation must call @[context->eval_finish] after all
//! other evaluation is done and the input stream is finished.
- optional void reset (Context ctx, Type type, mixed... args);
+ optional void reset (Context ctx, Type type, PCode p_code, mixed... args);
//! Define to support reuse of a parser object. It'll be called
//! instead of making a new object for a new stream. It keeps the
//! static configuration, i.e. the type (and tag set when used in
4036:
//! @[TagSetParser] objects. It should call @[initialize] with the
//! given context and type to reset this base class properly.
- optional Parser clone (Context ctx, Type type, mixed... args);
+ optional Parser clone (Context ctx, Type type, PCode p_code, mixed... args);
//! Define to create new parser objects by cloning instead of
//! creating from scratch. It returns a new instance of this parser
//! with the same static configuration, i.e. the type (and tag set
//! when used in TagSetParser).
- static void create (Context ctx, Type type, mixed... args)
+ static void create (Context ctx, Type type, PCode p_code, mixed... args)
//! Should (at least) call @[initialize] with the given context and
//! type.
{
- initialize (ctx, type);
+ initialize (ctx, type, p_code);
#ifdef RXML_OBJ_DEBUG
__object_marker->create (this_object());
#endif
}
- static void initialize (Context ctx, Type _type)
+ static void initialize (Context ctx, Type _type, PCode _p_code)
//! Does the required initialization for this base class. Use from
//! @[create] and @[reset] (when it's defined) to initialize or
//! reset the parser object properly.
{
context = ctx;
type = _type;
-
+ p_code = _p_code;
}
string current_input() {return 0;}
4122:
//! In addition to the type, the tag set is part of the static
//! configuration.
- optional void reset (Context ctx, Type type, TagSet tag_set, mixed... args);
- optional Parser clone (Context ctx, Type type, TagSet tag_set, mixed... args);
- static void create (Context ctx, Type type, TagSet tag_set, mixed... args)
+ optional void reset (Context ctx, Type type, PCode p_code,
+ TagSet tag_set, mixed... args);
+ optional Parser clone (Context ctx, Type type, PCode p_code,
+ TagSet tag_set, mixed... args);
+ static void create (Context ctx, Type type, PCode p_code,
+ TagSet tag_set, mixed... args)
{
- initialize (ctx, type, tag_set);
+ initialize (ctx, type, p_code, tag_set);
#ifdef RXML_OBJ_DEBUG
__object_marker->create (this_object());
#endif
}
- static void initialize (Context ctx, Type type, TagSet _tag_set)
+ static void initialize (Context ctx, Type type, PCode p_code, TagSet _tag_set)
{
- ::initialize (ctx, type);
+ ::initialize (ctx, type, p_code);
tag_set = _tag_set;
- p_code = 0;
+
}
mixed read();
4180:
class PNone
//! The identity parser. It only returns its input.
{
+ static inherit String.Buffer;
inherit Parser;
- static string data = "";
- static int evalpos = 0;
-
+
PCode p_code;
int feed (string in)
{
- data += in;
+ add (in);
return 1;
}
void finish (void|string in)
{
- if (in) data += in;
- if (p_code) p_code->add (data);
+ if (in) add (in);
+ if (p_code) {
+ string data = get();
+ p_code->add (data);
+ add (data);
}
-
+ }
string eval()
{
- string res = data[evalpos..];
- evalpos = sizeof (data);
- return res;
+ return get();
}
- void reset (Context ctx)
+ void reset (Context ctx, Type type, PCode p_code)
{
- context = ctx;
- data = "";
- evalpos = 0;
+ initialize (ctx, type, p_code);
+ get();
}
-
+ static void create (Context ctx, Type type, PCode p_code)
+ {
+ initialize (ctx, type, p_code);
+ #ifdef RXML_OBJ_DEBUG
+ __object_marker->create (this_object());
+ #endif
+ }
+
string _sprintf() {return "RXML.PNone" + OBJ_COUNT;}
}
4334:
}
inline final Parser get_parser (Context ctx, void|TagSet tag_set,
- void|Parser parent)
- //! Returns a parser instance initialized with the given context.
+ void|Parser parent, void|int make_p_code)
+ //! Returns a parser instance initialized with the given context. If
+ //! @[make_p_code] is nonzero, the parser will be initialized with a
+ //! new @[PCode] object.
{
Parser p;
-
+ PCode p_code = make_p_code && PCode (this_object(), tag_set);
if (_p_cache) { // It's a tag set parser.
TagSet tset = tag_set || ctx->tag_set;
4346:
parent->clone && parent->type->name == this_object()->name) {
// There are runtime tags. Try to clone the parent parser if
// all conditions are met.
- p = parent->clone (ctx, this_object(), tset, @parser_args);
+ p = parent->clone (ctx, this_object(), p_code, tset, @parser_args);
p->_parent = parent;
return p;
}
4358:
pco->free_parser = p->_next_free;
// ^^^ Using interpreter lock to here.
p->data_callback = 0;
- p->reset (ctx, this_object(), tset, @parser_args);
+ p->reset (ctx, this_object(), p_code, tset, @parser_args);
#ifdef RXML_OBJ_DEBUG
p->__object_marker->create (p);
#endif
4367:
else
// ^^^ Using interpreter lock to here.
if (pco->clone_parser)
- p = pco->clone_parser->clone (ctx, this_object(), tset, @parser_args);
- else if ((p = parser_prog (ctx, this_object(), tset, @parser_args))->clone) {
+ p = pco->clone_parser->clone (
+ ctx, this_object(), p_code, tset, @parser_args);
+ else if ((p = parser_prog (
+ ctx, this_object(), p_code, tset, @parser_args))->clone) {
// pco->clone_parser might already be initialized here due
// to race, but that doesn't matter.
- p->context = 0; // Don't leave the context in the clone master.
+ p->context = p->p_code = 0; // Don't leave this stuff in the clone master.
#ifdef RXML_OBJ_DEBUG
p->__object_marker->create (p);
#endif
- p = (pco->clone_parser = p)->clone (ctx, this_object(), tset, @parser_args);
+ p = (pco->clone_parser = p)->clone (
+ ctx, this_object(), p_code, tset, @parser_args);
}
}
4384:
pco = PCacheObj();
pco->tag_set_gen = tset->generation;
_p_cache[tset] = pco; // Might replace an object due to race, but that's ok.
- if ((p = parser_prog (ctx, this_object(), tset, @parser_args))->clone) {
+ if ((p = parser_prog (
+ ctx, this_object(), p_code, tset, @parser_args))->clone) {
// pco->clone_parser might already be initialized here due
// to race, but that doesn't matter.
- p->context = 0; // Don't leave the context in the clone master.
+ p->context = p->p_code = 0; // Don't leave this stuff in the clone master.
#ifdef RXML_OBJ_DEBUG
p->__object_marker->create (p);
#endif
- p = (pco->clone_parser = p)->clone (ctx, this_object(), tset, @parser_args);
+ p = (pco->clone_parser = p)->clone (
+ ctx, this_object(), p_code, tset, @parser_args);
}
}
4405:
// Relying on interpreter lock here.
free_parser = p->_next_free;
p->data_callback = 0;
- p->reset (ctx, this_object(), @parser_args);
+ p->reset (ctx, this_object(), p_code, @parser_args);
#ifdef RXML_OBJ_DEBUG
p->__object_marker->create (p);
#endif
4413:
else if (clone_parser)
// Relying on interpreter lock here.
- p = clone_parser->clone (ctx, this_object(), @parser_args);
+ p = clone_parser->clone (ctx, this_object(), p_code, @parser_args);
- else if ((p = parser_prog (ctx, this_object(), @parser_args))->clone) {
+ else if ((p = parser_prog (ctx, this_object(), p_code, @parser_args))->clone) {
// clone_parser might already be initialized here due to race,
// but that doesn't matter.
- p->context = 0; // Don't leave the context in the clone master.
+ p->context = p->p_code = 0; // Don't leave this stuff in the clone master.
#ifdef RXML_OBJ_DEBUG
p->__object_marker->create (p);
#endif
- p = (clone_parser = p)->clone (ctx, this_object(), @parser_args);
+ p = (clone_parser = p)->clone (ctx, this_object(), p_code, @parser_args);
}
}
4430:
return p;
}
- Parser get_pcode_parser (Context ctx, void|TagSet tag_set, void|Parser|PCode parent)
- //! Like @[get_parser], but also initializes a PCode object in the
- //! returned parser.
- {
- if (_p_cache && !tag_set) tag_set = ctx->tag_set;
- Parser p = get_parser (ctx, tag_set, parent);
- p->p_code = PCode (this_object(), tag_set, p->recover_errors);
- return p;
- }
-
+
inline final void give_back (Parser parser, void|TagSet tag_set)
//! Returns the given parser object for reuse. Only has effect if
//! the parser implements @[Parser.reset]. If the parser is a tag
4450:
error ("Giving back parser to wrong type.\n");
#endif
if (parser->reset) {
- parser->context = parser->recover_errors = parser->_parent = 0;
+ parser->context = parser->p_code = parser->recover_errors = parser->_parent = 0;
#ifdef RXML_OBJ_DEBUG
- parser->__object_marker->create (p);
+ parser->__object_marker->create (parser);
#endif
if (_p_cache) {
if (PCacheObj pco = _p_cache[tag_set]) {
5324:
}
String.Buffer res = String.Buffer();
- res->add ("<");
- res->add (tagname);
+ function(string:void) add = res->add;
+ add ("<");
+ add (tagname);
if (args)
if (flags & FLAG_RAW_ARGS)
foreach (indices (args), string arg) {
- res->add (" "), res->add (arg), res->add ("=\"");
- res->add (replace (args[arg], "\"", "\"'\"'\""));
- res->add ("\"");
+ add (" "), add (arg), add ("=\"");
+ add (replace (args[arg], "\"", "\"'\"'\""));
+ add ("\"");
}
else
foreach (indices (args), string arg) {
- res->add (" "), res->add (arg), res->add ("=");
- res->add (Roxen->html_encode_tag_value (args[arg]));
+ add (" "), add (arg), add ("=");
+ add (Roxen->html_encode_tag_value (args[arg]));
}
if (content) {
- res->add (">"), res->add (content);
- res->add ("</"), res->add (tagname), res->add (">");
+ add (">"), add (content);
+ add ("</"), add (tagname), add (">");
}
else
if (flags & FLAG_COMPAT_PARSE)
- if (flags & FLAG_EMPTY_ELEMENT) res->add (">");
- else res->add ("></"), res->add (tagname), res->add (">");
+ if (flags & FLAG_EMPTY_ELEMENT) add (">");
+ else add ("></"), add (tagname), add (">");
else
- res->add (" />");
+ add (" />");
return res->get();
}
5391:
//! A helper for representing variable reference tokens.
{
constant is_RXML_VarRef = 1;
+ constant is_RXML_p_code_entry = 1;
-
+ #define VAR_STRING ((({scope}) + (arrayp (var) ? \
+ (array(string)) var : ({(string) var}))) * ".")
+
mixed get (Context ctx, void|Type want_type)
{
-
+ ctx->frame_depth++;
+
+ mixed err = catch {
#ifdef DEBUG
if (ctx->frame)
TAG_DEBUG (ctx->frame, " Looking up variable %s.%s in context of type %s\n",
scope, arrayp (var) ? var * "." : var,
(encoding ? t_any_text : want_type)->name);
#endif
-
+ mixed val;
+ string varref;
if (encoding) {
- string val = ctx->get_var (var, scope, t_any_text);
+ COND_PROF_ENTER(mixed id=ctx->id,(varref = VAR_STRING),"entity");
+ val = ctx->get_var (var, scope, t_any_text);
+ COND_PROF_LEAVE(mixed id=ctx->id,varref,"entity");
if (!(val = Roxen->roxen_encode (val + "", encoding)))
parse_error ("Unknown encoding %O.\n", encoding);
#ifdef DEBUG
5410: Inside #if defined(DEBUG)
TAG_DEBUG (ctx->frame, " Got value %s after conversion "
"with encoding %s\n", utils->format_short (val), encoding);
#endif
- return val;
+
}
else {
- mixed val;
- if (zero_type (val = ctx->get_var (var, scope, want_type))) val = nil;
+ COND_PROF_ENTER(mixed id=ctx->id,(varref = VAR_STRING),"entity");
+ if (zero_type (val = ctx->get_var (var, scope, want_type)))
+ val = nil;
+ COND_PROF_LEAVE(mixed id=ctx->id,varref,"entity");
#ifdef DEBUG
if (ctx->frame)
TAG_DEBUG (ctx->frame, " Got value %s\n", utils->format_short (val));
#endif
-
+ }
+
+ ctx->frame_depth--;
return val;
-
+ };
+
+ if (err->is_RXML_Backtrace) err->current_var = VAR_STRING;
+ ctx->frame_depth--;
+ throw (err);
}
- }
+
mixed set (Context ctx, mixed val) {return ctx->set_var (var, val, scope);}
5434:
string _sprintf() {return "RXML.VarRef(" + name() + ")" + OBJ_COUNT;}
}
+ class CompiledError
+ //! A compiled-in error. Used when the parser handles an error, to get
+ //! the same behavior in the p-code.
+ {
+ constant is_RXML_ParseError = 1;
+ constant is_RXML_p_code_entry = 1;
+
+ string type;
+ string msg;
+ string current_var;
+
+ void create (Backtrace rxml_bt)
+ {
+ type = rxml_bt->type;
+ msg = rxml_bt->msg;
+ current_var = rxml_bt->current_var;
+ }
+
+ mixed get (Context ctx, void|Type want_type)
+ {
+ Backtrace bt = Backtrace (type, msg, ctx, backtrace());
+ bt->current_var = current_var;
+ throw (bt);
+ }
+ }
+
class PikeCompile
//! Helper class to paste together a Pike program from strings.
{
5586:
// Returns a compiled function for doing the evaluation. The
// function will receive a context to do the evaluation in.
- static void create (Type _type, void|TagSet _tag_set, void|int recover_errors)
+ static void create (Type _type, void|TagSet _tag_set)
{
type = _type, tag_set = _tag_set;
}
5618:
array parts;
int ppos = 0;
- if (mixed err = catch {
+
if (context && context->unwind_state) {
object ignored;
[ignored, pos, parts, ppos] = m_delete (context->unwind_state, this_object());
}
else parts = allocate (length);
-
+ while (1) { // Loops only if errors are catched.
+ if (mixed err = catch {
for (; pos < length; pos++) {
mixed item = p_code[pos];
if (objectp (item))
if (item->is_RXML_Frame) {
item = item->_eval (
context, this_object(), type, item->content); // Might unwind.
- if (errmsgs) item += errmsgs, errmsgs = 0;
+
}
- else if (item->is_RXML_VarRef) {
+ else if (item->is_RXML_p_code_entry) {
item = item->get (context, type); // Might unwind.
- if (errmsgs) item += errmsgs, errmsgs = 0;
+
}
if (item != nil)
parts[ppos++] = item;
-
+ if (errmsgs)
+ parts[ppos++] = errmsgs, errmsgs = 0;
}
context->eval_finish();
5657:
context->unwind_state[this_object()] = ({err, pos, parts, ppos});
throw (this_object());
}
- else throw_fatal (err);
+ else {
+ context->handle_exception (err, this_object()); // May throw.
+ string msgs = errmsgs;
+ errmsgs = 0;
+ if (pos >= length)
+ return msgs || nil;
+ else {
+ if (msgs) parts[ppos++] = msgs;
+ pos++;
+ continue;
}
-
+ }
-
+ error ("Should not get here.\n");
+ }
+ error ("Should not get here.\n");
+ }
+
string _compile_text (PikeCompile comp)
//! Returns a string containing a Pike expression that evaluates the
//! value of this @[PCode] object, assuming the current context is