Skip to content

Commit

Permalink
Avoid NFEs when range checking in semantic lookahead
Browse files Browse the repository at this point in the history
  • Loading branch information
simonpoole committed Nov 27, 2019
1 parent 9e4135c commit 1f7e049
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ repositories {

``` groovy
dependencies {
compile "ch.poole:OpeningHoursParser:0.16.1"
compile "ch.poole:OpeningHoursParser:0.17.1"
}
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ apply plugin: 'maven-publish'
apply plugin: "jacoco"


version = '0.17.0'
version = '0.17.1'
sourceCompatibility = 1.8
targetCompatibility = 1.8

Expand Down
21 changes: 12 additions & 9 deletions src/main/java/ch/poole/openinghoursparser/OpeningHoursParser.jj
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@

package ch.poole.openinghoursparser;
import java.util.ArrayList;import java.util.Collections;
import java.util.Locale;import java.io.ByteArrayInputStream;public class OpeningHoursParser{
import java.util.Locale;import java.io.ByteArrayInputStream;

import ch.poole.openinghoursparser.Util;public class OpeningHoursParser{
static int TWELVEHOURS = 12*60;

boolean strict = false;
enum AMPM { AM, PM };
boolean monthOnly = false;}PARSER_END(OpeningHoursParser)SKIP :{ "\r"| "\n"| " "| "\t"
boolean monthOnly = false;}
PARSER_END(OpeningHoursParser)SKIP :{ "\r"| "\n"| " "| "\t"
| "\u200A"
| "\u2009"
| "\u00A0"
Expand Down Expand Up @@ -91,9 +94,9 @@ TOKEN :
{ < TO : " to " >
}/**
* match a number between 1 and 5
*/Token one2five() :{ Token n = null;}{ LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 && Integer.parseInt(getToken(1).image) <= 5 }) n = < NUMBER > { return n; }}/**
*/Token one2five() :{ Token n = null;}{ LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 1, 5) }) n = < NUMBER > { return n; }}/**
* match a positive number larger than 1
*/Token number() :{ Token n = null;}{ LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 }) n = < NUMBER > { return n; }}/**
*/Token number() :{ Token n = null;}{ LOOKAHEAD({ getToken(1).kind == NUMBER && Util.equalsOrMore(getToken(1).image, 1) }) n = < NUMBER > { return n; }}/**
* Match a comment.
*/String comment() :{ StringBuilder builder = new StringBuilder();}{ < QUOTE > ( getChar(builder) )* < ENDQUOTE > { return builder.toString(); }}/**
* Match char inside quoted string.
Expand All @@ -103,7 +106,7 @@ TOKEN :
/**
* returns a number if between 0 and 24
* uses semantic lookahead
*/Token hours() :{ Token h = null;}{ LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 0 && Integer.parseInt(getToken(1).image) <= 24 }) h = < NUMBER > { return h; }}
*/Token hours() :{ Token h = null;}{ LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 0, 24) }) h = < NUMBER > { return h; }}
/**
* returns the total number of minutes for a time of the form hh:00 or just hh
*
Expand Down Expand Up @@ -166,7 +169,7 @@ AMPM ampm() :
/**
* returns the total number of minutes for a time of the form hh:00 or just hh with hh up to 48
*/int extendedtime() :{ Token h = null; Token m = null; int result = 0;
AMPM ampm = null;}{ ( LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 0 && Integer.parseInt(getToken(1).image) <= 48 }) h = < NUMBER > ) ( m = < MINUTES > {
AMPM ampm = null;}{ ( LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 0, 48) }) h = < NUMBER > ) ( m = < MINUTES > {
if (strict && (m.image.length() < 3 || !m.image.startsWith(":"))) {
ParseException pex = new ParseException("Invalid minutes at " + token.next.beginLine + ", column " + token.next.beginColumn);
pex.currentToken = token;
Expand Down Expand Up @@ -336,15 +339,15 @@ WeekDayRange weekday_range() : { String startDay = null; String endDay = nul
return mdr;
}
}
int daynum() :{ Token n = null;}{ ( LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 && Integer.parseInt(getToken(1).image) <= 31 }) n = < NUMBER > ) { return Integer.parseInt(n.image); }}
int daynum() :{ Token n = null;}{ ( LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 1, 31) }) n = < NUMBER > ) { return Integer.parseInt(n.image); }}

int year() :
{
Token n = null;
}
{
(
LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1900})
LOOKAHEAD({ getToken(1).kind == NUMBER && Util.equalsOrMore(getToken(1).image, 1900)})
n = < NUMBER >
)
{
Expand Down Expand Up @@ -486,7 +489,7 @@ int year() :
return result;
}
)
}int weeknum() :{ Token n = null;}{ ( LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 && Integer.parseInt(getToken(1).image) <= 54 }) n = < NUMBER > ) { return Integer.parseInt(n.image); }}WeekRange week_range() :{ WeekRange wr = new WeekRange(); Token w = null; Token w1 = null;
}int weeknum() :{ Token n = null;}{ ( LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 1, 54) }) n = < NUMBER > ) { return Integer.parseInt(n.image); }}WeekRange week_range() :{ WeekRange wr = new WeekRange(); Token w = null; Token w1 = null;
Token to = null;}{ wr.startWeek = weeknum() ( ( < HYPHEN > | (to = < TO >)
)
(
Expand Down
35 changes: 34 additions & 1 deletion src/main/java/ch/poole/openinghoursparser/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static List<ArrayList<Rule>> getMergeableRules(List<Rule> rules) {
public static String rulesToOpeningHoursString(@NotNull List<Rule> rules) {
return rulesToOpeningHoursString(rules, false);
}

/**
* Generate an OH string from rules
*
Expand Down Expand Up @@ -180,4 +180,37 @@ static <T extends Copy<?>> List<T> copyList(List<T> l) {
}
return r;
}

/**
* Make a safe comparison catching parse errors
*
* @param token the current token
* @param lower lower bounds
* @return true if greater or equals to limit and is an int
*/
static boolean equalsOrMore(@NotNull String token, int lower) {
try {
int temp = Integer.parseInt(token);
return temp >= lower;
} catch (NumberFormatException nfe) {
return false;
}
}

/**
* Make a safe comparison catching parse errors
*
* @param token the current token
* @param lower lower bounds
* @param upper upper bounds
* @return true if in bounds and is an int
*/
static boolean between(@NotNull String token, int lower, int upper) {
try {
int temp = Integer.parseInt(token);
return temp >= lower && temp <= upper;
} catch (NumberFormatException nfe) {
return false;
}
}
}
4 changes: 2 additions & 2 deletions test-data/oh.txt-result
Original file line number Diff line number Diff line change
Expand Up @@ -8989,7 +8989,7 @@
1
1
1
2
1
1
1
0 02:00-09:00
Expand Down Expand Up @@ -11083,7 +11083,7 @@
1
0 08:00-10:30,11:00-14:30; Fr off
0 08:00-21:00
2
1
0 08:00-10:00
0 08:00-10:00,04:00-19:00
1
Expand Down
4 changes: 2 additions & 2 deletions test-data/oh.txt-result-strict
Original file line number Diff line number Diff line change
Expand Up @@ -8989,7 +8989,7 @@
1
1
1
2
1
1
1
1
Expand Down Expand Up @@ -11083,7 +11083,7 @@
1
1
1
2
1
1
1
1
Expand Down

0 comments on commit 1f7e049

Please sign in to comment.