XMLパーサっぽいの

30分プログラム、その226XMLパーサっぽい何か。
OCamlDuceなどの[ [] "xyzzy"]という記法をXMLに変換するのが目的。まだ属性を書けない。
Javascript-Parsecprototype.jsを使っている。

使い方

var parser = new DuceParser('<foo>[ <bar>[] <baz>"xyzzy" ]');
var result = parser.xml.parse();
if(result.success()){
   console.log(result.result); # => ["<foo><bar></bar><baz>xyzzy</baz></foo>"]
}else{
   console.log('fail');
}

ソースコード

// include
var DuceParser = Inforno.Parsec.Parsers.define(function(){ with(this){
   this.alpha = chrLike(function(c){ 
      return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')});
   this.dash  = chr('-');

   // lexer
   this.space = chrLike(function(c){
      return ' \t\n\r'.toArray().include(c);
   }).retval('');
   this.spaces = many(this.space).retval('');

   this.ident = alpha.$(many(alpha.l(dash))).ret(function(a,b){
      return a+b.join('');
   }).$(spaces).ret(function(a,_){ return a;});;

   // string
   this.sChar = chrLike(function(c){ return c != '"';}) .l (str('\\"').retval('"'));
   this.string = between(chr('"'),
			 many(sChar),
			 chr('"')).ret(function(c){ 
			    return c.join('');}).$(spaces);

   // sequence(e.g. [<foo>[] <bar>[] <baz>[]])
   this.seq = between(chr('[').$(spaces).retval(''),
		      sepBy(p('xml'),spaces,true).ret(function(cs){
			 if(cs){
			    return cs.join('');
			 }
		      }),
		      spaces.$(chr(']'))).ret(function(cs){
			 return cs;
		      }).$(spaces);

   // tag
   this.tag = between(chr('<'), 
		      p('ident'),
		      chr('>'));

   var t = new Template('<#{tag}>#{child}</#{tag}>');
   this.xml = tag.$(string.l(seq)).ret(function(tag,child){
      return t.evaluate({
	 tag:tag,
	 child:child});
   });
}});