Hi,

I'm trying to use joda-time from within a Scala parser-combinator. I'm
writing a parser for the output of a command line interface and as
part of this I need to parse some dates. I would really like to use
joda-time for this since I really don't want to reinvent the wheel.
There is however an impedance mismatch since the combinator-parser
library traverses CharSequences and the joda-time api wants Strings as
input. The combinator parsers are stream-based so there is really no
chance they could work on Strings.

Scala's combinator-parsers are a really nifty piece of software since
it allows me to write really concise production-rules for my grammar,
but I couldn't find any established way to parse dates from standard
patterns. The basic building blocks are mostly just regex, but it's
very easy to combine these into more advanced parsers. And it is also
very easy to write your own custom parsers, but they have to work on
CharSequences.

Basically, what I wanted to do was just to wrap the
dateFormat.parseInto()-method in a Scala-parser to be able to use it
as a building-block for other parsers.

When looking at the joda-time source, I could not really find any real
reason why it had to work with Strings. So I made an attempt to change
it to work with CharSequences instead. I cloned the unofficial mirror
over at github and made my changes. The output of this is over here:

https://github.com/hedefalk/joda-time/commit/ef3bdafd89b334fb052ce0dd192613683b3486a4

It was quick and dirty but less than an hour of work. Risking that
this email turns long, It allows me to write a Scala-parser like this

trait DateParsers extends RegexParsers {
  def dateTime(pattern: String): Parser[DateTime] = new Parser[DateTime] {
    val dateFormat = DateTimeFormat.forPattern(pattern);

    def jodaParse(text: CharSequence, offset: Int) = {
      val mutableDateTime = new MutableDateTime
      val newPos = dateFormat.parseInto(mutableDateTime, text, offset);
      (mutableDateTime.toDateTime, newPos)
    }

    def apply(in: Input) = {
      val source = in.source
      val offset = in.offset
      val start = handleWhiteSpace(source, offset)
      val (dateTime, endPos) = jodaParse(source, start)
      if (endPos >= 0)
        Success(dateTime, in.drop(endPos - offset))
      else
        Failure("Failed to parse date", in.drop(start - offset))
    }
  }
}

which can then be used in production rules like this:


def changeset: Parser[ChangeSet] = changesetIdRow ~ opt(tagRow) ~
userRow ~ dateRow ~ summaryRow ^^
    {
      case changesetIdVal ~ tagOption ~ userVal ~ dateVal ~ summaryVal =>
        new ChangeSet(changesetIdVal, tagOption, userVal, dateVal, summaryVal)
    }

  private[this] def changesetIdRow = "changeset:" ~> changesetId
  private[this] def tagRow = "tag:" ~> ".*".r
  private[this] def userRow = "user:" ~> ".*".r
  private[this] def dateRow = "date:" ~> dateTime("EEE MMM d HH:mm:ss yyyy Z")
  private[this] def summaryRow = "summary:" ~> ".*".r


Anyway, I just wanted to show that this would be really useful for me.
By simply making joda-time parse CharSequences instead of Strings it
becomes a lot easier to use as part of a stream-based
parsing-framework.

Would it be possible to make a change like this to joda-time? As I
said, the patch linked above is just a quick and dirty fix, but I
wanted to see that it worked. All tests pass and the only thing that
really had to be replaced was the regionMatches()-method on String.

Cheers,
Viktor

------------------------------------------------------------------------------
Special Offer-- Download ArcSight Logger for FREE (a $49 USD value)!
Finally, a world-class log management solution at an even better price-free!
Download using promo code Free_Logger_4_Dev2Dev. Offer expires 
February 28th, so secure your free ArcSight Logger TODAY! 
http://p.sf.net/sfu/arcsight-sfd2d
_______________________________________________
Joda-interest mailing list
Joda-interest@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/joda-interest

Reply via email to