This is an automated email from the git hooks/post-receive script. reazem-guest pushed a commit to branch master in repository jsemver.
commit cf8d6b1960a6f5e6bb670920925d93c0427e1990 Author: Zafar Khaja <[email protected]> Date: Wed Nov 13 21:40:09 2013 +0400 Add Javadoc to the source code --- README.md | 5 - .../github/zafarkhaja/semver/GrammarException.java | 8 + .../github/zafarkhaja/semver/MetadataVersion.java | 85 ++++++ .../github/zafarkhaja/semver/NormalVersion.java | 65 +++++ .../java/com/github/zafarkhaja/semver/Parser.java | 11 + .../github/zafarkhaja/semver/ParserException.java | 10 + .../java/com/github/zafarkhaja/semver/Version.java | 303 +++++++++++++++++++++ .../github/zafarkhaja/semver/VersionParser.java | 198 ++++++++++++++ .../com/github/zafarkhaja/semver/expr/And.java | 23 ++ .../com/github/zafarkhaja/semver/expr/Equal.java | 18 ++ .../github/zafarkhaja/semver/expr/Expression.java | 11 + .../zafarkhaja/semver/expr/ExpressionParser.java | 171 ++++++++++++ .../com/github/zafarkhaja/semver/expr/Greater.java | 19 ++ .../zafarkhaja/semver/expr/GreaterOrEqual.java | 20 ++ .../com/github/zafarkhaja/semver/expr/Less.java | 19 ++ .../github/zafarkhaja/semver/expr/LessOrEqual.java | 20 ++ .../com/github/zafarkhaja/semver/expr/Lexer.java | 63 +++++ .../zafarkhaja/semver/expr/LexerException.java | 17 ++ .../com/github/zafarkhaja/semver/expr/Not.java | 17 ++ .../github/zafarkhaja/semver/expr/NotEqual.java | 18 ++ .../java/com/github/zafarkhaja/semver/expr/Or.java | 23 ++ .../semver/expr/UnexpectedTokenException.java | 23 ++ .../expr/{Expression.java => package-info.java} | 12 +- .../semver/{Parser.java => package-info.java} | 11 +- .../com/github/zafarkhaja/semver/util/Stream.java | 110 ++++++++ .../util/UnexpectedElementTypeException.java | 24 ++ .../semver/{Parser.java => util/package-info.java} | 7 +- 27 files changed, 1292 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e5a1251..73543fe 100644 --- a/README.md +++ b/README.md @@ -218,11 +218,6 @@ other interesting capabilities of the SemVer Expressions DSL. * Parenthesized expression - `~1.3 | (1.4.* & !=1.4.5) | ~2` -TODO ----- -* [Write doc comments for all API classes and methods](https://github.com/zafarkhaja/java-semver/issues/2) - - Bugs and Features ----------------- Bug reports and feature requests can be submitted at https://github.com/zafarkhaja/java-semver/issues. diff --git a/src/main/java/com/github/zafarkhaja/semver/GrammarException.java b/src/main/java/com/github/zafarkhaja/semver/GrammarException.java index 93ca594..3ea97b3 100644 --- a/src/main/java/com/github/zafarkhaja/semver/GrammarException.java +++ b/src/main/java/com/github/zafarkhaja/semver/GrammarException.java @@ -24,11 +24,19 @@ package com.github.zafarkhaja.semver; /** + * Thrown when an error occurs during the parsing specified + * by the SemVer or the formal grammar of the parsed string. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public class GrammarException extends ParserException { + /** + * Constructs a {@code GrammarException} instance with an error message. + * + * @param message the error message + */ GrammarException(String message) { super(message); } diff --git a/src/main/java/com/github/zafarkhaja/semver/MetadataVersion.java b/src/main/java/com/github/zafarkhaja/semver/MetadataVersion.java index ce615c9..bb03741 100644 --- a/src/main/java/com/github/zafarkhaja/semver/MetadataVersion.java +++ b/src/main/java/com/github/zafarkhaja/semver/MetadataVersion.java @@ -26,39 +26,66 @@ package com.github.zafarkhaja.semver; import java.util.Arrays; /** + * The {@code MetadataVersion} class is used to represent + * the pre-release version and the build metadata. * * @author Zafar Khaja <[email protected]> + * @since 0.2.0 */ class MetadataVersion implements Comparable<MetadataVersion> { + /** + * Null metadata, the implementation of the Null Object design pattern. + */ static final MetadataVersion NULL = new NullMetadataVersion(); + /** + * The implementation of the Null Object design pattern. + */ private static class NullMetadataVersion extends MetadataVersion { + /** + * Constructs a {@code NullMetadataVersion} instance. + */ public NullMetadataVersion() { super(null); } + /** + * @throws NullPointerException as Null metadata cannot be incremented + */ @Override MetadataVersion increment() { throw new NullPointerException("Metadata version is NULL"); } + /** + * {@inheritDoc} + */ @Override public String toString() { return ""; } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return 0; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { return other instanceof NullMetadataVersion; } + /** + * {@inheritDoc} + */ @Override public int compareTo(MetadataVersion other) { if (!equals(other)) { @@ -72,12 +99,24 @@ class MetadataVersion implements Comparable<MetadataVersion> { } } + /** + * The array containing the version's identifiers. + */ private final String[] idents; + /** + * Constructs a {@code MetadataVersion} instance with identifiers. + * @param identifiers the version's identifiers + */ MetadataVersion(String[] identifiers) { idents = identifiers; } + /** + * Increments the metadata version. + * + * @return a new instance of the {@code MetadataVersion} class + */ MetadataVersion increment() { String[] ids = idents; String lastId = ids[ids.length - 1]; @@ -91,6 +130,9 @@ class MetadataVersion implements Comparable<MetadataVersion> { return new MetadataVersion(ids); } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { if (this == other) { @@ -102,11 +144,17 @@ class MetadataVersion implements Comparable<MetadataVersion> { return compareTo((MetadataVersion) other) == 0; } + /** + * {@inheritDoc} + */ @Override public int hashCode() { return Arrays.hashCode(idents); } + /** + * {@inheritDoc} + */ @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -116,6 +164,9 @@ class MetadataVersion implements Comparable<MetadataVersion> { return sb.deleteCharAt(sb.lastIndexOf(".")).toString(); } + /** + * {@inheritDoc} + */ @Override public int compareTo(MetadataVersion other) { if (other == MetadataVersion.NULL) { @@ -127,11 +178,23 @@ class MetadataVersion implements Comparable<MetadataVersion> { } int result = compareIdentifierArrays(other.idents); if (result == 0) { + /** + * A larger set of pre-release fields has a higher + * precedence than a smaller set, if all of the + * preceding identifiers are equal. (SemVer p.11) + */ result = idents.length - other.idents.length; } return result; } + /** + * Compares two arrays of identifiers. + * + * @param otherIdents the identifiers of the other version + * @return integer result of comparison compatible with + * the {@code Comparable.compareTo} method + */ private int compareIdentifierArrays(String[] otherIdents) { int result = 0; int length = getLeastCommonArrayLength(idents, otherIdents); @@ -144,10 +207,25 @@ class MetadataVersion implements Comparable<MetadataVersion> { return result; } + /** + * Returns the size of the smallest array. + * + * @param arr1 the first array + * @param arr2 the second array + * @return the size of the smallest array + */ private int getLeastCommonArrayLength(String[] arr1, String[] arr2) { return arr1.length <= arr2.length ? arr1.length : arr2.length; } + /** + * Compares two identifiers. + * + * @param ident1 the first identifier + * @param ident2 the second identifier + * @return integer result of comparison compatible with + * the {@code Comparable.compareTo} method + */ private int compareIdentifiers(String ident1, String ident2) { if (isInt(ident1) && isInt(ident2)) { return Integer.parseInt(ident1) - Integer.parseInt(ident2); @@ -156,6 +234,13 @@ class MetadataVersion implements Comparable<MetadataVersion> { } } + /** + * Checks if the specified string is an integer. + * + * @param str the string to check + * @return {@code true} if the specified string is an integer + * or {@code false} otherwise + */ private boolean isInt(String str) { try { Integer.parseInt(str); diff --git a/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java b/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java index 7779b64..053d573 100644 --- a/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java +++ b/src/main/java/com/github/zafarkhaja/semver/NormalVersion.java @@ -24,15 +24,39 @@ package com.github.zafarkhaja.semver; /** + * The {@code NormalVersion} class represents the version core. + * + * This class is immutable and hence thread-safe. * * @author Zafar Khaja <[email protected]> + * @since 0.2.0 */ class NormalVersion implements Comparable<NormalVersion> { + /** + * The major version number. + */ private final int major; + + /** + * The minor version number. + */ private final int minor; + + /** + * The patch version number. + */ private final int patch; + /** + * Constructs a {@code NormalVersion} with the + * major, minor and patch version numbers. + * + * @param major the major version number + * @param minor the minor version number + * @param patch the patch version number + * @throws IllegalArgumentException if one of the version numbers is a negative integer + */ NormalVersion(int major, int minor, int patch) { if (major < 0 || minor < 0 || patch < 0) { throw new IllegalArgumentException( @@ -44,30 +68,63 @@ class NormalVersion implements Comparable<NormalVersion> { this.patch = patch; } + /** + * Returns the major version number. + * + * @return the major version number + */ int getMajor() { return major; } + /** + * Returns the minor version number. + * + * @return the minor version number + */ int getMinor() { return minor; } + /** + * Returns the patch version number. + * + * @return the patch version number + */ int getPatch() { return patch; } + /** + * Increments the major version number. + * + * @return a new instance of the {@code NormalVersion} class + */ NormalVersion incrementMajor() { return new NormalVersion(major + 1, 0, 0); } + /** + * Increments the minor version number. + * + * @return a new instance of the {@code NormalVersion} class + */ NormalVersion incrementMinor() { return new NormalVersion(major, minor + 1, 0); } + /** + * Increments the patch version number. + * + * @return a new instance of the {@code NormalVersion} class + */ NormalVersion incrementPatch() { return new NormalVersion(major, minor, patch + 1); } + /** + * {@inheritDoc} + */ @Override public int compareTo(NormalVersion other) { int result = major - other.major; @@ -80,6 +137,9 @@ class NormalVersion implements Comparable<NormalVersion> { return result; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { if (this == other) { @@ -91,6 +151,9 @@ class NormalVersion implements Comparable<NormalVersion> { return compareTo((NormalVersion) other) == 0; } + /** + * {@inheritDoc} + */ @Override public int hashCode() { int hash = 17; @@ -106,6 +169,8 @@ class NormalVersion implements Comparable<NormalVersion> { * A normal version number MUST take the form X.Y.Z where X, Y, and Z are * non-negative integers. X is the major version, Y is the minor version, * and Z is the patch version. (SemVer p.2) + * + * @return the string representation of this normal version */ @Override public String toString() { diff --git a/src/main/java/com/github/zafarkhaja/semver/Parser.java b/src/main/java/com/github/zafarkhaja/semver/Parser.java index 32d7571..c90f87f 100644 --- a/src/main/java/com/github/zafarkhaja/semver/Parser.java +++ b/src/main/java/com/github/zafarkhaja/semver/Parser.java @@ -24,9 +24,20 @@ package com.github.zafarkhaja.semver; /** + * A parser interface. + * + * @param <T> the type of parser's output * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public interface Parser<T> { + + /** + * Parses the input string. + * + * @param input the string to parse + * @return the Abstract Syntax Tree + */ T parse(String input); } diff --git a/src/main/java/com/github/zafarkhaja/semver/ParserException.java b/src/main/java/com/github/zafarkhaja/semver/ParserException.java index e839b20..b2cea5b 100644 --- a/src/main/java/com/github/zafarkhaja/semver/ParserException.java +++ b/src/main/java/com/github/zafarkhaja/semver/ParserException.java @@ -24,15 +24,25 @@ package com.github.zafarkhaja.semver; /** + * Thrown to indicate an error during the parsing. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public class ParserException extends RuntimeException { + /** + * Constructs a {@code ParserException} instance with an error message. + * + * @param message the error message + */ public ParserException(String message) { super(message); } + /** + * Constructs a {@code ParserException} instance with no error message. + */ public ParserException() { } diff --git a/src/main/java/com/github/zafarkhaja/semver/Version.java b/src/main/java/com/github/zafarkhaja/semver/Version.java index 30a2db1..a72dae9 100644 --- a/src/main/java/com/github/zafarkhaja/semver/Version.java +++ b/src/main/java/com/github/zafarkhaja/semver/Version.java @@ -28,24 +28,70 @@ import com.github.zafarkhaja.semver.expr.ExpressionParser; import java.util.Comparator; /** + * The {@code Version} class is the main class of the Java SemVer library. + * + * This class implements the Facade design pattern. + * It is also immutable, which makes the class thread-safe. * * @author Zafar Khaja <[email protected]> + * @since 0.1.0 */ public class Version implements Comparable<Version> { + /** + * The normal version. + */ private final NormalVersion normal; + + /** + * The pre-release version. + */ private final MetadataVersion preRelease; + + /** + * The build metadata. + */ private final MetadataVersion build; + /** + * A separator that separates the pre-release + * version from the normal version. + */ private static final String PRE_RELEASE_PREFIX = "-"; + + /** + * A separator that separates the build metadata from + * the normal version or the pre-release version. + */ private static final String BUILD_PREFIX = "+"; + /** + * A mutable builder for the immutable {@code Version} class. + */ public static class Builder { + /** + * The normal version string. + */ private String normal; + + /** + * The pre-release version string. + */ private String preRelease; + + /** + * The build metadata string. + */ private String build; + /** + * Constructs a {@code Builder} instance with the + * string representation of the normal version. + * + * @param normal the string representation of the normal version + * @throws NullPointerException if the specified normal version is null + */ public Builder(String normal) { if (normal == null) { throw new NullPointerException( @@ -55,14 +101,29 @@ public class Version implements Comparable<Version> { this.normal = normal; } + /** + * Sets the pre-release version. + * + * @param preRelease the string representation of the pre-release version + */ public void setPreReleaseVersion(String preRelease) { this.preRelease = preRelease; } + /** + * Sets the build metadata. + * + * @param build the string representation of the build metadata + */ public void setBuildMetadata(String build) { this.build = build; } + /** + * Builds a {@code Version} object. + * + * @return a newly built {@code Version} instance + */ public Version build() { return new Version( VersionParser.parseVersionCore(normal), @@ -72,10 +133,30 @@ public class Version implements Comparable<Version> { } } + /** + * A comparator that respects the build metadata when comparing versions. + */ public static final Comparator BUILD_AWARE_ORDER = new BuildAwareOrder(); + /** + * A build-aware comparator. + */ private static class BuildAwareOrder implements Comparator<Version> { + /** + * Compares two {@code Version} instances taking + * into account their build metadata. + * + * When compared build metadata is divided into identifiers. The + * numeric identifiers are compared numerically, and the alphanumeric + * identifiers are compared in the ASCII sort order. + * + * If one of the compared versions has no defined build + * metadata, this version is considered to have a lower + * precedence than that of the other. + * + * @return {@inheritDoc} + */ @Override public int compare(Version v1, Version v2) { int result = v1.compareTo(v2); @@ -96,14 +177,34 @@ public class Version implements Comparable<Version> { } } + /** + * Constructs a {@code Version} instance with the normal version. + * + * @param normal the normal version + */ Version(NormalVersion normal) { this(normal, MetadataVersion.NULL, MetadataVersion.NULL); } + /** + * Constructs a {@code Version} instance with the + * normal version and the pre-release version. + * + * @param normal the normal version + * @param preRelease the pre-release version + */ Version(NormalVersion normal, MetadataVersion preRelease) { this(normal, preRelease, MetadataVersion.NULL); } + /** + * Constructs a {@code Version} instance with the normal + * version, the pre-release version and the build metadata. + * + * @param normal the normal version + * @param preRelease the pre-release version + * @param build the build metadata + */ Version( NormalVersion normal, MetadataVersion preRelease, @@ -114,31 +215,86 @@ public class Version implements Comparable<Version> { this.build = build; } + /** + * Creates a new instance of {@code Version} as a + * result of parsing the specified version string. + * + * @param version the version string to parse + * @return a new instance of the {@code Version} class + */ public static Version valueOf(String version) { return VersionParser.parseValidSemVer(version); } + /** + * Creates a new instance of {@code Version} + * for the specified version numbers. + * + * @param major the major version number + * @return a new instance of the {@code Version} class + * @since 0.7.0 + */ public static Version forIntegers(int major) { return new Version(new NormalVersion(major, 0, 0)); } + /** + * Creates a new instance of {@code Version} + * for the specified version numbers. + * + * @param major the major version number + * @param minor the minor version number + * @return a new instance of the {@code Version} class + * @since 0.7.0 + */ public static Version forIntegers(int major, int minor) { return new Version(new NormalVersion(major, minor, 0)); } + /** + * Creates a new instance of {@code Version} + * for the specified version numbers. + * + * @param major the major version number + * @param minor the minor version number + * @param patch the patch version number + * @return a new instance of the {@code Version} class + * @since 0.7.0 + */ public static Version forIntegers(int major, int minor, int patch) { return new Version(new NormalVersion(major, minor, patch)); } + /** + * Checks if this version satisfies the specified SemVer Expression. + * + * This method is a part of the SemVer Expressions API. + * + * @param expr the SemVer Expression + * @return {@code true} if this version satisfies the specified + * SemVer Expression or {@code false} otherwise + * @since 0.7.0 + */ public boolean satisfies(String expr) { Parser<Expression> parser = ExpressionParser.newInstance(); return parser.parse(expr).interpret(this); } + /** + * Increments the major version. + * + * @return a new instance of the {@code Version} class + */ public Version incrementMajorVersion() { return new Version(normal.incrementMajor()); } + /** + * Increments the major version and appends the pre-release version. + * + * @param preRelease the pre-release version to append + * @return a new instance of the {@code Version} class + */ public Version incrementMajorVersion(String preRelease) { return new Version( normal.incrementMajor(), @@ -146,10 +302,21 @@ public class Version implements Comparable<Version> { ); } + /** + * Increments the minor version. + * + * @return a new instance of the {@code Version} class + */ public Version incrementMinorVersion() { return new Version(normal.incrementMinor()); } + /** + * Increments the minor version and appends the pre-release version. + * + * @param preRelease the pre-release version to append + * @return a new instance of the {@code Version} class + */ public Version incrementMinorVersion(String preRelease) { return new Version( normal.incrementMinor(), @@ -157,10 +324,21 @@ public class Version implements Comparable<Version> { ); } + /** + * Increments the patch version. + * + * @return a new instance of the {@code Version} class + */ public Version incrementPatchVersion() { return new Version(normal.incrementPatch()); } + /** + * Increments the patch version and appends the pre-release version. + * + * @param preRelease the pre-release version to append + * @return a new instance of the {@code Version} class + */ public Version incrementPatchVersion(String preRelease) { return new Version( normal.incrementPatch(), @@ -168,14 +346,30 @@ public class Version implements Comparable<Version> { ); } + /** + * Increments the pre-release version. + * + * @return a new instance of the {@code Version} class + */ public Version incrementPreReleaseVersion() { return new Version(normal, preRelease.increment()); } + /** + * Increments the build metadata. + * + * @return a new instance of the {@code Version} class + */ public Version incrementBuildMetadata() { return new Version(normal, preRelease, build.increment()); } + /** + * Sets the pre-release version. + * + * @param preRelease the pre-release version to set + * @return a new instance of the {@code Version} class + */ public Version setPreReleaseVersion(String preRelease) { return new Version( normal, @@ -183,6 +377,12 @@ public class Version implements Comparable<Version> { ); } + /** + * Sets the build metadata. + * + * @param build the build metadata to set + * @return a new instance of the {@code Version} class + */ public Version setBuildMetadata(String build) { return new Version( normal, @@ -191,46 +391,118 @@ public class Version implements Comparable<Version> { ); } + /** + * Returns the major version number. + * + * @return the major version number + */ public int getMajorVersion() { return normal.getMajor(); } + /** + * Returns the minor version number. + * + * @return the minor version number + */ public int getMinorVersion() { return normal.getMinor(); } + /** + * Returns the patch version number. + * + * @return the patch version number + */ public int getPatchVersion() { return normal.getPatch(); } + /** + * Returns the string representation of the normal version. + * + * @return the string representation of the normal version + */ public String getNormalVersion() { return normal.toString(); } + /** + * Returns the string representation of the pre-release version. + * + * @return the string representation of the pre-release version + */ public String getPreReleaseVersion() { return preRelease.toString(); } + /** + * Returns the string representation of the build metadata. + * + * @return the string representation of the build metadata + */ public String getBuildMetadata() { return build.toString(); } + /** + * Checks if this version is greater than the other version. + * + * @param other the other version to compare to + * @return {@code true} if this version is greater than the other version + * or {@code false} otherwise + * @see #compareTo(Version other) + */ public boolean greaterThan(Version other) { return compareTo(other) > 0; } + /** + * Checks if this version is greater than or equal to the other version. + * + * @param other the other version to compare to + * @return {@code true} if this version is greater than or equal + * to the other version or {@code false} otherwise + * @see #compareTo(Version other) + */ public boolean greaterThanOrEqualTo(Version other) { return compareTo(other) >= 0; } + /** + * Checks if this version is less than the other version. + * + * @param other the other version to compare to + * @return {@code true} if this version is less than the other version + * or {@code false} otherwise + * @see #compareTo(Version other) + */ public boolean lessThan(Version other) { return compareTo(other) < 0; } + /** + * Checks if this version is less than or equal to the other version. + * + * @param other the other version to compare to + * @return {@code true} if this version is less than or equal + * to the other version or {@code false} otherwise + * @see #compareTo(Version other) + */ public boolean lessThanOrEqualTo(Version other) { return compareTo(other) <= 0; } + /** + * Checks if this version equals the other version. + * + * The comparison is done by the {@code Version.compareTo} method. + * + * @param other the other version to compare to + * @return {@code true} if this version equals the other version + * or {@code false} otherwise + * @see #compareTo(Version other) + */ @Override public boolean equals(Object other) { if (this == other) { @@ -242,6 +514,9 @@ public class Version implements Comparable<Version> { return compareTo((Version) other) == 0; } + /** + * {@inheritDoc} + */ @Override public int hashCode() { int hash = 5; @@ -251,6 +526,9 @@ public class Version implements Comparable<Version> { return hash; } + /** + * {@inheritDoc} + */ @Override public String toString() { StringBuilder sb = new StringBuilder(getNormalVersion()); @@ -263,6 +541,20 @@ public class Version implements Comparable<Version> { return sb.toString(); } + /** + * Compares this version to the other version. + * + * This method does not take into account the versions' build + * metadata. If you want to compare the versions' build metadata + * use the {@code Version.compareWithBuildsTo} method or the + * {@code Version.BUILD_AWARE_ORDER} comparator. + * + * @param other the other version to compare to + * @return a negative integer, zero or a positive integer if this version + * is less than, equal to or greater the the specified version + * @see #BUILD_AWARE_ORDER + * @see #compareWithBuildsTo(Version other) + */ @Override public int compareTo(Version other) { int result = normal.compareTo(other.normal); @@ -272,6 +564,17 @@ public class Version implements Comparable<Version> { return result; } + /** + * Compare this version to the other version + * taking into account the build metadata. + * + * The method makes use of the {@code Version.BUILD_AWARE_ORDER} comparator. + * + * @param other the other version to compare to + * @return integer result of comparison compatible with + * that of the {@code Comparable.compareTo} method + * @see #BUILD_AWARE_ORDER + */ public int compareWithBuildsTo(Version other) { return BUILD_AWARE_ORDER.compare(this, other); } diff --git a/src/main/java/com/github/zafarkhaja/semver/VersionParser.java b/src/main/java/com/github/zafarkhaja/semver/VersionParser.java index a79a0d0..5d47e5f 100644 --- a/src/main/java/com/github/zafarkhaja/semver/VersionParser.java +++ b/src/main/java/com/github/zafarkhaja/semver/VersionParser.java @@ -27,16 +27,25 @@ import com.github.zafarkhaja.semver.util.Stream; import java.util.ArrayList; import java.util.List; import static com.github.zafarkhaja.semver.VersionParser.Char.*; +import com.github.zafarkhaja.semver.util.UnexpectedElementTypeException; /** + * A parser for the SemVer Version. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class VersionParser implements Parser<Version> { + /** + * Valid character types. + */ static enum Char implements Stream.ElementType<Character> { DIGIT { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { @@ -46,6 +55,9 @@ class VersionParser implements Parser<Version> { } }, LETTER { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { @@ -56,6 +68,9 @@ class VersionParser implements Parser<Version> { } }, DOT { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { @@ -65,6 +80,9 @@ class VersionParser implements Parser<Version> { } }, HYPHEN { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { @@ -74,6 +92,9 @@ class VersionParser implements Parser<Version> { } }, PLUS { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Character chr) { if (chr == null) { @@ -83,6 +104,9 @@ class VersionParser implements Parser<Version> { } }, EOL { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Character chr) { return chr == null; @@ -90,8 +114,17 @@ class VersionParser implements Parser<Version> { }; } + /** + * The stream of characters. + */ private final Stream<Character> chars; + /** + * Constructs a {@code VersionParser} instance + * with the input string to parse. + * + * @param input the input string to parse + */ VersionParser(String input) { Character[] elements = new Character[input.length()]; for (int i = 0; i < input.length(); i++) { @@ -100,21 +133,59 @@ class VersionParser implements Parser<Version> { chars = new Stream<Character>(elements); } + /** + * Parses the input string. + * + * @param input the input string to parse + * @return a valid version object + * @throws GrammarException when there is an error defined in + * the SemVer or the formal grammar + * @throws UnexpectedElementTypeException when encounters an unexpected + * character type + */ @Override public Version parse(String input) { return parseValidSemVer(); } + /** + * Parses the whole version including pre-release version and build metadata. + * + * @param version the version string to parse + * @return a valid version object + * @throws GrammarException when there is an error defined in + * the SemVer or the formal grammar + * @throws UnexpectedElementTypeException when encounters an unexpected + * character type + */ static Version parseValidSemVer(String version) { VersionParser parser = new VersionParser(version); return parser.parseValidSemVer(); } + /** + * Parses the version core. + * + * @param versionCore the version core string to parse + * @return a valid normal version object + * @throws GrammarException when there is an error defined in + * the SemVer or the formal grammar + * @throws UnexpectedElementTypeException when encounters an unexpected + * character type + */ static NormalVersion parseVersionCore(String versionCore) { VersionParser parser = new VersionParser(versionCore); return parser.parseVersionCore(); } + /** + * Parses the pre-release version. + * + * @param preRelease the pre-release version string to parse + * @return a valid pre-release version object + * @throws GrammarException when there is an error defined in + * the SemVer or the formal grammar + */ static MetadataVersion parsePreRelease(String preRelease) { if (preRelease == null) { return MetadataVersion.NULL; @@ -123,6 +194,14 @@ class VersionParser implements Parser<Version> { return parser.parsePreRelease(); } + /** + * Parses the build metadata. + * + * @param build the build metadata string to parse + * @return a valid build metadata object + * @throws GrammarException when there is an error defined in + * the SemVer or the formal grammar + */ static MetadataVersion parseBuild(String build) { if (build == null) { return MetadataVersion.NULL; @@ -131,6 +210,20 @@ class VersionParser implements Parser<Version> { return parser.parseBuild(); } + /** + * Parses the {@literal <valid semver>} non-terminal. + * + * <pre> + * {@literal + * <valid semver> ::= <version core> + * | <version core> "-" <pre-release> + * | <version core> "+" <build> + * | <version core> "-" <pre-release> "+" <build> + * } + * </pre> + * + * @return a valid version object + */ private Version parseValidSemVer() { NormalVersion normalVersion = parseVersionCore(); MetadataVersion preReleaseVersion = MetadataVersion.NULL; @@ -150,6 +243,17 @@ class VersionParser implements Parser<Version> { ); } + /** + * Parses the {@literal <version core>} non-terminal. + * + * <pre> + * {@literal + * <version core> ::= <major> "." <minor> "." <patch> + * } + * </pre> + * + * @return a valid normal version object + */ private NormalVersion parseVersionCore() { int major = Integer.parseInt(numericIdentifier()); chars.consume(DOT); @@ -159,6 +263,24 @@ class VersionParser implements Parser<Version> { return new NormalVersion(major, minor, patch); } + /** + * Parses the {@literal <pre-release>} non-terminal. + * + * <pre> + * {@literal + * <pre-release> ::= <dot-separated pre-release identifiers> + * + * <dot-separated pre-release identifiers> ::= <pre-release identifier> + * | <pre-release identifier> "." <dot-separated pre-release identifiers> + * + * <pre-release identifier> ::= <alphanumeric identifier> + * | <numeric identifier> + * } + * </pre> + * + * @return a valid pre-release version object + * @throws GrammarException if the pre-release version has empty identifier(s) + */ private MetadataVersion parsePreRelease() { Char end = closestEndpoint(PLUS, EOL); Char before = closestEndpoint(DOT, end); @@ -182,6 +304,24 @@ class VersionParser implements Parser<Version> { ); } + /** + * Parses the {@literal <build>} non-terminal. + * + * <pre> + * {@literal + * <build> ::= <dot-separated build identifiers> + * + * <dot-separated build identifiers> ::= <build identifier> + * | <build identifier> "." <dot-separated build identifiers> + * + * <build identifier> ::= <alphanumeric identifier> + * | <digits> + * } + * </pre> + * + * @return a valid build metadata object + * @throws GrammarException if the build metadata has empty identifier(s) + */ private MetadataVersion parseBuild() { Char end = EOL; Char before = closestEndpoint(DOT, end); @@ -205,6 +345,20 @@ class VersionParser implements Parser<Version> { ); } + /** + * Parses the {@literal <numeric identifier>} non-terminal. + * + * <pre> + * {@literal + * <numeric identifier> ::= "0" + * | <positive digit> + * | <positive digit> <digits> + * } + * </pre> + * + * @return a string representing the numeric identifier + * @throws GrammarException if the numeric identifier has leading zero(es) + */ private String numericIdentifier() { checkForLeadingZeroes(); StringBuilder sb = new StringBuilder(); @@ -215,6 +369,20 @@ class VersionParser implements Parser<Version> { return sb.toString(); } + /** + * Parses the {@literal <alphanumeric identifier>} non-terminal. + * + * <pre> + * {@literal + * <alphanumeric identifier> ::= <non-digit> + * | <non-digit> <identifier characters> + * | <identifier characters> <non-digit> + * | <identifier characters> <non-digit> <identifier characters> + * } + * </pre> + * + * @return a string representing the alphanumeric identifier + */ private String alphanumericIdentifier() { StringBuilder sb = new StringBuilder(); sb.append(chars.consume(DIGIT, LETTER, HYPHEN)); @@ -224,6 +392,18 @@ class VersionParser implements Parser<Version> { return sb.toString(); } + /** + * Parses the {@literal <digits>} non-terminal. + * + * <pre> + * {@literal + * <digits> ::= <digit> + * | <digit> <digits> + * } + * </pre> + * + * @return a string representing the digits + */ private String digits() { StringBuilder sb = new StringBuilder(); sb.append(chars.consume(DIGIT)); @@ -233,6 +413,13 @@ class VersionParser implements Parser<Version> { return sb.toString(); } + /** + * Chooses the closest character. + * + * @param tryThis the character to try first + * @param orThis the character to fallback to + * @return the closest character + */ private Char closestEndpoint(Char tryThis, Char orThis) { if (chars.positiveLookaheadBefore(orThis, tryThis)) { return tryThis; @@ -240,6 +427,11 @@ class VersionParser implements Parser<Version> { return orThis; } + /** + * Checks for leading zeroes in the numeric identifiers. + * + * @throws GrammarException if a numeric identifier has leading zero(es) + */ private void checkForLeadingZeroes() { Character la1 = chars.lookahead(1); Character la2 = chars.lookahead(2); @@ -250,6 +442,12 @@ class VersionParser implements Parser<Version> { } } + /** + * Checks for empty identifiers in the pre-release version or build metadata. + * + * @throws GrammarException if the pre-release version or build + * metadata have empty identifier(s) + */ private void checkForEmptyIdentifier() { if (DOT.isMatchedBy(chars.lookahead(1))) { throw new GrammarException("Identifiers MUST NOT be empty"); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/And.java b/src/main/java/com/github/zafarkhaja/semver/expr/And.java index 850d5d2..3a5bedb 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/And.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/And.java @@ -26,19 +26,42 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the logical "and" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class And implements Expression { + /** + * The left-hand operand of expression. + */ private final Expression left; + + /** + * The right-hand operand of expression. + */ private final Expression right; + /** + * Constructs a {@code And} expression with + * the left-hand and right-hand operands. + * + * @param left the left-hand operand of expression + * @param right the right-hand operand of expression + */ And(Expression left, Expression right) { this.left = left; this.right = right; } + /** + * Checks if both operands evaluate to {@code true}. + * + * @param version the version to interpret against + * @return {@code true} if both operands evaluate to {@code true} + * or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return left.interpret(version) && right.interpret(version); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Equal.java b/src/main/java/com/github/zafarkhaja/semver/expr/Equal.java index 71cb5f7..5f7d9fa 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Equal.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Equal.java @@ -26,17 +26,35 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the comparison "equal" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class Equal implements Expression { + /** + * The parsed version, the right-hand operand of the "equal" operator. + */ private final Version parsedVersion; + /** + * Constructs a {@code Equal} expression with the parsed version. + * + * @param parsedVersion the parsed version + */ Equal(Version parsedVersion) { this.parsedVersion = parsedVersion; } + /** + * Checks if the current version equals the parsed version. + * + * @param version the version to compare to, the left-hand + * operand of the "equal" operator + * @return {@code true} if the version equals the + * parsed version or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return version.equals(parsedVersion); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java b/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java index 48ba122..25724be 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java @@ -26,9 +26,20 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * The {@code Expression} interface is to be implemented + * by the nodes of the Abstract Syntax Tree produced by + * the {@code ExpressionParser} class. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public interface Expression { + + /** + * Interprets the expression. + * + * @param version the version to interpret against + * @return the result of the expression interpretation + */ boolean interpret(Version version); } diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/ExpressionParser.java b/src/main/java/com/github/zafarkhaja/semver/expr/ExpressionParser.java index e403bb2..ac9dfac 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/ExpressionParser.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/ExpressionParser.java @@ -33,28 +33,72 @@ import java.util.Iterator; import static com.github.zafarkhaja.semver.expr.Lexer.Token.Type.*; /** + * A parser for the SemVer Expressions. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public class ExpressionParser implements Parser<Expression> { + /** + * The lexer instance used for tokenization of the input string. + */ private final Lexer lexer; + + /** + * The stream of tokens produced by the lexer. + */ private Stream<Token> tokens; + /** + * Constructs a {@code ExpressionParser} instance + * with the corresponding lexer. + * + * @param lexer the lexer to use for tokenization of the input string + */ ExpressionParser(Lexer lexer) { this.lexer = lexer; } + /** + * Creates and returns new instance of the {@code ExpressionParser} class. + * + * This method implements the Static Factory Method pattern. + * + * @return a new instance of the {@code ExpressionParser} class + */ public static Parser<Expression> newInstance() { return new ExpressionParser(new Lexer()); } + /** + * Parses the SemVer Expressions. + * + * @param input a string representing the SemVer Expression + * @return the AST for the SemVer Expressions + * @throws LexerException when encounters an illegal character + * @throws UnexpectedTokenException when encounters an unexpected token type + */ @Override public Expression parse(String input) { tokens = lexer.tokenize(input); return parseSemVerExpression(); } + /** + * Parses the {@literal <semver-expr>} non-terminal. + * + * <pre> + * {@literal + * <semver-expr> ::= "!" "(" <semver-expr> ")" + * | "(" <semver-expr> ")" + * | <semver-expr> <boolean-expr> + * | <expr> + * } + * </pre> + * + * @return the expression AST + */ private Expression parseSemVerExpression() { Expression expr; if (tokens.positiveLookahead(NOT)) { @@ -72,6 +116,19 @@ public class ExpressionParser implements Parser<Expression> { return parseBooleanExpression(expr); } + /** + * Parses the {@literal <boolean-expr>} non-terminal. + * + * <pre> + * {@literal + * <boolean-expr> ::= <boolean-op> <semver-expr> + * | <epsilon> + * } + * </pre> + * + * @param expr the left-hand expression of the logical operators + * @return the expression AST + */ private Expression parseBooleanExpression(Expression expr) { if (tokens.positiveLookahead(AND)) { tokens.consume(); @@ -83,6 +140,20 @@ public class ExpressionParser implements Parser<Expression> { return expr; } + /** + * Parses the {@literal <expr>} non-terminal. + * + * <pre> + * {@literal + * <expr> ::= <comparison-expr> + * | <version-expr> + * | <tilde-expr> + * | <range-expr> + * } + * </pre> + * + * @return the expression AST + */ private Expression parseExpression() { if (tokens.positiveLookahead(TILDE)) { return parseTildeExpression(); @@ -94,6 +165,18 @@ public class ExpressionParser implements Parser<Expression> { return parseComparisonExpression(); } + /** + * Parses the {@literal <comparison-expr>} non-terminal. + * + * <pre> + * {@literal + * <comparison-expr> ::= <comparison-op> <version> + * | <version> + * } + * </pre> + * + * @return the expression AST + */ private Expression parseComparisonExpression() { Token token = tokens.lookahead(); Expression expr; @@ -128,6 +211,17 @@ public class ExpressionParser implements Parser<Expression> { return expr; } + /** + * Parses the {@literal <tilde-expr>} non-terminal. + * + * <pre> + * {@literal + * <tilde-expr> ::= "~" <version> + * } + * </pre> + * + * @return the expression AST + */ private Expression parseTildeExpression() { tokens.consume(TILDE); int major = intOf(tokens.consume(NUMERIC).lexeme); @@ -150,10 +244,30 @@ public class ExpressionParser implements Parser<Expression> { ); } + /** + * Determines if the following version terminals are part + * of the {@literal <version-expr>} not-terminal. + * + * @return {@code true} if the following version terminals are + * part of the {@literal <version-expr>} not-terminal or + * {@code false} otherwise + */ private boolean isVersionExpression() { return isVersionFollowedBy(STAR); } + /** + * Parses the {@literal <version-expr>} non-terminal. + * + * <pre> + * {@literal + * <version-expr> ::= <major> "." "*" + * | <major> "." <minor> "." "*" + * } + * </pre> + * + * @return the expression AST + */ private Expression parseVersionExpression() { int major = intOf(tokens.consume(NUMERIC).lexeme); tokens.consume(DOT); @@ -173,10 +287,29 @@ public class ExpressionParser implements Parser<Expression> { ); } + /** + * Determines if the following version terminals are + * part of the {@literal <range-expr>} not-terminal. + * + * @return {@code true} if the following version terminals are + * part of the {@literal <range-expr>} not-terminal or + * {@code false} otherwise + */ private boolean isRangeExpression() { return isVersionFollowedBy(HYPHEN); } + /** + * Parses the {@literal <range-expr>} non-terminal. + * + * <pre> + * {@literal + * <range-expr> ::= <version> "-" <version> + * } + * </pre> + * + * @return the expression AST + */ private Expression parseRangeExpression() { Expression ge = new GreaterOrEqual(parseVersion()); tokens.consume(HYPHEN); @@ -184,6 +317,19 @@ public class ExpressionParser implements Parser<Expression> { return new And(ge, le); } + /** + * Parses the {@literal <version>} non-terminal. + * + * <pre> + * {@literal + * <version> ::= <major> + * | <major> "." <minor> + * | <major> "." <minor> "." <patch> + * } + * </pre> + * + * @return the parsed version + */ private Version parseVersion() { int major = intOf(tokens.consume(NUMERIC).lexeme); int minor = 0; @@ -199,6 +345,17 @@ public class ExpressionParser implements Parser<Expression> { return versionOf(major, minor, patch); } + /** + * Determines if the version terminals are + * followed by the specified token type. + * + * This method is essentially a {@code lookahead(k)} method + * which allows to solve the grammar's ambiguities. + * + * @param type the token type to check + * @return {@code true} if the version terminals are followed by + * the specified token type or {@code false} otherwise + */ private boolean isVersionFollowedBy(ElementType<Token> type) { EnumSet<Token.Type> expected = EnumSet.of(NUMERIC, DOT); Iterator<Token> it = tokens.iterator(); @@ -212,10 +369,24 @@ public class ExpressionParser implements Parser<Expression> { return type.isMatchedBy(lookahead); } + /** + * Creates a {@code Version} instance for the specified integers. + * + * @param major the major version number + * @param minor the minor version number + * @param patch the patch version number + * @return the version for the specified integers + */ private Version versionOf(int major, int minor, int patch) { return Version.forIntegers(major, minor, patch); } + /** + * Returns a {@code int} representation of the specified string. + * + * @param value the string to convert into an integer + * @return the integer value of the specified string + */ private int intOf(String value) { return Integer.parseInt(value); } diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Greater.java b/src/main/java/com/github/zafarkhaja/semver/expr/Greater.java index 21dc478..3b14ae4 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Greater.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Greater.java @@ -26,17 +26,36 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the comparison "greater than" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class Greater implements Expression { + /** + * The parsed version, the right-hand + * operand of the "greater than" operator. + */ private final Version parsedVersion; + /** + * Constructs a {@code Greater} expression with the parsed version. + * + * @param parsedVersion the parsed version + */ Greater(Version parsedVersion) { this.parsedVersion = parsedVersion; } + /** + * Checks if the current version is greater than the parsed version. + * + * @param version the version to compare to, the left-hand + * operand of the "greater than" operator + * @return {@code true} if the version is greater than the + * parsed version or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return version.greaterThan(parsedVersion); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/GreaterOrEqual.java b/src/main/java/com/github/zafarkhaja/semver/expr/GreaterOrEqual.java index a205ccd..4adccc8 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/GreaterOrEqual.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/GreaterOrEqual.java @@ -26,17 +26,37 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the comparison "greater than or equal to" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class GreaterOrEqual implements Expression { + /** + * The parsed version, the right-hand operand + * of the "greater than or equal to" operator. + */ private final Version parsedVersion; + /** + * Constructs a {@code GreaterOrEqual} expression with the parsed version. + * + * @param parsedVersion the parsed version + */ GreaterOrEqual(Version parsedVersion) { this.parsedVersion = parsedVersion; } + /** + * Checks if the current version is greater + * than or equal to the parsed version. + * + * @param version the version to compare to, the left-hand operand + * of the "greater than or equal to" operator + * @return {@code true} if the version is greater than or equal + * to the parsed version or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return version.greaterThanOrEqualTo(parsedVersion); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Less.java b/src/main/java/com/github/zafarkhaja/semver/expr/Less.java index dd62450..5cbb5de 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Less.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Less.java @@ -26,17 +26,36 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the comparison "less than" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class Less implements Expression { + /** + * The parsed version, the right-hand + * operand of the "less than" operator. + */ private final Version parsedVersion; + /** + * Constructs a {@code Less} expression with the parsed version. + * + * @param parsedVersion the parsed version + */ Less(Version parsedVersion) { this.parsedVersion = parsedVersion; } + /** + * Checks if the current version is less than the parsed version. + * + * @param version the version to compare to, the left-hand + * operand of the "less than" operator + * @return {@code true} if the version is less than the + * parsed version or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return version.lessThan(parsedVersion); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/LessOrEqual.java b/src/main/java/com/github/zafarkhaja/semver/expr/LessOrEqual.java index b6fd00a..51d9bab 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/LessOrEqual.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/LessOrEqual.java @@ -26,17 +26,37 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the comparison "less than or equal to" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class LessOrEqual implements Expression { + /** + * The parsed version, the right-hand operand + * of the "less than or equal to" operator. + */ private final Version parsedVersion; + /** + * Constructs a {@code LessOrEqual} expression with the parsed version. + * + * @param parsedVersion the parsed version + */ LessOrEqual(Version parsedVersion) { this.parsedVersion = parsedVersion; } + /** + * Checks if the current version is less + * than or equal to the parsed version. + * + * @param version the version to compare to, the left-hand operand + * of the "less than or equal to" operator + * @return {@code true} if the version is less than or equal + * to the parsed version or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return version.lessThanOrEqualTo(parsedVersion); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Lexer.java b/src/main/java/com/github/zafarkhaja/semver/expr/Lexer.java index c6bff31..b63efc1 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Lexer.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Lexer.java @@ -30,13 +30,21 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** + * A lexer for the SemVer Expressions. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class Lexer { + /** + * This class holds the information about lexemes in the input stream. + */ static class Token { + /** + * Valid token types. + */ enum Type implements Stream.ElementType<Token> { NUMERIC("0|[1-9][0-9]*"), @@ -57,23 +65,44 @@ class Lexer { RIGHT_PAREN("\\)"), WHITESPACE("\\s+"), EOL("?!") { + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Token token) { return token == null; } }; + /** + * A pattern matching this type. + */ final Pattern pattern; + /** + * Constructs a token type with a regular + * expression for the pattern. + * + * @param regexp the regular expression for the pattern + * @see #pattern + */ private Type(String regexp) { pattern = Pattern.compile("^(" + regexp + ")"); } + /** + * Returns the string representation of this type. + * + * @return the string representation of this type + */ @Override public String toString() { return name() + "(" + pattern + ")"; } + /** + * {@inheritDoc} + */ @Override public boolean isMatchedBy(Token token) { if (token == null) { @@ -83,14 +112,30 @@ class Lexer { } } + /** + * The type of this token. + */ final Type type; + + /** + * The lexeme of this token. + */ final String lexeme; + /** + * Constructs a {@code Token} instance with the type and lexeme. + * + * @param type the type of this token + * @param lexeme the lexeme of this token + */ Token(Type type, String lexeme) { this.type = type; this.lexeme = (lexeme == null) ? "" : lexeme; } + /** + * {@inheritDoc} + */ @Override public boolean equals(Object other) { if (this == other) { @@ -103,6 +148,9 @@ class Lexer { return type.equals(token.type) && lexeme.equals(token.lexeme); } + /** + * {@inheritDoc} + */ @Override public int hashCode() { int hash = 5; @@ -111,16 +159,31 @@ class Lexer { return hash; } + /** + * Returns the string representation of this token. + * + * @return the string representation of this token + */ @Override public String toString() { return type.name() + "(" + lexeme + ")"; } } + /** + * Constructs a {@code Lexer} instance. + */ Lexer() { } + /** + * Tokenizes the specified input string. + * + * @param input the input string to tokenize + * @return a stream of tokens + * @throws LexerException when encounters an illegal character + */ Stream<Token> tokenize(String input) { List<Token> tokens = new ArrayList<Token>(); while (!input.isEmpty()) { diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/LexerException.java b/src/main/java/com/github/zafarkhaja/semver/expr/LexerException.java index 2927c56..b932ef6 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/LexerException.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/LexerException.java @@ -24,17 +24,34 @@ package com.github.zafarkhaja.semver.expr; /** + * Thrown during the lexical analysis when + * an illegal character is encountered. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public class LexerException extends RuntimeException { + /** + * The string being analyzed starting from an illegal character. + */ private final String expr; + /** + * Constructs a {@code LexerException} instance with + * a string starting from an illegal character. + * + * @param expr the string starting from an illegal character + */ LexerException(String expr) { this.expr = expr; } + /** + * Returns the string representation of this exception. + * + * @return the string representation of this exception + */ @Override public String toString() { return "Illegal character near '" + expr + "'"; diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Not.java b/src/main/java/com/github/zafarkhaja/semver/expr/Not.java index a84d800..1d0fd2d 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Not.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Not.java @@ -26,17 +26,34 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the logical "negation" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class Not implements Expression { + /** + * The expression to negate. + */ private final Expression expr; + /** + * Constructs a {@code Not} expression with an expression to negate. + * + * @param expr the expression to negate + */ Not(Expression expr) { this.expr = expr; } + /** + * Negates the given expression. + * + * @param version the version to interpret against + * @return {@code true} if the given expression evaluates to + * {@code false} and {@code false} otherwise + */ @Override public boolean interpret(Version version) { return !expr.interpret(version); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/NotEqual.java b/src/main/java/com/github/zafarkhaja/semver/expr/NotEqual.java index 60e8289..466592a 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/NotEqual.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/NotEqual.java @@ -26,17 +26,35 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the comparison "not equal" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class NotEqual implements Expression { + /** + * The parsed version, the right-hand operand of the "not equal" operator. + */ private final Version parsedVersion; + /** + * Constructs a {@code NotEqual} expression with the parsed version. + * + * @param parsedVersion the parsed version + */ NotEqual(Version parsedVersion) { this.parsedVersion = parsedVersion; } + /** + * Checks if the current version does not equal the parsed version. + * + * @param version the version to compare with, the left-hand + * operand of the "not equal" operator + * @return {@code true} if the version does not equal the + * parsed version or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return !version.equals(parsedVersion); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Or.java b/src/main/java/com/github/zafarkhaja/semver/expr/Or.java index dec3987..1bf4c36 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Or.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/Or.java @@ -26,19 +26,42 @@ package com.github.zafarkhaja.semver.expr; import com.github.zafarkhaja.semver.Version; /** + * Expression for the logical "or" operator. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ class Or implements Expression { + /** + * The left-hand operand of expression. + */ private final Expression left; + + /** + * The right-hand operand of expression. + */ private final Expression right; + /** + * Constructs a {@code Or} expression with + * the left-hand and right-hand operands. + * + * @param left the left-hand operand of expression + * @param right the right-hand operand of expression + */ Or(Expression left, Expression right) { this.left = left; this.right = right; } + /** + * Checks if one of the operands evaluates to {@code true}. + * + * @param version the version to interpret against + * @return {@code true} if one of the operands evaluates to {@code true} + * or {@code false} otherwise + */ @Override public boolean interpret(Version version) { return left.interpret(version) || right.interpret(version); diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/UnexpectedTokenException.java b/src/main/java/com/github/zafarkhaja/semver/expr/UnexpectedTokenException.java index 67ebd55..cc10185 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/UnexpectedTokenException.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/UnexpectedTokenException.java @@ -28,19 +28,42 @@ import com.github.zafarkhaja.semver.expr.Lexer.*; import java.util.Arrays; /** + * Thrown when a token of unexpected types is encountered during the parsing. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ public class UnexpectedTokenException extends ParserException { + /** + * The unexpected token. + */ private final Token unexpected; + + /** + * The array of the expected token types. + */ private final Token.Type[] expected; + /** + * Constructs a {@code UnexpectedTokenException} instance + * with the unexpected token and the expected types. + * + * @param element the unexpected token + * @param expected an array of the expected token types + */ UnexpectedTokenException(Token token, Token.Type... expected) { unexpected = token; this.expected = expected; } + /** + * Returns the string representation of this exception + * containing the information about the unexpected + * token and, if available, about the expected types. + * + * @return the string representation of this exception + */ @Override public String toString() { String message = "Unexpected token '" + unexpected + "'"; diff --git a/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java b/src/main/java/com/github/zafarkhaja/semver/expr/package-info.java similarity index 83% copy from src/main/java/com/github/zafarkhaja/semver/expr/Expression.java copy to src/main/java/com/github/zafarkhaja/semver/expr/package-info.java index 48ba122..001d23d 100644 --- a/src/main/java/com/github/zafarkhaja/semver/expr/Expression.java +++ b/src/main/java/com/github/zafarkhaja/semver/expr/package-info.java @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.github.zafarkhaja.semver.expr; - -import com.github.zafarkhaja.semver.Version; /** + * This package contains classes that implement the SemVer Expressions. + * + * The main class of the package is the {@code ExpressionParser} class which + * parses the specified expressions and returns the Abstract Syntax Tree. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ -public interface Expression { - boolean interpret(Version version); -} +package com.github.zafarkhaja.semver.expr; diff --git a/src/main/java/com/github/zafarkhaja/semver/Parser.java b/src/main/java/com/github/zafarkhaja/semver/package-info.java similarity index 84% copy from src/main/java/com/github/zafarkhaja/semver/Parser.java copy to src/main/java/com/github/zafarkhaja/semver/package-info.java index 32d7571..d89e198 100644 --- a/src/main/java/com/github/zafarkhaja/semver/Parser.java +++ b/src/main/java/com/github/zafarkhaja/semver/package-info.java @@ -21,12 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.github.zafarkhaja.semver; /** + * This is the root package of the Java SemVer library. + * + * The package exports most of the public API. The main entry point of the + * package is the {@code Version} class, which implements the Facade design + * pattern. * * @author Zafar Khaja <[email protected]> + * @since 0.1.0 */ -public interface Parser<T> { - T parse(String input); -} +package com.github.zafarkhaja.semver; diff --git a/src/main/java/com/github/zafarkhaja/semver/util/Stream.java b/src/main/java/com/github/zafarkhaja/semver/util/Stream.java index 50dddf7..9d5d041 100644 --- a/src/main/java/com/github/zafarkhaja/semver/util/Stream.java +++ b/src/main/java/com/github/zafarkhaja/semver/util/Stream.java @@ -28,23 +28,65 @@ import java.util.Iterator; import java.util.NoSuchElementException; /** + * A simple stream class used to represent a stream of characters or tokens. + * + * @param <E> the type of elements held in this stream * * @author Zafar Khaja <[email protected]> + * @see com.github.zafarkhaja.semver.VersionParser + * @see com.github.zafarkhaja.semver.expr.Lexer + * @see com.github.zafarkhaja.semver.expr.ExpressionParser + * @since 0.7.0 */ public class Stream<E> implements Iterable<E> { + /** + * The {@code ElementType} interface represents types of the elements + * held by this stream and can be used for stream filtering. + * + * @param <E> type of elements held by this stream + */ public static interface ElementType<E> { + + /** + * Checks if the specified element matches this type. + * + * @param element the element to be tested + * @return {@code true} if the element matches this type + * or {@code false} otherwise + */ boolean isMatchedBy(E element); } + /** + * The array holding all the elements of this stream. + */ private final E[] elements; + /** + * The current offset which is incremented when an element is consumed. + * + * @see #consume() + */ private int offset = 0; + /** + * Constructs a stream containing the specified elements. + * + * The stream does not store the real elements but the defensive copy. + * + * @param elements the elements to be streamed + */ public Stream(E[] elements) { this.elements = elements.clone(); } + /** + * Consumes the next element in this stream. + * + * @return the next element in this stream + * or {@code null} if no more elements left + */ public E consume() { if (offset >= elements.length) { return null; @@ -52,6 +94,14 @@ public class Stream<E> implements Iterable<E> { return elements[offset++]; } + /** + * Consumes the next element in this stream + * only if it is of the expected types. + * + * @param expected the types which are expected + * @return the next element in this stream + * @throws UnexpectedElementTypeException if the next element is of an unexpected type + */ public E consume(ElementType<E>... expected) { E lookahead = lookahead(1); for (ElementType<E> type : expected) { @@ -62,10 +112,23 @@ public class Stream<E> implements Iterable<E> { throw new UnexpectedElementTypeException(lookahead, expected); } + /** + * Returns the next element in this stream without consuming it. + * + * @return the next element in this stream + */ public E lookahead() { return lookahead(1); } + /** + * Returns the element at the specified position + * in this stream without consuming it. + * + * @param position the position of the element to return + * @return the element at the specified position + * or {@code null} if no more elements left + */ public E lookahead(int position) { int idx = offset + position - 1; if (idx < elements.length) { @@ -74,6 +137,13 @@ public class Stream<E> implements Iterable<E> { return null; } + /** + * Checks if the next element in this stream is of the expected types. + * + * @param expected the expected types + * @return {@code true} if the next element is of the expected types + * or {@code false} otherwise + */ public boolean positiveLookahead(ElementType<E>... expected) { for (ElementType<E> type : expected) { if (type.isMatchedBy(lookahead(1))) { @@ -83,6 +153,15 @@ public class Stream<E> implements Iterable<E> { return false; } + /** + * Checks if there exists an element in this stream of + * the expected types before the specified type. + * + * @param before the type before which to search + * @param expected the expected types + * @return {@code true} if there is an element of the expected types + * before the specified type or {@code false} otherwise + */ public boolean positiveLookaheadBefore( ElementType<E> before, ElementType<E>... expected @@ -102,6 +181,15 @@ public class Stream<E> implements Iterable<E> { return false; } + /** + * Checks if there is an element in this stream of + * the expected types until the specified position. + * + * @param until the position until which to search + * @param expected the expected types + * @return {@code true} if there is an element of the expected types + * until the specified position or {@code false} otherwise + */ public boolean positiveLookaheadUntil( int until, ElementType<E>... expected @@ -116,17 +204,28 @@ public class Stream<E> implements Iterable<E> { return false; } + /** + * Returns an iterator over elements that are left in this stream. + * + * @return an iterator of the remaining elements in this stream + */ @Override public Iterator<E> iterator() { return new Iterator<E>() { private int index = offset; + /** + * {@inheritDoc} + */ @Override public boolean hasNext() { return index < elements.length; } + /** + * {@inheritDoc} + */ @Override public E next() { if (index >= elements.length) { @@ -135,6 +234,9 @@ public class Stream<E> implements Iterable<E> { return elements[index++]; } + /** + * {@inheritDoc} + */ @Override public void remove() { throw new UnsupportedOperationException(); @@ -142,6 +244,14 @@ public class Stream<E> implements Iterable<E> { }; } + /** + * Returns an array containing all of the + * elements that are left in this stream. + * + * The returned array is a safe copy. + * + * @return an array containing all of elements in this stream + */ public E[] toArray() { return Arrays.copyOfRange(elements, offset, elements.length); } diff --git a/src/main/java/com/github/zafarkhaja/semver/util/UnexpectedElementTypeException.java b/src/main/java/com/github/zafarkhaja/semver/util/UnexpectedElementTypeException.java index 7eb5bcb..e6bb827 100644 --- a/src/main/java/com/github/zafarkhaja/semver/util/UnexpectedElementTypeException.java +++ b/src/main/java/com/github/zafarkhaja/semver/util/UnexpectedElementTypeException.java @@ -27,19 +27,43 @@ import com.github.zafarkhaja.semver.util.Stream.ElementType; import java.util.Arrays; /** + * Thrown when attempting to consume a stream element of unexpected types. * * @author Zafar Khaja <[email protected]> + * @see Stream#consume(Stream.ElementType...) + * @since 0.7.0 */ public class UnexpectedElementTypeException extends RuntimeException { + /** + * The unexpected element in the stream. + */ private final Object unexpected; + + /** + * The array of the expected element types. + */ private final ElementType<?>[] expected; + /** + * Constructs a {@code UnexpectedElementTypeException} instance + * with the unexpected element and the expected types. + * + * @param element the unexpected element in the stream + * @param expected an array of the expected element types + */ UnexpectedElementTypeException(Object element, ElementType<?>... expected) { unexpected = element; this.expected = expected; } + /** + * Returns the string representation of this exception + * containing the information about the unexpected + * element and, if available, about the expected types. + * + * @return the string representation of this exception + */ @Override public String toString() { String message = "Unexpected element '" + unexpected + "'"; diff --git a/src/main/java/com/github/zafarkhaja/semver/Parser.java b/src/main/java/com/github/zafarkhaja/semver/util/package-info.java similarity index 91% copy from src/main/java/com/github/zafarkhaja/semver/Parser.java copy to src/main/java/com/github/zafarkhaja/semver/util/package-info.java index 32d7571..121d57f 100644 --- a/src/main/java/com/github/zafarkhaja/semver/Parser.java +++ b/src/main/java/com/github/zafarkhaja/semver/util/package-info.java @@ -21,12 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.github.zafarkhaja.semver; /** + * This package provides some useful utility classes. * * @author Zafar Khaja <[email protected]> + * @since 0.7.0 */ -public interface Parser<T> { - T parse(String input); -} +package com.github.zafarkhaja.semver.util; -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jsemver.git _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

