/* * simple_actions.h * * * Created by Andreas Vox on 02.06.06. * Copyright 2006 under GPL2. All rights reserved. * */ #ifndef SIMPLE_ACTIONS_H #define SIMPLE_ACTIONS_H #include "actions.h" /***** Defines the following actions: Factory( fun ) - -> D Factory() - -> D Prototype( data ) - -> D Top( 3 ) O x x x -> O x x x O Getter( fun ) O -> O D Setter( fun ) O D -> O D SetterWithConversion( fun ) O S -> O S SetAttribute( fun, name, default) O -> O SetAttribute( fun, name) O -> O SetAttributeWithConversion( f, n, c, def) O -> O SetAttributeWithConversion( f, n, convert) O -> O SetAttributes( fun ) O -> O SetText( fun ) O -> O AddText( fun ) O -> O Transform ( fun ) D -> E *TransformLater ( fun ) D -> E IdRef() O -> O Lookup( name ) - -> D PatchIdRefAttribute( fun, name) O -> O Result() O -> O *****/ namespace desaxe { using namespace desaxe; /** * Pushes a new object of type Obj_Type onto the stack. * Obj_Type needs a default constructor */ template class Factory_body : public Generator_body { public: typedef Obj_Type* (*FunType)(); Factory_body() : create_(NULL) {} Factory_body(FunType create) : create_(create) {} void begin(const Xml_string&, Xml_attr) { this->dig->push(create_? create_() : new Obj_Type()); } private: Obj_Type* (*create_)(); }; template struct Factory : public MakeGenerator, Type, typename Factory_body::FunType> { Factory(typename Factory_body::FunType create) : MakeGenerator, Type, typename Factory_body::FunType>(create) {} Factory() : MakeGenerator, Type, typename Factory_body::FunType>() {} }; /** * Pushes a new object of type Obj_Type onto the stack. */ template class FactoryWithArgs_body : public Generator_body { public: typedef Obj_Type* (*FunType)(const Xml_string&, Xml_attr); FactoryWithArgs_body(FunType create) : create_(create) {} void begin(const Xml_string& name, Xml_attr attr) { this->dig->push(create_(name, attr)); } private: Obj_Type* (*create_)(const Xml_string&, Xml_attr); }; template struct FactoryWithArgs : public MakeGenerator, Type, typename FactoryWithArgs_body::FunType> { FactoryWithArgs(typename FactoryWithArgs_body::FunType create) : MakeGenerator, Type, typename FactoryWithArgs_body::FunType>::MakeGenerator(create) {} }; /** * Pushes a new object of type Obj_Type onto the stack which is initialized with the tag name. * If no create method is given, Obj_Type needs a constructor which taks a Xml_string argument */ template class FactoryWithName_body : public Generator_body { public: typedef Obj_Type* (*FunType)(const Xml_string&); FactoryWithName_body() : create_(NULL) {} FactoryWithName_body(FunType create) : create_(create) {} void begin(const Xml_string& tag, Xml_attr) { this->dig->push(create_? create_(tag) : new Obj_Type(tag)); } private: FunType create_; }; template struct FactoryWithName : public MakeGenerator, Type, typename FactoryWithName_body::FunType> { FactoryWithName() : MakeGenerator, Type, typename FactoryWithName_body::FunType>::MakeGenerator() {} FactoryWithName(typename FactoryWithName_body::FunType create) : MakeGenerator, Type, typename FactoryWithName_body::FunType>::MakeGenerator(create) {} }; /** * Pushes a clone of proto onto the stack. Obj_Type needs a copy constructor */ template class Prototype_body : public Generator_body { public: Prototype_body(const Obj_Type& proto) : proto_(new Obj_Type(proto)) {} ~Prototype_body() { delete proto_; } void begin(const Xml_string&, Xml_attr) { this->dig->push(new Obj_Type(proto_)); } private: const Obj_Type* proto_; }; template struct Prototype : public MakeGenerator, Type, const Type&> { Prototype(const Type& def) : MakeGenerator, Type, const Type&>::MakeGenerator(def) {} }; /** * Pushes a new pointer to the n-th object on the stack. */ template class Top_body : public Generator_body { public: Top_body(unsigned int n) : distance(n) {} void begin(const Xml_string&, Xml_attr) { this->dig->push(this->dig->template top(distance)); } private: unsigned int distance; }; template struct Top : public MakeGenerator, Type, unsigned int> { Top(unsigned int distance) : MakeGenerator, Type, unsigned int>::MakeGenerator(distance) {} Top() : MakeGenerator, Type, unsigned int>::MakeGenerator(0) {} }; /** * Reads an object of type Data_Type from the object on top of the stack, * then pushes this Data_Type object onto the stack. */ template class Getter_body : public Generator_body { public: typedef const Data_Type& (Obj_Type::*FunType)(); Getter_body(FunType get) : get_(get) {} void begin(const Xml_string&, Xml_attr) { Obj_Type* obj = this->dig->template top(1); Data_Type* data = (obj->*get_)(); this->dig->push(data); } private: FunType get_; }; template struct Getter : public MakeGenerator, Data, typename Getter_body::FunType> { Getter(typename Getter_body::FunType get) : MakeGenerator, Data, typename Getter_body::FunType>::MakeGenerator(get) {} }; /** * Writes the topmost object to the topmost object but one on the stack, where the set method takes a pointer */ template class SetterP_body : public Action_body { public: typedef void (Obj_Type::*FunType)(Data_Type*); SetterP_body(FunType set) : set_(set) {} void end(const Xml_string&) { Store_Type* data = this->dig->template top(); Obj_Type* obj = this->dig->template top(1); #ifdef DESAXE_DEBUG std::cerr << "setter(ptr): " << obj << " .= " << data << "\n"; #endif (obj->*set_)( data ); } private: FunType set_; }; template struct SetterP : public MakeAction, typename SetterP_body::FunType> { SetterP(typename SetterP_body::FunType set) : MakeAction, typename SetterP_body::FunType>(set) {} }; /** * Writes the topmost object to the topmost object but one on the stack. */ template class Setter_body : public Action_body { public: typedef void (Obj_Type::*FunType)(Data_Type); Setter_body(FunType set) : set_(set) {} void end(const Xml_string&) { Data_Type* data = this->dig->template top(); Obj_Type* obj = this->dig->template top(1); #ifdef DESAXE_DEBUG std::cerr << "setter: " << obj << " .= *(" << data << ")\n"; #endif (obj->*set_)( *data ); } private: FunType set_; }; template struct Setter : public MakeAction, typename Setter_body::FunType> { Setter(typename Setter_body::FunType set) : MakeAction, typename Setter_body::FunType>(set) {} }; /** * Writes the topmost object to the topmost object but one on the stack. */ template class SetterWithConversion_body : public Action_body { public: typedef void (Obj_Type::*FunType)(Data_Type); typedef Data_Type (*ConvType)(Store_Type); SetterWithConversion_body(FunType set, ConvType conv) : set_(set), conv_(conv) {} void end(const Xml_string&) { Store_Type* data = this->dig->template top(); Obj_Type* obj = this->dig->template top(1); #ifdef DESAXE_DEBUG std::cerr << "setter: " << obj << " .= " << conv_ << "(*" << data << ")\n"; #endif if (conv_) (obj->*set_)( conv_(*data) ); else (obj->*set_)( static_cast(*data) ); } private: FunType set_; ConvType conv_; }; template struct SetterWithConversion : public MakeAction, typename SetterWithConversion_body::FunType, typename SetterWithConversion_body::ConvType> { typedef SetterWithConversion_body BodyType; SetterWithConversion(typename SetterWithConversion_body::FunType set) : MakeAction, typename SetterWithConversion_body::FunType, typename SetterWithConversion_body::ConvType>(set, NULL) {} SetterWithConversion(typename BodyType::FunType set, typename SetterWithConversion_body::ConvType conv) : MakeAction, typename SetterWithConversion_body::FunType, typename SetterWithConversion_body::ConvType>(set, conv) {} }; /** * Stores all attributes to the topmost object on the stack. */ template class SetAttributes_body : public Action_body { public: typedef void (Obj_Type::*FunType)(const Xml_string&, const Xml_string&) ; SetAttributes_body(FunType set) : set_(set) {} void begin(const Xml_string&, Xml_attr attr) { Obj_Type* obj = this->dig->template top(); Xml_attr::iterator it; for(it=attr.begin(); it != attr.end(); ++it) (obj->*set_)( Xml_key(it), Xml_data(it) ); } private: FunType set_; }; template struct SetAttributes : public MakeAction, typename SetAttributes_body::FunType> { SetAttributes(typename SetAttributes_body::FunType set) : MakeAction, typename SetAttributes_body::FunType>(set) {} }; /** * Stores named attribute to the topmost object on the stack if attribute present, * or stores defauot if present. */ template class SetAttribute_body : public Action_body { public: typedef void (Obj_Type::*FunType)(Data_Type) ; SetAttribute_body(FunType set, const Xml_string& name) : set_(set), name_(name), default_(), hasDefault_(false) {} SetAttribute_body(FunType set, const Xml_string& name, Data_Type deflt) : set_(set), name_(name), default_(deflt), hasDefault_(true) {} void begin(const Xml_string&, Xml_attr attr) { Obj_Type* obj = this->dig->template top(); Xml_attr::iterator it = attr.find(name_); if (it != attr.end() ) (obj->*set_)( Data_Type(Xml_data(it)) ); else if (hasDefault_) (obj->*set_)( default_ ); } private: FunType set_; Xml_string name_; Data_Type default_; bool hasDefault_; }; template struct SetAttribute : public MakeAction, typename SetAttribute_body::FunType, const Xml_string&, Data> { SetAttribute(typename SetAttribute_body::FunType set, const Xml_string& name) : MakeAction, typename SetAttribute_body::FunType, const Xml_string&, Data>(set,name) {} SetAttribute(typename SetAttribute_body::FunType set, const Xml_string& name, Data deflt) : MakeAction, typename SetAttribute_body::FunType, const Xml_string&, Data>(set,name,deflt) {} }; /** * Stores named attribute to the topmost object on the stack if attribute present, * or stores default if present. */ template class SetAttributeWithConversion_body : public Action_body { public: typedef void (Obj_Type::*FunType)(Data_Type) ; typedef Data_Type (*ConvType)(const Xml_string&); SetAttributeWithConversion_body(FunType set, const Xml_string& name, ConvType conv) : set_(set), name_(name), conv_(conv), default_(), hasDefault_(false) {} SetAttributeWithConversion_body(FunType set, const Xml_string& name, ConvType conv, Data_Type deflt) : set_(set), name_(name), conv_(conv), default_(deflt), hasDefault_(true) {} void begin(const Xml_string&, Xml_attr attr) { Obj_Type* obj = this->dig->template top(); Xml_attr::iterator it = attr.find(name_); if (it != attr.end() && conv_) (obj->*set_)( conv_(Xml_data(it)) ); else if (hasDefault_) (obj->*set_)( default_ ); } private: FunType set_; Xml_string name_; ConvType conv_; Data_Type default_; bool hasDefault_; }; template struct SetAttributeWithConversion : public MakeAction, typename SetAttributeWithConversion_body::FunType, const Xml_string&, typename SetAttributeWithConversion_body::ConvType, Data> { typedef SetAttributeWithConversion_body BodyType; SetAttributeWithConversion(typename BodyType::FunType set, const Xml_string& name, typename BodyType::ConvType conv) : MakeAction(set,name,conv) {} SetAttributeWithConversion(typename BodyType::FunType set, const Xml_string& name, typename BodyType::ConvType conv, Data deflt) : MakeAction(set,name,conv,deflt) {} }; /** * Stores text (PCDATA) in the topmost object on the stack. * This might be called more than once. */ template class AddText_body : public Action_body { public: typedef void (Obj_Type::*FunType)(const Xml_string&); AddText_body(FunType add) : addT(add) {} void chars(const Xml_string& txt) { Obj_Type* obj = this->dig->template top(); (obj->*addT)( txt ); } private: FunType addT; }; template struct AddText : public MakeAction, typename AddText_body::FunType> { AddText(typename AddText_body::FunType set) : MakeAction, typename AddText_body::FunType>(set) {} }; /** * Collects text (PCDATA) chunks and later stores it in the topmost object * on the stack. * This is only called once at the close tag of the current pattern. * WARNING: not safe for nesting */ template class SetText_body : public Action_body { public: typedef void (Obj_Type::*FunType)(const Xml_string&); SetText_body(FunType set) : setT(set) {} void begin(const Xml_string&, Xml_attr) { txt = ""; } void chars(const Xml_string& chunk) { txt += chunk; } void end(const Xml_string& tag) { Obj_Type* obj = this->dig->template top(); (obj->*setT)( txt ); } private: FunType setT; Xml_string txt; }; template struct SetText : public MakeAction, typename SetText_body::FunType> { typedef SetText_body BodyType; SetText(typename BodyType::FunType set) : MakeAction(set) {} }; template class Store_body : public Action_body { public: Store_body(const Xml_string& name) : m_name(name) {} void begin(const Xml_string& tag, Xml_attr attr) { Obj_Type* obj = this->dig->template top(); // qDebug() << QString("Store: %1 <- %2").arg(tag).arg(typeid(obj).name()); this->dig->template store(m_name, obj); } private: Xml_string m_name; }; template struct Store : public MakeAction, const Xml_string& > { Store(const Xml_string& name) : MakeAction, const Xml_string& >(name) {} }; /** * This applies "id" and "idref" attributes to the object on top of the stack. * In case of an "id" attribute, if there is no entry with this ID in * the digester's storage, the topmost object is stored there. Otherwise the * topmost object is replaced with the stored object. * In case of an "idref" attribute, if there is no entry with this ID in * the digester's storage, the topmost object is also stored there. Then the * trigger "WithinIdRef" is set during begin() and the processing continues * normally. When end() is called, the topmost object is replaced by the * stored one (this will be a no-op if there wasnt an entry in storage before) */ template class IdRef_body : public Action_body { public: IdRef_body() : stack() {} void begin(const Xml_string&, Xml_attr attr) { Obj_Type* obj = this->dig->template top(); Mode mode; Xml_attr::iterator it = attr.find("id"); if (it != attr.end()) { mode.ID = attr["id"]; mode.isIdRef = false; } else { Xml_attr::iterator it = attr.find("idref"); if (it != attr.end()) { mode.ID = attr["idref"]; mode.isIdRef = true; } else { mode.ID = ""; mode.isIdRef = false; } } if (mode.ID != "") { Obj_Type* storedObj = this->dig->template lookup(mode.ID); if ( !storedObj ) { this->dig->store(mode.ID, obj); } else if ( !mode.isIdRef ) { delete (this->dig->template top()); this->dig->pop(); this->dig->push(this->dig->template lookup(mode.ID)); } else { // NYI: set trigger } } stack.push_back(mode); } void end(const Xml_string&) { Mode mode = stack.back(); stack.pop_back(); if (mode.isIdRef) { delete (this->dig->template top()); this->dig->pop(); this->dig->push(this->dig->template lookup(mode.ID)); // NYI reset trigger } } private: struct Mode { Xml_string ID; bool isIdRef; }; std::vector stack; }; template struct IdRef : public MakeAction > {}; /** * Reads an object of type Data_Type from the digesters * storage and pushes it onto the stack. * WARNING: this might be a NULL pointer */ template class Lookup_body : public Generator_body { public: Lookup_body(const Xml_string& ID) : ID_(ID) {} void begin(const Xml_string&, Xml_attr) { Data_Type* data = this->dig->template lookup(ID_); this->dig->push(data); } private: Xml_string ID_; }; template struct Lookup : public MakeGenerator, const Xml_string&> { Lookup(Xml_string ID) : MakeGenerator, const Xml_string&>::MakeGenerator(ID) {} }; /** * Transforms the topmost object to the topmost object but one on the stack. // FIXME: this should just be a getter... */ template class Transform_body : public Action_body { public: typedef Obj_Type (*FunType)(const Arg_Type&); Transform_body(FunType fun) : fun_(fun), stack() {} void begin(const Xml_string&, Xml_attr) { Cell cell; cell.arg = this->dig->template top(); cell.obj = fun_(*cell.arg); #ifdef DESAXE_DEBUG std::cerr << "transform: " << cell.arg << " -> " << cell.obj << ")\n"; #endif stack.push_back(cell); this->dig->pop(); this->dig->push(&cell.obj); } void end(const Xml_string&) { Cell cell = stack.back(); stack.pop_back(); this->dig->pop(); this->dig->push(cell.arg); } private: FunType fun_; struct Cell { Arg_Type* arg; Obj_Type obj; }; std::vector stack; }; template struct Transform : public MakeAction, typename Transform_body::FunType> { typedef Transform_body BodyType; Transform(typename BodyType::FunType f) : MakeAction(f) {} }; template class PatchIdRefAttribute_body : public Action_body { public: typedef void (Obj_Type::*FunType)(Data_Type*) ; PatchIdRefAttribute_body(FunType set, const Xml_string& name) : set_(set), name_(name) {} void begin(const Xml_string&, Xml_attr attr) { Xml_attr::iterator it = attr.find(name_); if (it != attr.end()) { Obj_Type* obj = this->dig->template top(); this->dig->template patchInvoke(Xml_data(it), obj, set_); } } private: FunType set_; Xml_string name_; }; template struct PatchIdRefAttribute : public MakeAction, typename PatchIdRefAttribute_body::FunType, const Xml_string&> { typedef PatchIdRefAttribute_body BodyType; PatchIdRefAttribute(typename BodyType::FunType set, const Xml_string& name) : MakeAction(set,name) {} }; /** * defines the topmost object as the result */ template class Result_body : public Action_body { public: Result_body() {} void end(const Xml_string&) { this->dig->setResult(dig->template top()); } }; template struct Result : public MakeAction > {}; } // namespace #endif