Search code examples
javajparsec

JParsec for version numbers


I am trying to write a simple parser for version numbers using JParsec 3. The version numbers look like:

123
1.2.3
123.4

The rule is:

Up to three non-negative integers, separated by .

I have a Version class with three factory methods:

Version.of(int major)
Version.of(int major, int minor)
Version.of(int major, int minor, int patch)

I would like to write a parser for versions of any of the three types.

Here is what I have so far:

static final Parser<Integer> integerParser = Scanners.INTEGER
        .map(x -> Integer.parseUnsignedInt(x));

static final Parser<Version> versionParser1 =
        integerParser.map(x -> Version.of(x));

static final Parser<Version> versionParser2 =
        Parsers.sequence(
                integerParser.followedBy(Scanners.isChar('.')), 
                integerParser)
                .map(x -> Version.of(x.get(0), x.get(1)));

static final Parser<Version> versionParser3 =
        Parsers.sequence(
                integerParser.followedBy(Scanners.isChar('.')),
                integerParser.followedBy(Scanners.isChar('.')), 
                integerParser)
                .map(x -> Version.of(x.get(0), x.get(1), x.get(2)));

public static final Parser<Version> versionParser =
    versionParser1.or(versionParser2).or(versionParser3); 

This doesn't actually compile, because where I have x.get(0), x is an Integer.

How should I be using JParsec here?


Solution

  • You can use the Parsers.sequence(p1,p2,...,map) functions instead. The Parsers.sequence(p1...).map(f) behaviour is to drop the output of all parsers but the last. Then combine all parsers using a different combinator than or() because it will fail if parsers consume input but do not succeed. A possible solution is

    public static final Parser<Version> versionParser = Parsers.longest(versionParser1, versionParser2, versionParser3);