July 31, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

The Story of a WML Generator

  • September 19, 2005
  • By Radu Braniste
  • Send Email »
  • More Articles »

Filtering was moved outside elements and is attached as a policy to GenericElement. Additional run-time safety was added via LateInsertCheck—more details when discussing the run-time features. Elements are tag typed to avoid circular dependencies and extra complexity (TagTypes.h):

struct IBreakImpl{};
struct IHeadImpl{};
struct IAnchorImpl{};
struct IParagraphImpl{};
struct ICardImpl{};

The IxxxImpl structures are not intended to be manipulated polymorphically and one might take the same precautions as with GenericElement, which has a non-virtual protected destructor.

Please note in the code above constructs of type:

this->method();

This C++ lookup requirement is described in detail in [8].

Elements take as a template parameter the class they inherit from, thus allowing for different filters. Filters are defined separately (filters.h) and of course different implementations can coexist, the one to be used being selected at compile time. A filter acts mostly like an enabler—allowing or disallowing the compilation based on the filter parameter type.

struct BaseFilter
{};
struct ParagraphFilter
{
   static void filter(const IAnchorImpl&){}
};
struct HeadFilter
{
   static void filter(const IBreakImpl&){}
}
struct CardFilter
{
   static void filter(const IParagraphImpl&){}
};
template < class P>
struct DeckFilter
{
   static void filter(const IHeadImpl& e)
   {
      P::check(e);
   }
      static void filter(const ICardImpl& e)
   {
      P::check(e);
   }
};
struct HeadBeforeBodyCheck
{
   static bool headIsFirstInADeck ;
   static void check(const IHeadImpl& e)
   {
      assert (!headIsFirstInADeck && "head was used already");
      headIsFirstInADeck = true;
   }
      static void check(const ICardImpl& e)
   {
      assert (headIsFirstInADeck && "attempt to insert before head" );
   }
};
bool HeadBeforeBodyCheck::headIsFirstInADeck = false;

DeckFilter offers a naïve example of a composite filter—checking at run-time whether a Header was inserted before the Cards in a Deck.

Here is an usage example (wmlExecution1.h):

namespace WML_TYPEDEF_HELPER
{
   typedef CardImpl< GenericElement<CardFilter>, ICardImpl> Card;
   typedef HeadImpl<GenericElement<HeadFilter>, IHeadImpl> Head;
   typedef BreakImpl< GenericElement<BaseFilter>, IBreakImpl> Break;
   typedef DeckImpl< GenericElement<DeckFilter<HeadBeforeBodyCheck> >,
      IDeckImpl> Deck;
   typedef ParagraphImpl< GenericElement<ParagraphFilter>,
      IParagraphImpl> Paragraph;
   typedef AnchorImpl< GenericElement<BaseFilter>,
      IAnchorImpl> Anchor;
}
void doReadWML()
{
      typedef WML_TYPEDEF_HELPER::Card Card;
      typedef WML_TYPEDEF_HELPER::Head Head;
      typedef WML_TYPEDEF_HELPER::Break Break;
      typedef WML_TYPEDEF_HELPER::Deck Deck;
      typedef WML_TYPEDEF_HELPER::Paragraph Paragraph;
      typedef WML_TYPEDEF_HELPER::Anchor Anchor;
   Paragraph p;
   Break br;
   Head hd;
   hd.insert(br);
   Deck dk;
   dk.insert(hd);
   Anchor a("href", "html");
   //a.insert("html");
   Card c;
   c.setID("ID");
   p.insert(a);
      c.insert(p);
   ///p.insert(a);
   dk.insert(c);
      //dk.insert(hd);
   std::cout << static_cast<const std::string&>(dk) << std::endl;
}

WML_TYPEDEF_HELPER isolates the typedef declarations from the rest of the code, as an additional reusability unit.

Attempts like

a.insert("html");

or

dk.insert(p);

are rejected by the compiler.

On the other hand,

p.insert(a);

raises an assertion violation at run time: failed assertion '!isClosed && "inserted after closed"'. This means that the element to be inserted has been already closed and used in a previous context.

Using

dk.insert(hd);

after

dk.insert(c);

has the same consequences as commenting out the first call to

dk.insert(hd);

namely: failed assertion headIsFirstInADeck && "attempt to insert before head", meaning that the header can be used only once, before inserting any card.

Epilogue

This article presented two flexible implementations of a compile-time safe generator for WML-like XML subsets, coded in C# and C++. Easy to configure for various validation rules, the generator offers an interesting alternative to other similar products based on XSTL workflow chains.

Download the Code

Download the C# source code here and the C++ source code here.

References

[1] http://www.openmobilealliance.org/tech/affiliates/wap/wapindex.html

[2] http://www.wapforum.org/DTD/

[3] mlgen.zip contains the .NET solution

[4] Implementing the entire WML specification is left as an exercise for the reader

[5] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vclrfusingdirective.asp

[6] http://www.objectmentor.com/resources/articles/ocp.pdf

[7] wmlgenerator.zip contains the C++ solution files

[8] http://www.comeaucomputing.com/techtalk/templates/#whythisarrow





Page 3 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel