Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ This document is formatted according to the principles of [Keep A CHANGELOG](htt
- [Java] Optimize `GherkinLine.substringTrimmed` ([#444](https://github.com/cucumber/gherkin/pull/444))
- [Java] Improve performance with a generated keyword matcher ([#445](https://github.com/cucumber/gherkin/pull/445))

### Deprecated
- [Java] Deprecate `GherkinDialectProvider` in favour of `GherkinDialects` ([#448](https://github.com/cucumber/gherkin/pull/448))

### Changed
- Fixed Afrikaans translation for "rule" ([#428](https://github.com/cucumber/gherkin/pull/428))

Expand Down
29 changes: 27 additions & 2 deletions java/src/codegen/resources/templates/gherkin-dialects.java.ftl
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
package io.cucumber.gherkin;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import static java.util.Collections.unmodifiableMap;
import static java.util.Objects.requireNonNull;

final class GherkinDialects {
static final Map<String, GherkinDialect> DIALECTS;
/**
* Utility class to access all known {@linkplain GherkinDialect gherkin dialects}.
*/
public final class GherkinDialects {

private static final Map<String, GherkinDialect> DIALECTS;

private GherkinDialects() {
// Utility class
}

public static Set<String> getLanguages() {
return GherkinDialects.DIALECTS.keySet();
}

public static Collection<GherkinDialect> getDialects() {
return GherkinDialects.DIALECTS.values();
}

public static Optional<GherkinDialect> getDialect(String language) {
requireNonNull(language);
return Optional.ofNullable(GherkinDialects.DIALECTS.get(language));
}

static {
Map<String, GherkinDialect> dialects = new LinkedHashMap<>();
Expand Down
14 changes: 7 additions & 7 deletions java/src/codegen/resources/templates/keyword-matchers.java.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import static io.cucumber.messages.types.StepKeywordType.CONTEXT;
import static io.cucumber.messages.types.StepKeywordType.OUTCOME;
import static io.cucumber.messages.types.StepKeywordType.UNKNOWN;

import static io.cucumber.gherkin.GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR_LENGTH;
import static io.cucumber.gherkin.Constants.TITLE_KEYWORD_SEPARATOR_LENGTH;

/**
* Generated by GenerateKeywordMatchers.
Expand All @@ -29,7 +29,7 @@ final class KeywordMatchers {
<#list matchers as name, matcher>
private static final class ${matcher.className} implements KeywordMatcher {
@Override
public Match matchFeatureKeyword(GherkinLine line) {
public Match matchFeatureKeyword(Line line) {
<#list matcher.features as feature>
if (line.startsWithTitleKeyword("${feature.keyword}")) {
return new Match("${feature.keyword}", ${feature.length} + TITLE_KEYWORD_SEPARATOR_LENGTH);
Expand All @@ -38,7 +38,7 @@ final class KeywordMatchers {
return null;
}
@Override
public Match matchBackgroundKeyword(GherkinLine line) {
public Match matchBackgroundKeyword(Line line) {
<#list matcher.backgrounds as background>
if (line.startsWithTitleKeyword("${background.keyword}")) {
return new Match("${background.keyword}", ${background.length} + TITLE_KEYWORD_SEPARATOR_LENGTH);
Expand All @@ -47,7 +47,7 @@ final class KeywordMatchers {
return null;
}
@Override
public Match matchRuleKeyword(GherkinLine line) {
public Match matchRuleKeyword(Line line) {
<#list matcher.rules as rule>
if (line.startsWithTitleKeyword("${rule.keyword}")) {
return new Match("${rule.keyword}", ${rule.length} + TITLE_KEYWORD_SEPARATOR_LENGTH);
Expand All @@ -56,7 +56,7 @@ final class KeywordMatchers {
return null;
}
@Override
public Match matchScenarioKeyword(GherkinLine line) {
public Match matchScenarioKeyword(Line line) {
<#list matcher.scenarios as scenario>
if (line.startsWithTitleKeyword("${scenario.keyword}")) {
return new Match("${scenario.keyword}", ${scenario.length} + TITLE_KEYWORD_SEPARATOR_LENGTH);
Expand All @@ -65,7 +65,7 @@ final class KeywordMatchers {
return null;
}
@Override
public Match matchExampleKeyword(GherkinLine line) {
public Match matchExampleKeyword(Line line) {
<#list matcher.examples as example>
if (line.startsWithTitleKeyword("${example.keyword}")) {
return new Match("${example.keyword}", ${example.length} + TITLE_KEYWORD_SEPARATOR_LENGTH);
Expand All @@ -74,7 +74,7 @@ final class KeywordMatchers {
return null;
}
@Override
public StepMatch matchStepKeyword(GherkinLine line) {
public StepMatch matchStepKeyword(Line line) {
<#list matcher.steps as step>
if (line.startsWith("${step.keyword}")) {
return new StepMatch("${step.keyword}", ${step.length}, ${step.keywordType} );
Expand Down
16 changes: 16 additions & 0 deletions java/src/main/java/io/cucumber/gherkin/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.cucumber.gherkin;

final class Constants {

static final char TAG_PREFIX_CHAR = '@';
static final char COMMENT_PREFIX_CHAR = '#';
static final char TITLE_KEYWORD_SEPARATOR = ':';
/**
* Size of TITLE_KEYWORD_SEPARATOR = 1 char.
*/
static final int TITLE_KEYWORD_SEPARATOR_LENGTH = 1;
static final char TABLE_CELL_SEPARATOR = '|';
static final String DOCSTRING_SEPARATOR = "\"\"\"";
static final String DOCSTRING_ALTERNATIVE_SEPARATOR = "```";
static final String DEFAULT_LANGUAGE = "en";
}
5 changes: 4 additions & 1 deletion java/src/main/java/io/cucumber/gherkin/GherkinDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
import static java.util.Collections.unmodifiableSet;
import static java.util.Objects.requireNonNull;

/**
* Holds all localized keywords for a single language.
*/
public final class GherkinDialect {
private static final Comparator<String> LONGEST_TO_SHORTEST_COMPARATOR =
(s1, s2) -> Integer.compare(s2.length(), s1.length());
(a, b) -> Integer.compare(b.length(), a.length());
private final String language;
private final String name;
private final String nativeName;
Expand Down
21 changes: 9 additions & 12 deletions java/src/main/java/io/cucumber/gherkin/GherkinDialectProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,32 @@

import static java.util.Objects.requireNonNull;

/**
* @deprecated use {@link GherkinDialects} instead.
*/
@Deprecated
public final class GherkinDialectProvider {

private final String defaultDialectName;
private GherkinDialect defaultDialect;

public GherkinDialectProvider(String defaultDialectName) {
this.defaultDialectName = requireNonNull(defaultDialectName);
}

public GherkinDialectProvider() {
this("en");
this(Constants.DEFAULT_LANGUAGE);
}

public GherkinDialect getDefaultDialect() {
if (defaultDialect == null) {
defaultDialect = GherkinDialects.DIALECTS.get(defaultDialectName);
if (defaultDialect == null) {
throw new ParserException.NoSuchLanguageException(defaultDialectName, null);
}
}
return defaultDialect;
return GherkinDialects.getDialect(defaultDialectName)
.orElseThrow(() -> new ParserException.NoSuchLanguageException(defaultDialectName, null));
}

public Optional<GherkinDialect> getDialect(String language) {
requireNonNull(language);
return Optional.ofNullable(GherkinDialects.DIALECTS.get(language));
return GherkinDialects.getDialect(language);
}

public Set<String> getLanguages() {
return GherkinDialects.DIALECTS.keySet();
return GherkinDialects.getLanguages();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,11 @@ private void ensureCellCount(List<TableRow> rows) {

@SuppressWarnings("ForLoopReplaceableByForEach") // classic 'for' loop is ~2x faster than 'for-each'
private List<TableCell> getCells(Token token) {
List<GherkinLineSpan> matchedItems = token.matchedItems;
List<LineSpan> matchedItems = token.matchedItems;
int itemSize = matchedItems.size();
List<TableCell> cells = new ArrayList<>(itemSize);
for (int i = 0; i < itemSize; i++) {
GherkinLineSpan cellItem = matchedItems.get(i);
LineSpan cellItem = matchedItems.get(i);
TableCell tableCell = new TableCell(
atColumn(token.location, cellItem.column),
cellItem.text
Expand All @@ -300,7 +300,7 @@ private List<Tag> getTags(AstNode node) {
List<Token> tokens = tagsNode.getTokens(TokenType.TagLine);
List<Tag> tags = new ArrayList<>();
for (Token token : tokens) {
for (GherkinLineSpan tagItem : token.matchedItems) {
for (LineSpan tagItem : token.matchedItems) {
tags.add(new Tag(atColumn(token.location, tagItem.column), tagItem.text, idGenerator.newId()));
}
}
Expand Down
7 changes: 0 additions & 7 deletions java/src/main/java/io/cucumber/gherkin/GherkinException.java

This file was deleted.

This file was deleted.

20 changes: 10 additions & 10 deletions java/src/main/java/io/cucumber/gherkin/GherkinTokenMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static io.cucumber.gherkin.GherkinLanguageConstants.COMMENT_PREFIX_CHAR;
import static io.cucumber.gherkin.GherkinLanguageConstants.DEFAULT_LANGUAGE;
import static io.cucumber.gherkin.GherkinLanguageConstants.DOCSTRING_ALTERNATIVE_SEPARATOR;
import static io.cucumber.gherkin.GherkinLanguageConstants.DOCSTRING_SEPARATOR;
import static io.cucumber.gherkin.GherkinLanguageConstants.TABLE_CELL_SEPARATOR;
import static io.cucumber.gherkin.GherkinLanguageConstants.TAG_PREFIX_CHAR;
import static io.cucumber.gherkin.Constants.COMMENT_PREFIX_CHAR;
import static io.cucumber.gherkin.Constants.DEFAULT_LANGUAGE;
import static io.cucumber.gherkin.Constants.DOCSTRING_ALTERNATIVE_SEPARATOR;
import static io.cucumber.gherkin.Constants.DOCSTRING_SEPARATOR;
import static io.cucumber.gherkin.Constants.TABLE_CELL_SEPARATOR;
import static io.cucumber.gherkin.Constants.TAG_PREFIX_CHAR;
import static io.cucumber.gherkin.Locations.COLUMN_OFFSET;
import static io.cucumber.gherkin.Locations.atColumn;
import static io.cucumber.gherkin.Parser.TokenType;
Expand Down Expand Up @@ -61,7 +61,7 @@ private void setLanguageMatched(String language, Location location) {
currentKeywordMatcher = keywordMatcher;
}

private void setTokenMatched(Token token, TokenType matchedType, String text, String keyword, int indent, StepKeywordType keywordType, List<GherkinLineSpan> items) {
private void setTokenMatched(Token token, TokenType matchedType, String text, String keyword, int indent, StepKeywordType keywordType, List<LineSpan> items) {
token.matchedType = matchedType;
token.matchedKeyword = keyword;
token.keywordType = keywordType;
Expand Down Expand Up @@ -127,7 +127,7 @@ public boolean match_TagLine(Token token) {
if (!token.line.startsWith(TAG_PREFIX_CHAR)) {
return false;
}
List<GherkinLineSpan> tags = GherkinTagLine.parse(token.line.getIndent(), token.line.getText(), token.location);
List<LineSpan> tags = TagLine.parse(token.line.getIndent(), token.line.getText(), token.location);
setTokenMatched(token, TokenType.TagLine, null, null, token.line.getIndent(), null, tags);
return true;
}
Expand Down Expand Up @@ -157,7 +157,7 @@ public boolean match_ExamplesLine(Token token) {
return matchTitleLine(token, TokenType.ExamplesLine, currentKeywordMatcher::matchExampleKeyword);
}

private boolean matchTitleLine(Token token, TokenType tokenType, Function<GherkinLine, KeywordMatcher.Match> matcher) {
private boolean matchTitleLine(Token token, TokenType tokenType, Function<Line, KeywordMatcher.Match> matcher) {
KeywordMatcher.Match match = matcher.apply(token.line);
if (match == null) {
return false;
Expand Down Expand Up @@ -216,7 +216,7 @@ public boolean match_TableRow(Token token) {
if (!token.line.startsWith(TABLE_CELL_SEPARATOR)) {
return false;
}
List<GherkinLineSpan> tableCells = GherkinTableRowLine.parse(token.line.getIndent(), token.line.getText());
List<LineSpan> tableCells = TableRowLine.parse(token.line.getIndent(), token.line.getText());
setTokenMatched(token, TokenType.TableRow, null, null, token.line.getIndent(), null, tableCells);
return true;
}
Expand Down
12 changes: 6 additions & 6 deletions java/src/main/java/io/cucumber/gherkin/KeywordMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

interface KeywordMatcher {

Match matchFeatureKeyword(GherkinLine line);
Match matchBackgroundKeyword(GherkinLine line);
Match matchRuleKeyword(GherkinLine line);
Match matchScenarioKeyword(GherkinLine line);
Match matchExampleKeyword(GherkinLine line);
StepMatch matchStepKeyword(GherkinLine line);
Match matchFeatureKeyword(Line line);
Match matchBackgroundKeyword(Line line);
Match matchRuleKeyword(Line line);
Match matchScenarioKeyword(Line line);
Match matchExampleKeyword(Line line);
StepMatch matchStepKeyword(Line line);

final class StepMatch {
private final String keyword;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.cucumber.gherkin;

import static io.cucumber.gherkin.GherkinLanguageConstants.TITLE_KEYWORD_SEPARATOR;
import static io.cucumber.gherkin.Constants.TITLE_KEYWORD_SEPARATOR;
import static io.cucumber.gherkin.StringUtils.trimAndIndent;
import static java.util.Objects.requireNonNull;

final class GherkinLine {
final class Line {

/**
* The line text, including all leading and trailing whitespace characters.
Expand All @@ -24,7 +24,7 @@ final class GherkinLine {
private final int indent;
private final int textLength;

GherkinLine(String rawText) {
Line(String rawText) {
this.rawText = requireNonNull(rawText);
StringUtils.IndentedText trimmedIndent = trimAndIndent(rawText);
this.text = trimmedIndent.getText();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.cucumber.gherkin;

final class GherkinLineSpan {
final class LineSpan {
/**
* Index-1 based position in codepoints.
*/
Expand All @@ -11,7 +11,7 @@ final class GherkinLineSpan {
*/
final String text;

GherkinLineSpan(int column, String text) {
LineSpan(int column, String text) {
this.column = column;
this.text = text;
}
Expand All @@ -20,7 +20,7 @@ final class GherkinLineSpan {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GherkinLineSpan that = (GherkinLineSpan) o;
LineSpan that = (LineSpan) o;
return column == that.column && text.equals(that.text);
}

Expand Down
Loading
Loading