2000-02-13
2000-02-13 11:03:32 by Martin Stjernholm <mast@lysator.liu.se>
-
49897a0d65e159d301226810b821aa4d6786d62c
(522 lines)
(+303/-219)
[
Show
| Annotate
]
Branch: 5.2
Fixed `->= misconception. Added parse_frame(). Fixed assorted
evaluation bugs. Added t_none.
Rev: server/etc/modules/RXML.pmod/module.pmod:1.52
2:
//!
//! Created 1999-07-30 by Martin Stjernholm.
//!
- //! $Id: module.pmod,v 1.51 2000/02/13 02:24:45 mast Exp $
+ //! $Id: module.pmod,v 1.52 2000/02/13 11:03:32 mast Exp $
//! Kludge: Must use "RXML.refs" somewhere for the whole module to be
//! loaded correctly.
417:
{
switch (var) {
case "imported":
- (imported - ({0}))->dont_notify (changed);
+ if (!val) return val; // Pike can call us with 0 as part of an optimization.
+ filter (imported, "dont_notify", changed);
imported = [array(TagSet)] val;
imported->do_notify (changed);
break;
1097:
#endif
- // Global services.
-
- void rxml_error (string msg, mixed... args)
- //! Tries to throw an error with rxml_error() in the current context.
- {
- Context ctx = get_context();
- if (ctx && ctx->rxml_error)
- ctx->rxml_error (msg, @args);
- else {
- if (sizeof (args)) msg = sprintf (msg, @args);
- msg = Context.rxml_error_prefix + " (no context): " + msg;
- array b = backtrace();
- throw (({msg, b[..sizeof (b) - 2]}));
- }
- }
-
- void rxml_fatal (string msg, mixed... args)
- //! Tries to throw a fatal error with rxml_fatal() in the current
- //! context.
- {
- Context ctx = get_context();
- if (ctx && ctx->rxml_fatal)
- ctx->rxml_fatal (msg, @args);
- else {
- if (sizeof (args)) msg = sprintf (msg, @args);
- msg = Context.rxml_fatal_prefix + " (no context): " + msg;
- array b = backtrace();
- throw (({msg, b[..sizeof (b) - 2]}));
- }
- }
-
- 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.
- {
- TagSet tag_set = get_context()->tag_set;
- object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag = tag_set->get_tag (name);
- if (arrayp (tag))
- 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.
- {
- TagSet tag_set = get_context()->tag_set;
- object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag = tag_set->get_tag (name);
- if (arrayp (tag))
- error ("Getting frames for low level tags are currently not implemented.\n");
- Frame frame = tag (args, content);
- frame->flags |= FLAG_UNPARSED;
- return frame;
- }
-
-
+
//! Constants for the bit field RXML.Frame.flags.
constant FLAG_NONE = 0x00000000;
1185:
//! The rest of the flags are dynamic (i.e. tested in the Frame object).
constant FLAG_PARENT_SCOPE = 0x00000100;
- //! If set, the array from do_return() and cached_return() will be
- //! interpreted in the scope of the parent tag, rather than in the
- //! current one.
+ //! If set, the array from do_enter(), do_return() and cached_return()
+ //! will be interpreted in the scope of the parent tag, rather than in
+ //! the current one.
constant FLAG_NO_IMPLICIT_ARGS = 0x00000200;
//! If set, the parser won't apply any implicit arguments. FIXME: Not
1208:
constant FLAG_STREAM = FLAG_STREAM_RESULT | FLAG_STREAM_CONTENT;
+ constant FLAG_UNPARSED = 0x00001000;
+ //! If set, args and content in the frame contain unparsed strings.
+ //! The frame will be parsed before it's evaluated. This flag should
+ //! never be set in Tag.flags, but it's useful when creating frames
+ //! directly.
+
//! The following flags specifies whether certain conditions must be
//! met for a cached frame to be considered (if RXML.Frame.is_valid()
//! is defined). They may be read directly after do_return() returns.
1238:
//! the final result. On a cache hit it'll be executed like the return
//! value from do_return() to produce the result.
- constant FLAG_UNPARSED = 0x80000000;
- //! Only used internally. Signifies that args and content in the frame
- //! contain unparsed strings.
-
+
class Frame
//! A tag instance.
{
1308:
//! do_iterate(). do_return() is called after each iteration.
//!
//! The result_type variable is set to the type of result the parser
- //! wants. It's any type that is valid by tag->result_type. If the
- //! result type is sequential, it's spliced into the surrounding
- //! content, otherwise it replaces the previous value of the
- //! content, if any. If the result is Void, it does not affect the
- //! surrounding content at all.
+ //! wants. It's any type or subtype that is valid by
+ //! tag->result_type. If the result type is sequential, it's spliced
+ //! into the surrounding content, otherwise it replaces the previous
+ //! value of the content, if any. If the result is Void, it does not
+ //! affect the surrounding content at all.
//!
//! Return values:
//!
1580:
// Unwind state data:
//raw_content
- #define ESTATE_BEGIN 0
- #define ESTATE_ENTERED 1
- #define ESTATE_LAST_ITER 2
- int eval_state = ESTATE_BEGIN;
+ #define EVSTAT_BEGIN 0
+ #define EVSTAT_ENTERED 1
+ #define EVSTAT_LAST_ITER 2
+ #define EVSTAT_ITER_DONE 3
+ int eval_state = EVSTAT_BEGIN;
int iter;
Parser subparser;
mixed piece;
1647:
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;
if (sizeof (atypes) < sizeof (tag->req_arg_types)) {
1671:
}
#endif
}
- #ifdef DEBUG
- if (!args) error ("Internal error: args not set.\n");
+ }
+
+ #ifdef MODULE_DEBUG
+ if (!args) error ("args not set.\n");
#endif
if (TagSet add_tags = raw_content && [object(TagSet)] this->additional_tags) {
1691:
#endif
Type ptype = parser->type;
foreach (tag->result_types, Type rtype)
- if (ptype->subtype_of (rtype)) {result_type = rtype; break;}
+ if (ptype == rtype) {
+ result_type = rtype;
+ break;
+ }
+ else if (ptype->subtype_of (rtype)) {
+ result_type = ptype (rtype->_parser_prog);
+ break;
+ }
if (!result_type) // Sigh..
rxml_fatal (
"Tag returns " +
1710:
}
mixed err = catch {
- if (eval_state == ESTATE_BEGIN)
+ switch (eval_state) {
+ case EVSTAT_BEGIN:
if (array|function(RequestID,void|mixed:array) do_enter =
[array|function(RequestID,void|mixed:array)] this->do_enter) {
- if (!exec) exec = do_enter (ctx->id); // Might unwind.
+ if (!exec) exec = do_enter (ctx->id); // Might unwind.
if (exec) {
mixed res = _exec_array (parser, exec); // Might unwind.
if (flags & FLAG_STREAM_RESULT) {
1731:
}
}
}
- eval_state = ESTATE_ENTERED;
+ eval_state = EVSTAT_ENTERED;
-
+ case EVSTAT_ENTERED:
+ case EVSTAT_LAST_ITER:
do {
- if (eval_state != ESTATE_LAST_ITER) {
+ if (eval_state != EVSTAT_LAST_ITER) {
int|function(RequestID:int) do_iterate =
[int|function(RequestID:int)] this->do_iterate;
if (intp (do_iterate)) {
iter = [int] do_iterate || 1;
- eval_state = ESTATE_LAST_ITER;
+ eval_state = EVSTAT_LAST_ITER;
}
else
if (!(iter = (/*[function(RequestID:int)]HMM*/ do_iterate
) (ctx->id))) // Might unwind.
- eval_state = ESTATE_LAST_ITER;
+ eval_state = EVSTAT_LAST_ITER;
}
ENTER_SCOPE (ctx, this);
for (; iter > 0; iter--) {
- if (raw_content) { // Got nested parsing to do.
+ if (raw_content) { // Got nested parsing to do.
if (ctx->new_runtime_tags) {
// Empty this first in case do_enter() set it.
_handle_runtime_tags (parser, ctx->new_runtime_tags);
1757:
}
int finished = 0;
- if (!subparser) { // The nested content is not yet parsed.
+ if (!subparser) { // The nested content is not yet parsed.
subparser = content_type->get_parser (
ctx, [object(TagSet)] this->local_tags);
subparser->_parent = parser;
1787: Inside #if defined(DEBUG)
error ("Internal error: "
"Clobbering unwind_state->stream_piece.\n");
#endif
- if (result_type->quoting_scheme != parser->type->quoting_scheme)
+ if (result_type->quoting_scheme !=
+ parser->type->quoting_scheme)
res = parser->type->quote (res);
ctx->unwind_state->stream_piece = res;
throw (this);
1805:
}
if (finished) break;
}
- else { // The frame doesn't handle streamed content.
+ else { // The frame doesn't handle streamed content.
piece = Void;
if (finished) {
mixed res = subparser->eval(); // Might unwind.
1826:
if (!exec)
exec = functionp (do_return) ?
([function(RequestID,void|mixed:array)] do_return) (
- ctx->id) : // Might unwind.
+ ctx->id) : // Might unwind.
[array] do_return;
if (exec) {
mixed res = _exec_array (parser, exec); // Might unwind.
if (flags & FLAG_STREAM_RESULT) {
#ifdef DEBUG
if (ctx->unwind_state)
- error ("Internal error: Clobbering unwind_state to do streaming.\n");
+ error ("Internal error: Clobbering unwind_state "
+ "to do streaming.\n");
if (piece != Void)
error ("Internal error: Thanks, we think about how nice it must "
"be to play the harmonica...\n");
1848:
}
LEAVE_SCOPE (ctx, this);
- } while (eval_state != ESTATE_LAST_ITER);
+ } while (eval_state != EVSTAT_LAST_ITER);
- if (!this->do_return && result == Void && content_type->subtype_of (result_type))
+ case EVSTAT_ITER_DONE:
+ if (!this->do_return && result == Void)
+ if (result_type->_parser_prog == PNone) {
+ if (content_type->subtype_of (result_type))
result = content;
-
+ }
+ else
+ if (stringp (content_type)) {
+ eval_state = EVSTAT_ITER_DONE; // Only need to record this state here.
+ if (!exec) exec = ({content});
+ if (!(flags & FLAG_PARENT_SCOPE)) ENTER_SCOPE (ctx, this);
+ _exec_array (parser, exec); // Might unwind.
+ LEAVE_SCOPE (ctx, this);
+ }
+ }
if (ctx->new_runtime_tags) {
_handle_runtime_tags (parser, ctx->new_runtime_tags);
1942:
}
+ // Global services.
+
+ void rxml_error (string msg, mixed... args)
+ //! Tries to throw an error with rxml_error() in the current context.
+ {
+ Context ctx = get_context();
+ if (ctx && ctx->rxml_error)
+ ctx->rxml_error (msg, @args);
+ else {
+ if (sizeof (args)) msg = sprintf (msg, @args);
+ msg = Context.rxml_error_prefix + " (no context): " + msg;
+ array b = backtrace();
+ throw (({msg, b[..sizeof (b) - 2]}));
+ }
+ }
+
+ void rxml_fatal (string msg, mixed... args)
+ //! Tries to throw a fatal error with rxml_fatal() in the current
+ //! context.
+ {
+ Context ctx = get_context();
+ if (ctx && ctx->rxml_fatal)
+ ctx->rxml_fatal (msg, @args);
+ else {
+ if (sizeof (args)) msg = sprintf (msg, @args);
+ msg = Context.rxml_fatal_prefix + " (no context): " + msg;
+ array b = backtrace();
+ throw (({msg, b[..sizeof (b) - 2]}));
+ }
+ }
+
+ void error (string msg, mixed... args)
+ {
+ Context ctx = get_context();
+ array b = backtrace();
+ if (ctx && ctx->describe_rxml_backtrace)
+ throw (({msg + "RXML backtrace: " + ctx->describe_rxml_backtrace (ctx->frame, ctx->current_var), b[..sizeof (b) - 2]}));
+ else
+ throw (({msg, b[..sizeof (b) - 2]}));
+ }
+
+ 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.
+ {
+ TagSet tag_set = get_context()->tag_set;
+ object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag = tag_set->get_tag (name);
+ if (arrayp (tag))
+ 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.
+ {
+ TagSet tag_set = get_context()->tag_set;
+ object(Tag)|array(LOW_TAG_TYPE|LOW_CONTAINER_TYPE) tag = tag_set->get_tag (name);
+ if (arrayp (tag))
+ error ("Getting frames for low level tags are currently not implemented.\n");
+ Frame frame = tag (args, content);
+ frame->flags |= FLAG_UNPARSED;
+ return frame;
+ }
+
+ class parse_frame /* (Type type, string to_parse) */
+ //! Returns a frame that, when evaluated, parses the given string
+ //! according to the type (which typically has a parser set).
+ {
+ inherit Frame;
+ constant flags = FLAG_UNPARSED;
+ mapping(string:mixed) args = ([]);
+
+ void create (Type type, string to_parse)
+ {
+ content_type = type, result_type = type (PNone);
+ content = to_parse;
+ }
+
+ string _sprintf() {return sprintf ("parse_frame(%O)", content_type);}
+ }
+
+
//! Parsers.
2495:
}
TAny t_any = TAny();
+ static class TNone
+ //! A sequential type accepting only the empty value.
+ {
+ inherit Type;
+ constant name = "none";
+ constant sequential = 1;
+ VoidType empty_value = Void;
+ constant quoting_scheme = "none";
+
+ void type_check (mixed val)
+ {
+ if (val != Void) rxml_fatal ("A value is not accepted.\n");
+ }
+
+ mixed convert (mixed val)
+ {
+ type_check (val);
+ return Void;
+ }
+
+ string _sprintf() {return "RXML.t_none" + PAREN_CNT (__count);}
+ }
+ TNone t_none = TNone();
+
static class TSame
//! A magic type used in Tag.content_type.
{