/* * actions.h * * * Created by Andreas Vox on 02.06.06. * Copyright 2006 under GPL2. All rights reserved. * */ #ifndef ACTIONS_H #define ACTIONS_H #include #include #include "digester.h" namespace desaxe { /** * Action / Action_body follow the handle/body pattern. This allows to omit the * new operator when creating Action expressions and make dynamic memory handling * more secure. * Base class for the body of all actions. Usually Digester calls these methods, * but subclasses are also allowed to call those methods if they know what they are * doing... */ class Action_body { protected: Action_body() : dig(NULL) {} virtual ~Action_body() {} virtual void begin(const Xml_string&, Xml_attr) {} virtual void end(const Xml_string&) {} virtual void chars(const Xml_string&) {} Digester* dig; private: int refs; friend class Action; }; /** * Actions do all the real work when digesting XML files: creating new objects, * setting attributes, calling methods. Each Action gets control two or more times * for each time the corresponding rule triggers: 1 x begin(), 0- x chars(), 1 x end(). * They come in two basic flavors: Generators create a new object in their begin() * method and put it on the object stack. Other Actions use objects on the stack, * XML attributes or XML text to store this data in other objects. This is usually * done in the end() method. * Warning: end() methods are called in reverse order. This is to ensure that they * see exactly the same stack content as their corresponging begin() method. * This is the handle class which delegates to the body */ class Action { public: inline Digester* digester() { return body->dig; } inline void setDigester(Digester* dig) { body->dig = dig; } inline void begin(const Xml_string& tag, Xml_attr attr) { body->begin(tag, attr); } inline void end(const Xml_string& tag) { body->end(tag); } inline void chars(const Xml_string& data) { body->chars(data); } // Handle stuff: Action(const Action& other) { body = other.body; body->refs++; } virtual ~Action() { if (--body->refs == 0) delete body; } Action& operator=(const Action& other) { if (body != other.body) { if (--body->refs == 0) delete body; body = other.body; ++body->refs; } return *this; } protected: Action(Action_body* body_) { body = body_; body->refs = 1; } Action_body* body; private: Action(); // not defined }; class Dummy {}; /** * This class implements typed constructors. They are in a subclass since * we don't want the type arguments in Action itself. * Use "class MyAction : public MakeAction {} " to define * your own Actions. You have to implement MyAction constructors if you * want constructors with arguments. */ template struct MakeAction : public Action { MakeAction() : Action(new Body()) {} MakeAction(Arg1 a1) : Action(new Body(a1)) {} MakeAction(Arg1 a1, Arg2 a2) : Action(new Body(a1, a2)) {} MakeAction(Arg1 a1, Arg2 a2, Arg3 a3) : Action(new Body(a1, a2, a3)) {} MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4) : Action(new Body(a1, a2, a3, a4)) {} MakeAction(Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4, Arg5 a5) : Action(new Body(a1, a2, a3, a4, a5)) {} }; /** * Abstract class for actions which leave a new object on the stack * The begin() method is defined in subclasses and puts the object on stack, * the generic end() method removes this object from stack. */ template class Generator_body : public Action_body { public: virtual Type* eval(Digester* dig_, const Xml_string& tag, Xml_attr attr) { dig = dig_; begin(tag, attr); Type* res; res = dig->template top(); end(tag); return res; } protected: virtual void end(const Xml_string& ) { dig->pop(); } }; /** * Generators have their own handle class, which is a subclass of Action */ template class Generator : public Action { public: Type* eval(Digester* dig, const Xml_string& tag, Xml_attr attr) { return static_cast*>(body)->eval(dig, tag, attr); } protected: Generator(Generator_body* body_) : Action(body_) {} }; /** * This class implements typed constructors. They are in a subclass since * we don't want the type arguments in Generator itself. * Use "class MyGenerator : public MakeGenerator {} " to * define your own generators. You have to implement MyGenerator constructors if you * want constructors with arguments. */ template struct MakeGenerator : public Generator { MakeGenerator() : Generator(new Body()) {} MakeGenerator(Arg1 a) : Generator(new Body(a)) {} MakeGenerator(Arg1 a1, Arg2 a2) : Generator(new Body(a1, a2)) {} MakeGenerator(Arg1 a1, Arg2 a2, Arg3 a3) : Generator(new Body(a1, a2, a3)) {} }; } // namespace #endif