2000-06-23
2000-06-23 16:50:13 by Martin Stjernholm <mast@lysator.liu.se>
-
51f88b6e89b96ebcdd1f37b952a9d8e5e8cbb329
(301 lines)
(+248/-53)
[
Show
| Annotate
]
Branch: 5.2
Cache lookups of overridden tags. Added RXML.Frame.propagate_tag and
RXML.Frame.raw_tag_text. Added RXML.FLAG_COMPAT_PARSE. Added feature
to make frames for overridden tags in RXML.make_tag and
RXML.make_unparsed_tag.
Rev: server/etc/modules/RXML.pmod/module.pmod:1.91
2:
//!
//! Created 1999-07-30 by Martin Stjernholm.
//!
- //! $Id: module.pmod,v 1.90 2000/05/26 15:24:51 nilsson Exp $
+ //! $Id: module.pmod,v 1.91 2000/06/23 16:50:13 mast Exp $
//! Kludge: Must use "RXML.refs" somewhere for the whole module to be
//! loaded correctly.
196:
Context ctx = parser->context;
// FIXME: P-code generation.
- if (string splice_args = args["::"]) {
+ string splice_args;
+ if ((splice_args = args["::"])) {
// Somewhat kludgy solution for the time being.
-
+ #ifdef MODULE_DEBUG
+ if (mixed err = catch {
+ #endif
splice_args = t_text (PEnt)->eval (splice_args, ctx, 0, parser, 1);
-
+ #ifdef MODULE_DEBUG
+ }) {
+ if (objectp (err) && ([object] err)->thrown_at_unwind)
+ fatal_error ("Can't save parser state when evaluating splice argument.\n");
+ throw_fatal (err);
+ }
+ #endif
m_delete (args, "::");
args += parser->parse_tag_args (splice_args);
}
213:
else frame = `() (args, Void);
else frame = `() (args, Void);
+ if (!zero_type (frame->raw_tag_text))
+ if (splice_args)
+ frame->raw_tag_text =
+ t_xml->format_tag (parser->tag_name(), args, content, flags);
+ else frame->raw_tag_text = parser->current_input();
+
mixed err = catch {
frame->_eval (parser, args, content);
mixed res;
399:
//! In the latter case, the tag name must be given as the second
//! argument. The return value is the same as for get_local_tag().
{
- if (objectp (tagdef) && ([object] tagdef)->is_RXML_Tag)
- name = [string] ([object] tagdef)->name;
+ if (!mappingp (overridden_tag_lookup))
+ overridden_tag_lookup = set_weak_flag (([]), 1);
+ object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag;
+ if (zero_type (tag = overridden_tag_lookup[tagdef]))
+ if (objectp (tagdef) && ([object] tagdef)->is_RXML_Tag) {
+ tag = overridden_tag_lookup[tagdef] =
+ find_overridden_tag (tagdef, [string] ([object] tagdef)->name);
+ }
+ else {
#ifdef MODULE_DEBUG
if (!name) fatal_error ("Need tag name.\n");
#endif
- if (tags[name] == tagdef ||
- (low_containers && low_containers[name] == tagdef) ||
- (low_tags && low_tags[name] == tagdef)) {
- foreach (imported, TagSet tag_set)
- if (object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tagdef =
- tag_set->get_tag (name)) return tagdef;
+ mapping(LOW_TAG_TYPE|LOW_CONTAINER_TYPE:
+ array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE)) ent =
+ overridden_tag_lookup[name];
+ if (!ent) ent = overridden_tag_lookup[name] = ([]);
+ if (zero_type (tag = ent[tagdef]))
+ tag = ent[tagdef] = find_overridden_tag (tagdef, name);
}
- else {
- int found = 0;
- foreach (imported, TagSet tag_set)
- if (object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) subtag =
- tag_set->get_tag (name))
- if (found) return subtag;
- else if (arrayp (subtag) ?
- subtag[0] == tagdef || subtag[1] == tagdef :
- subtag == tagdef)
- if ((subtag = tag_set->get_overridden_tag (tagdef, name)))
- return subtag;
- else found = 1;
+ return tag;
}
- return 0;
- }
+
array(Tag|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE)) get_overridden_tags (string name)
//! Returns all tag definitions for the given name, i.e. including
499:
{
generation++;
prepare_funs = 0;
+ overridden_tag_lookup = 0;
plugins = ([]);
(notify_funcs -= ({0}))();
set_weak_flag (notify_funcs, 1);
549:
return funs;
}
+ static mapping(Tag:Tag|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE))|
+ mapping(string:mapping(LOW_TAG_TYPE|LOW_CONTAINER_TYPE:
+ Tag|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE)))
+ overridden_tag_lookup;
+
+ /*static*/ Tag|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) find_overridden_tag (
+ Tag|LOW_TAG_TYPE|LOW_CONTAINER_TYPE tagdef, string name)
+ {
+ if (tags[name] == tagdef ||
+ (low_containers && low_containers[name] == tagdef) ||
+ (low_tags && low_tags[name] == tagdef)) {
+ foreach (imported, TagSet tag_set)
+ if (object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tagdef =
+ tag_set->get_tag (name)) return tagdef;
+ }
+ else {
+ int found = 0;
+ foreach (imported, TagSet tag_set)
+ if (object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) subtag =
+ tag_set->get_tag (name))
+ if (found) return subtag;
+ else if (arrayp (subtag) ?
+ subtag[0] == tagdef || subtag[1] == tagdef :
+ subtag == tagdef)
+ if ((subtag = tag_set->find_overridden_tag (tagdef, name)))
+ return subtag;
+ else found = 1;
+ }
+ return 0;
+ }
+
void call_prepare_funs (Context ctx)
// Kludge function used from rxml.pike.
{
1103:
string current_var;
array backtrace;
- void create (void|string _type, void|string _msg, void|Context _context)
+ void create (void|string _type, void|string _msg, void|Context _context,
+ void|array _backtrace)
{
type = _type;
msg = _msg;
1111:
frame = context->frame;
current_var = context->current_var;
}
+ if (_backtrace) backtrace = _backtrace;
+ else {
backtrace = predef::backtrace();
backtrace = backtrace[..sizeof (backtrace) - 2];
}
-
+ }
string describe_rxml_backtrace (void|int no_msg)
//! Returns a formatted RXML frame backtrace.
1215:
//! Static flags (i.e. tested in the Tag object).
constant FLAG_EMPTY_ELEMENT = 0x00000001;
- //! If set, the tag does not use any content. E.g. with a HTML parser
+ //! If set, the tag does not use any content. E.g. with an HTML parser
//! this defines whether the tag is a container or not, and in XML
//! parsing it simply causes the content (if any) to be thrown away.
- constant FLAG_NO_PREFIX = 0x00000002;
+ constant FLAG_COMPAT_PARSE = 0x00000002;
+ //! Makes the PXml parser parse the tag in an HTML compatible way: If
+ //! FLAG_EMPTY_ELEMENT is set and the tag doesn't end with '/>', it
+ //! will be parsed as an empty element. The effect of this flag in
+ //! other parsers is currently undefined.
+
+ constant FLAG_NO_PREFIX = 0x00000004;
//! Never apply any prefix to this tag.
- constant FLAG_SOCKET_TAG = 0x00000004;
+ constant FLAG_SOCKET_TAG = 0x00000008;
//! Declare the tag to be a socket tag, which accepts plugin tags (see
//! Tag.plugin_name for details).
1353:
//! the content, instead of the one inherited from the surrounding
//! parser. The tags are not inherited by subparsers.
+ //!string raw_tag_text;
+ //! If this variable exists, it gets the raw text representation of
+ //! the tag, if there is any. Note that it's after parsing of any
+ //! splice argument.
+
//!array do_enter (RequestID id);
//!array do_process (RequestID id, void|mixed piece);
//!array do_return (RequestID id);
1392:
//! multiset(mixed) - Should only contain one element that'll be
//! added or put into the result. Normally not necessary;
//! assign it directly to the result variable instead.
+ //! propagate_tag() - Use a call to this function to propagate the
+ //! tag to be handled by an overridden tag definition, if
+ //! any exists. If this is used, it's probably necessary
+ //! to define the raw_tag_text variable. For further
+ //! details see the doc for propagate_tag() in this class.
//!
//! 0 - Do nothing special. Exits the tag when used from
//! do_process() and FLAG_STREAM_RESULT is set.
1533:
return get_context()->tag_set->get_plugins (tag->name);
}
+ Frame|string propagate_tag (void|mapping(string:string) args, void|string content)
+ //! This function is intended to be used in the execution array from
+ //! do_return() etc to propagate the tag to the next overridden tag
+ //! definition, if any exists. It either returns a frame from the
+ //! overridden tag or, if no overridden tag exists, a string
+ //! containing a formatted tag (which requires that the result type
+ //! supports formatted tags, i.e. has a working format_tag()
+ //! function). If args and content are given, they will be used in
+ //! the tag after parsing, otherwise the raw_tag_text variable is
+ //! used, which must have a string value.
+ {
+ Context ctx = get_context();
+ object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) overridden =
+ ctx->tag_set->get_overridden_tag (tag);
+ if (arrayp (overridden))
+ fatal_error ("Getting frames for low level tags are currently not implemented.\n");
+
+ if (overridden) {
+ Frame frame;
+ if (!args) {
+ #ifdef MODULE_DEBUG
+ if (zero_type (this_object()->raw_tag_text))
+ fatal_error ("The variable raw_tag_text must be defined.\n");
+ if (!stringp (this_object()->raw_tag_text))
+ fatal_error ("raw_tag_text must have a string value.\n");
+ #endif
+ Parser_HTML()
+ ->add_container (tag->name,
+ lambda (object p, mapping(string:string) a, string c) {
+ args = a;
+ content = c;
+ return ({});
+ })
+ ->finish (this_object()->raw_tag_text);
+ }
+ frame = overridden (args, content || "");
+ frame->flags |= FLAG_UNPARSED;
+ return frame;
+ }
+
+ else
+ if (args) return result_type->format_tag (tag, args, content);
+ else {
+ #ifdef MODULE_DEBUG
+ if (zero_type (this_object()->raw_tag_text))
+ fatal_error ("The variable raw_tag_text must be defined.\n");
+ if (!stringp (this_object()->raw_tag_text))
+ fatal_error ("raw_tag_text must have a string value.\n");
+ if (mixed err = catch {
+ #endif
+ return t_text (PEnt)->eval (this_object()->raw_tag_text, ctx, empty_tag_set);
+ #ifdef MODULE_DEBUG
+ }) {
+ if (objectp (err) && ([object] err)->thrown_at_unwind)
+ fatal_error ("Can't save parser state when evaluating arguments.\n");
+ throw_fatal (err);
+ }
+ #endif
+ }
+ }
+
// Internals.
mixed _exec_array (TagSetParser parser, array exec, int parent_scope)
1646:
void|mapping(string:string) raw_args,
void|string raw_content)
// Note: It might be somewhat tricky to override this function.
+ // Note: Might be destructive on raw_args.
{
Frame this = this_object();
Context ctx = parser->context;
1725:
ctx->frame = this;
if (raw_args) {
- args = raw_args;
+
if (sizeof (raw_args)) {
// Note: Code duplication in Tag.eval_args().
mapping(string:Type) atypes = raw_args & tag->req_arg_types;
1740: Inside #if defined(MODULE_DEBUG)
#ifdef MODULE_DEBUG
if (mixed err = catch {
#endif
- foreach (indices (args), string arg)
- args[arg] = (atypes[arg] || tag->def_arg_type)->
+ foreach (indices (raw_args), string arg)
+ raw_args[arg] = (atypes[arg] || tag->def_arg_type)->
eval (raw_args[arg], ctx, 0, parser, 1); // Should not unwind.
#ifdef MODULE_DEBUG
}) {
1751:
}
#endif
}
+ args = raw_args;
}
#ifdef MODULE_DEBUG
2111:
//! connection to an SQL server fails.
{
if (sizeof (args)) msg = sprintf (msg, @args);
- throw (Backtrace ("run", msg, get_context()));
+ array bt = backtrace();
+ throw (Backtrace ("run", msg, get_context(), bt[..sizeof (bt) - 2]));
}
void parse_error (string msg, mixed... args)
2121:
//! invalid arguments to a tag.
{
if (sizeof (args)) msg = sprintf (msg, @args);
- throw (Backtrace ("parse", msg, get_context()));
+ array bt = backtrace();
+ throw (Backtrace ("parse", msg, get_context(), bt[..sizeof (bt) - 2]));
}
void fatal_error (string msg, mixed... args)
2154:
throw (err);
}
- Frame make_tag (string name, mapping(string:mixed) args, void|mixed content)
- //! Returns a frame for the specified tag. The tag definition is
- //! looked up in the current context and tag set. args and content are
- //! not parsed or evaluated.
+ Frame make_tag (string name, mapping(string:mixed) args, void|mixed content,
+ void|Tag|LOW_TAG_TYPE|LOW_CONTAINER_TYPE overridden_by)
+ //! Returns a frame for the specified tag, or 0 if no such tag exists.
+ //! The tag definition is looked up in the current context and tag
+ //! set. args and content are not parsed or evaluated. If
+ //! overridden_by is given, the returned frame will come from the tag
+ //! that overridden_by overrides, if there is any.
{
TagSet tag_set = get_context()->tag_set;
- object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag = tag_set->get_tag (name);
+ object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag =
+ overridden_by ? tag_set->get_overridden_tag (overridden_by, name) :
+ tag_set->get_tag (name);
+ if (!tag) return 0;
if (arrayp (tag))
fatal_error ("Getting frames for low level tags are currently not implemented.\n");
return tag (args, content);
}
- Frame make_unparsed_tag (string name, mapping(string:string) args, void|string content)
- //! Returns a frame for the specified tag. The tag definition is
- //! looked up in the current context and tag set. args and content are
- //! given unparsed in this variant; they're parsed when the frame is
- //! about to be evaluated.
+ Frame make_unparsed_tag (string name, mapping(string:string) args, void|string content,
+ void|Tag|LOW_TAG_TYPE|LOW_CONTAINER_TYPE overridden_by)
+ //! Returns a frame for the specified tag, or 0 if no such tag exists.
+ //! The tag definition is looked up in the current context and tag
+ //! set. args and content are given unparsed in this variant; they're
+ //! parsed when the frame is about to be evaluated. If overridden_by
+ //! is given, the returned frame will come from the tag that
+ //! overridden_by overrides, if there is any.
{
TagSet tag_set = get_context()->tag_set;
- object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag = tag_set->get_tag (name);
+ object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag =
+ overridden_by ? tag_set->get_overridden_tag (overridden_by, name) :
+ tag_set->get_tag (name);
+ if (!tag) return 0;
if (arrayp (tag))
fatal_error ("Getting frames for low level tags are currently not implemented.\n");
Frame frame = tag (args, content);
2404:
#endif
}
+ string current_input() {return 0;}
+ //! Should return the representation in the input stream for the
+ //! current tag or entity being parsed, or 0 if it isn't known.
+
// Internals.
Parser _next_free;
2617:
return newtype;
}
+ string format_tag (string|Tag tag, void|mapping(string:string) args,
+ void|string content, void|int flags)
+ //! Returns a formatted tag according to the type. tag is either a
+ //! tag object or the name of the tag. Throws an error if this type
+ //! cannot format tags.
+ {
+ parse_error ("Cannot format tags with type %s.\n", this_object()->name);
+ }
+
+ string format_entity (string entity)
+ //! Returns a formatted entity according to the type. Throws an
+ //! error if this type cannot format entities.
+ {
+ parse_error ("Cannot format entities with type %s.\n", this_object()->name);
+ }
+
//! Services.
int `== (mixed other)
2756:
mixed eval (string in, void|Context ctx, void|TagSet tag_set,
void|Parser|PCode parent, void|int dont_switch_ctx)
- //! Convenience function to parse and evaluate the value in the
- //! given string. If a context isn't given, the current one is used.
- //! The current context and ctx are assumed to be the same if
- //! dont_switch_ctx is nonzero.
+ //! Parses and evaluates the value in the given string. If a context
+ //! isn't given, the current one is used. The current context and
+ //! ctx are assumed to be the same if dont_switch_ctx is nonzero.
{
mixed res;
if (!ctx) ctx = get_context();
2924:
return val;
}
+ string format_tag (string|Tag tag, void|mapping(string:string) args,
+ void|string content, void|int flags)
+ //! Returns a formatted XML tag. If tag is a Tag object, the flags
+ //! FLAG_COMPAT_PARSE and FLAG_EMPTY_ELEMENT are heeded when
+ //! formatting empty element tags.
+ {
+ string tagname;
+ if (objectp (tag)) tagname = tag->name, flags = tag->flags;
+ else tagname = tag;
+ string res = "<" + tagname;
+ if (args)
+ foreach (indices (args), string arg)
+ res += " " + arg + "=\"" + Roxen->html_encode_string (args[arg]) + "\"";
+ if (content)
+ res += ">" + content + "</" + tag->name + ">";
+ else
+ if (flags & FLAG_COMPAT_PARSE)
+ if (flags & FLAG_EMPTY_ELEMENT) res += ">";
+ else res += "></" + tag->name + ">";
+ else
+ res += " />";
+ return res;
+ }
+
+ string format_entity (string entity)
+ {
+ return "&" + entity + ";";
+ }
+
string _sprintf() {return "RXML.t_xml" + OBJ_COUNT;}
}
THtml t_xml = TXml();
3167:
static program PXml;
static program PEnt;
static program PExpr;
+ static program Parser_HTML;
+
void _fix_module_ref (string name, mixed val)
{
mixed err = catch {
3181:
};
if (err) werror (describe_backtrace (err));
}
+
+ void create()
+ {
+ Parser_HTML = master()->resolv ("Parser.HTML");
+ }