public class Background extends ScenarioDefinition {
    public Background(Location location, String keyword, String name, String description, List<Step> steps) {
        super(location, keyword, name, description, steps);
    }
} public class Comment extends Node {
    private final String text;

    public Comment(Location location, String text) {
        super(location);
        this.text = text;
    }

    public String getText() {
        return text;
    }
} public class DataTable extends Node {
    private final List<TableRow> rows;

    public DataTable(List<TableRow> rows) {
        super(rows.get(0).getLocation());
        this.rows = Collections.unmodifiableList(rows);
    }

    public List<TableRow> getRows() {
        return rows;
    }
} public class DocString extends Node {
    private final String contentType;
    private final String content;

    public DocString(Location location, String contentType, String content) {
        super(location);
        this.contentType = contentType;
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public String getContentType() {
        return contentType;
    }
} public class Examples extends Node {
    private final List<Tag> tags;
    private final String keyword;
    private final String name;
    private final String description;
    private final TableRow tableHeader;
    private final List<TableRow> tableBody;

    public Examples(Location location, List<Tag> tags, String keyword, String name, String description, TableRow tableHeader, List<TableRow> tableBody) {
        super(location);
        this.tags = Collections.unmodifiableList(tags);
        this.keyword = keyword;
        this.name = name;
        this.description = description;
        this.tableHeader = tableHeader;
        this.tableBody = tableBody != null ? Collections.unmodifiableList(tableBody) : null;
    }

    public String getKeyword() {
        return keyword;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public List<TableRow> getTableBody() {
        return tableBody;
    }

    public TableRow getTableHeader() {
        return tableHeader;
    }

    public List<Tag> getTags() {
        return tags;
    }
} public class Feature extends Node {
    private final List<Tag> tags;
    private final String language;
    private final String keyword;
    private final String name;
    private final String description;
    private final List<ScenarioDefinition> children;

    public Feature(
            List<Tag> tags,
            Location location,
            String language,
            String keyword,
            String name,
            String description,
            List<ScenarioDefinition> children) {
        super(location);
        this.tags = Collections.unmodifiableList(tags);
        this.language = language;
        this.keyword = keyword;
        this.name = name;
        this.description = description;
        this.children = Collections.unmodifiableList(children);
    }

    public List<ScenarioDefinition> getChildren() {
        return children;
    }

    public String getLanguage() {
        return language;
    }

    public String getKeyword() {
        return keyword;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public List<Tag> getTags() {
        return tags;
    }
} public class GherkinDocument extends Node {
    private final Feature feature;
    private final List<Comment> comments;

    public GherkinDocument(
            Feature feature,
            List<Comment> comments) {
        super(null);
        this.feature = feature;
        this.comments = Collections.unmodifiableList(comments);
    }

    public Feature getFeature() {
        return feature;
    }

    public List<Comment> getComments() {
        return comments;
    }
} public class Location {
    private final int line;
    private final int column;

    public Location(int line, int column) {
        this.line = line;
        this.column = column;
    }

    public int getLine() {
        return line;
    }

    public int getColumn() {
        return column;
    }
} public abstract class Node {
    private final String type = getClass().getSimpleName();
    private final Location location;

    protected Node(Location location) {
        this.location = location;
    }

    public Location getLocation() {
        return location;
    }
} public class Scenario extends ScenarioDefinition {
    private final List<Tag> tags;

    public Scenario(List<Tag> tags, Location location, String keyword, String name, String description, List<Step> steps) {
        super(location, keyword, name, description, steps);
        this.tags = Collections.unmodifiableList(tags);
    }

    public List<Tag> getTags() {
        return tags;
    }
} public abstract class ScenarioDefinition extends Node {
    private final String keyword;
    private final String name;
    private final String description;
    private final List<Step> steps;

    public ScenarioDefinition(Location location, String keyword, String name, String description, List<Step> steps) {
        super(location);
        this.keyword = keyword;
        this.name = name;
        this.description = description;
        this.steps = Collections.unmodifiableList(steps);
    }

    public String getName() {
        return name;
    }

    public String getKeyword() {
        return keyword;
    }

    public String getDescription() {
        return description;
    }

    public List<Step> getSteps() {
        return steps;
    }
} public class ScenarioOutline extends ScenarioDefinition {
    private final List<Tag> tags;
    private final List<Examples> examples;

    public ScenarioOutline(List<Tag> tags, Location location, String keyword, String name, String description, List<Step> steps, List<Examples> examples) {
        super(location, keyword, name, description, steps);
        this.tags = Collections.unmodifiableList(tags);
        this.examples = Collections.unmodifiableList(examples);
    }

    public List<Tag> getTags() {
        return tags;
    }

    public List<Examples> getExamples() {
        return examples;
    }
} public class Step extends Node {
    private final String keyword;
    private final String text;
    private final Node argument;

    public Step(Location location, String keyword, String text, Node argument) {
        super(location);
        this.keyword = keyword;
        this.text = text;
        this.argument = argument;
    }

    public String getText() {
        return text;
    }

    public String getKeyword() {
        return keyword;
    }

    public Node getArgument() {
        return argument;
    }

} public class TableCell extends Node {
    private final String value;

    public TableCell(Location location, String value) {
        super(location);
        this.value = value;
    }

    public String getValue() {
        return value;
    }

} public class TableRow extends Node {
    private final List<TableCell> cells;

    public TableRow(Location location, List<TableCell> cells) {
        super(location);
        this.cells = Collections.unmodifiableList(cells);
    }

    public List<TableCell> getCells() {
        return cells;
    }

} public class Tag extends Node {
    private final String name;

    public Tag(Location location, String name) {
        super(location);
        this.name = name;
    }

    public String getName() {
        return name;
    }

} public interface Builder<T> {
    void build(Token token);
    void startRule(RuleType ruleType);
    void endRule(RuleType ruleType);
    T getResult();
    void reset();
} public enum RuleType {
    None,
    _EOF, // #EOF
    _Empty, // #Empty
    _Comment, // #Comment
    _TagLine, // #TagLine
    _FeatureLine, // #FeatureLine
    _BackgroundLine, // #BackgroundLine
    _ScenarioLine, // #ScenarioLine
    _ScenarioOutlineLine, // #ScenarioOutlineLine
    _ExamplesLine, // #ExamplesLine
    _StepLine, // #StepLine
    _DocStringSeparator, // #DocStringSeparator
    _TableRow, // #TableRow
    _Language, // #Language
    _Other, // #Other
    GherkinDocument, // GherkinDocument! := Feature?
    Feature, // Feature! := Feature_Header Background? Scenario_Definition*
    Feature_Header, // Feature_Header! := #Language? Tags? #FeatureLine Feature_Description
    Background, // Background! := #BackgroundLine Background_Description Scenario_Step*
    Scenario_Definition, // Scenario_Definition! := Tags? (Scenario | ScenarioOutline)
    Scenario, // Scenario! := #ScenarioLine Scenario_Description Scenario_Step*
    ScenarioOutline, // ScenarioOutline! := #ScenarioOutlineLine ScenarioOutline_Description ScenarioOutline_Step* Examples_Definition*
    Examples_Definition, // Examples_Definition! [#Empty|#Comment|#TagLine-&gt;#ExamplesLine] := Tags? Examples
    Examples, // Examples! := #ExamplesLine Examples_Description Examples_Table?
    Examples_Table, // Examples_Table! := #TableRow #TableRow*
    Scenario_Step, // Scenario_Step := Step
    ScenarioOutline_Step, // ScenarioOutline_Step := Step
    Step, // Step! := #StepLine Step_Arg?
    Step_Arg, // Step_Arg := (DataTable | DocString)
    DataTable, // DataTable! := #TableRow+
    DocString, // DocString! := #DocStringSeparator #Other* #DocStringSeparator
    Tags, // Tags! := #TagLine+
    Feature_Description, // Feature_Description := Description_Helper
    Background_Description, // Background_Description := Description_Helper
    Scenario_Description, // Scenario_Description := Description_Helper
    ScenarioOutline_Description, // ScenarioOutline_Description := Description_Helper
    Examples_Description, // Examples_Description := Description_Helper
    Description_Helper, // Description_Helper := #Empty* Description? #Comment*
    Description, // Description! := #Other+
    ;

    public static RuleType cast(TokenType tokenType) {
        return RuleType.values()[tokenType.ordinal()];
    }
} public enum TokenType {
    None,
    EOF,
    Empty,
    Comment,
    TagLine,
    FeatureLine,
    BackgroundLine,
    ScenarioLine,
    ScenarioOutlineLine,
    ExamplesLine,
    StepLine,
    DocStringSeparator,
    TableRow,
    Language,
    Other,
    ;
} public static String join(String separator, List<String> items) {
    return join(ToString.DEFAULT, separator, items);
}
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import gherkin.ast.Background;
import gherkin.ast.Comment;
import gherkin.ast.DataTable;
import gherkin.ast.DocString;
import gherkin.ast.Examples;
import gherkin.ast.Feature;
import gherkin.ast.GherkinDocument;
import gherkin.ast.Location;
import gherkin.ast.Node;
import gherkin.ast.Scenario;
import gherkin.ast.ScenarioDefinition;
import gherkin.ast.ScenarioOutline;
import gherkin.ast.Step;
import gherkin.ast.TableCell;
import gherkin.ast.TableRow;
import gherkin.ast.Tag;
import static gherkin.Parser.Builder;
import static gherkin.Parser.RuleType;
import static gherkin.Parser.TokenType;
import static gherkin.StringUtils.join;
package gherkin;




public class AstBuilder implements Builder<GherkinDocument> {
    private Deque<AstNode> stack;
    private List<Comment> comments;

    public AstBuilder() {
        reset();
    }

    @Override
    public void reset() {
        stack = new ArrayDeque<>();
        stack.push(new AstNode(RuleType.None));

        comments = new ArrayList<>();
    }

    private AstNode currentNode() {
        return stack.peek();
    }

    @Override
    public void build(Token token) {
        RuleType ruleType = RuleType.cast(token.matchedType);
        if (token.matchedType == TokenType.Comment) {
            comments.add(new Comment(getLocation(token, 0), token.matchedText));
        } else {
            currentNode().add(ruleType, token);
        }
    }

    @Override
    public void startRule(RuleType ruleType) {
        stack.push(new AstNode(ruleType));
    }

    @Override
    public void endRule(RuleType ruleType) {
        AstNode node = stack.pop();
        Object transformedNode = getTransformedNode(node);
        currentNode().add(node.ruleType, transformedNode);
    }

    private Object getTransformedNode(AstNode node) {
        switch (node.ruleType) {
            case Step: {
                Token stepLine = node.getToken(TokenType.StepLine);
                Node stepArg = node.getSingle(RuleType.DataTable, null);
                if (stepArg == null) {
                    stepArg = node.getSingle(RuleType.DocString, null);
                }
                return new Step(getLocation(stepLine, 0), stepLine.matchedKeyword, stepLine.matchedText, stepArg);
            }
            case DocString: {
                Token separatorToken = node.getTokens(TokenType.DocStringSeparator).get(0);
                String contentType = separatorToken.matchedText.length() > 0 ? separatorToken.matchedText : null;
                List<Token> lineTokens = node.getTokens(TokenType.Other);
                StringBuilder content = new StringBuilder();
                boolean newLine = false;
                for (Token lineToken : lineTokens) {
                    if (newLine) content.append("\n");
                    newLine = true;
                    content.append(lineToken.matchedText);
                }
                return new DocString(getLocation(separatorToken, 0), contentType, content.toString());
            }
            case DataTable: {
                List<TableRow> rows = getTableRows(node);
                return new DataTable(rows);
            }
            case Background: {
                Token backgroundLine = node.getToken(TokenType.BackgroundLine);
                String description = getDescription(node);
                List<Step> steps = getSteps(node);
                return new Background(getLocation(backgroundLine, 0), backgroundLine.matchedKeyword, backgroundLine.matchedText, description, steps);
            }
            case Scenario_Definition: {
                List<Tag> tags = getTags(node);
                AstNode scenarioNode = node.getSingle(RuleType.Scenario, null);

                if (scenarioNode != null) {
                    Token scenarioLine = scenarioNode.getToken(TokenType.ScenarioLine);
                    String description = getDescription(scenarioNode);
                    List<Step> steps = getSteps(scenarioNode);

                    return new Scenario(tags, getLocation(scenarioLine, 0), scenarioLine.matchedKeyword, scenarioLine.matchedText, description, steps);
                } else {
                    AstNode scenarioOutlineNode = node.getSingle(RuleType.ScenarioOutline, null);