
org.yaml.snakeyaml.parser.ParserImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.portal.tools.rest.builder
Show all versions of com.liferay.portal.tools.rest.builder
Liferay Portal Tools REST Builder
The newest version!
/**
* Copyright (c) 2008, SnakeYAML
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.yaml.snakeyaml.parser;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.Version;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.comments.CommentType;
import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.events.AliasEvent;
import org.yaml.snakeyaml.events.CommentEvent;
import org.yaml.snakeyaml.events.DocumentEndEvent;
import org.yaml.snakeyaml.events.DocumentStartEvent;
import org.yaml.snakeyaml.events.Event;
import org.yaml.snakeyaml.events.ImplicitTuple;
import org.yaml.snakeyaml.events.MappingEndEvent;
import org.yaml.snakeyaml.events.MappingStartEvent;
import org.yaml.snakeyaml.events.ScalarEvent;
import org.yaml.snakeyaml.events.SequenceEndEvent;
import org.yaml.snakeyaml.events.SequenceStartEvent;
import org.yaml.snakeyaml.events.StreamEndEvent;
import org.yaml.snakeyaml.events.StreamStartEvent;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.reader.StreamReader;
import org.yaml.snakeyaml.scanner.Scanner;
import org.yaml.snakeyaml.scanner.ScannerImpl;
import org.yaml.snakeyaml.tokens.AliasToken;
import org.yaml.snakeyaml.tokens.AnchorToken;
import org.yaml.snakeyaml.tokens.BlockEntryToken;
import org.yaml.snakeyaml.tokens.CommentToken;
import org.yaml.snakeyaml.tokens.DirectiveToken;
import org.yaml.snakeyaml.tokens.ScalarToken;
import org.yaml.snakeyaml.tokens.StreamEndToken;
import org.yaml.snakeyaml.tokens.StreamStartToken;
import org.yaml.snakeyaml.tokens.TagToken;
import org.yaml.snakeyaml.tokens.TagTuple;
import org.yaml.snakeyaml.tokens.Token;
import org.yaml.snakeyaml.util.ArrayStack;
/**
*
* # The following YAML grammar is LL(1) and is parsed by a recursive descent
* parser.
* stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
* implicit_document ::= block_node DOCUMENT-END*
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
* block_node_or_indentless_sequence ::=
* ALIAS
* | properties (block_content | indentless_block_sequence)?
* | block_content
* | indentless_block_sequence
* block_node ::= ALIAS
* | properties block_content?
* | block_content
* flow_node ::= ALIAS
* | properties flow_content?
* | flow_content
* properties ::= TAG ANCHOR? | ANCHOR TAG?
* block_content ::= block_collection | flow_collection | SCALAR
* flow_content ::= flow_collection | SCALAR
* block_collection ::= block_sequence | block_mapping
* flow_collection ::= flow_sequence | flow_mapping
* block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END
* indentless_sequence ::= (BLOCK-ENTRY block_node?)+
* block_mapping ::= BLOCK-MAPPING_START
* ((KEY block_node_or_indentless_sequence?)?
* (VALUE block_node_or_indentless_sequence?)?)*
* BLOCK-END
* flow_sequence ::= FLOW-SEQUENCE-START
* (flow_sequence_entry FLOW-ENTRY)*
* flow_sequence_entry?
* FLOW-SEQUENCE-END
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* flow_mapping ::= FLOW-MAPPING-START
* (flow_mapping_entry FLOW-ENTRY)*
* flow_mapping_entry?
* FLOW-MAPPING-END
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* FIRST sets:
* stream: { STREAM-START }
* explicit_document: { DIRECTIVE DOCUMENT-START }
* implicit_document: FIRST(block_node)
* block_node: { ALIAS TAG ANCHOR SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START }
* flow_node: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START }
* block_content: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
* flow_content: { FLOW-SEQUENCE-START FLOW-MAPPING-START SCALAR }
* block_collection: { BLOCK-SEQUENCE-START BLOCK-MAPPING-START }
* flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
* block_sequence: { BLOCK-SEQUENCE-START }
* block_mapping: { BLOCK-MAPPING-START }
* block_node_or_indentless_sequence: { ALIAS ANCHOR TAG SCALAR BLOCK-SEQUENCE-START BLOCK-MAPPING-START FLOW-SEQUENCE-START FLOW-MAPPING-START BLOCK-ENTRY }
* indentless_sequence: { ENTRY }
* flow_collection: { FLOW-SEQUENCE-START FLOW-MAPPING-START }
* flow_sequence: { FLOW-SEQUENCE-START }
* flow_mapping: { FLOW-MAPPING-START }
* flow_sequence_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
* flow_mapping_entry: { ALIAS ANCHOR TAG SCALAR FLOW-SEQUENCE-START FLOW-MAPPING-START KEY }
*
*
* Since writing a recursive-descendant parser is a straightforward task, we do not give many
* comments here.
*/
public class ParserImpl implements Parser {
private static final Map DEFAULT_TAGS = new HashMap();
static {
DEFAULT_TAGS.put("!", "!");
DEFAULT_TAGS.put("!!", Tag.PREFIX);
}
protected final Scanner scanner;
private Event currentEvent;
private final ArrayStack states;
private final ArrayStack marks;
private Production state;
private VersionTagsTuple directives;
public ParserImpl(StreamReader reader, LoaderOptions options) {
this(new ScannerImpl(reader, options));
}
public ParserImpl(Scanner scanner) {
this.scanner = scanner;
currentEvent = null;
directives = new VersionTagsTuple(null, new HashMap(DEFAULT_TAGS));
states = new ArrayStack(100);
marks = new ArrayStack(10);
state = new ParseStreamStart();
}
/**
* Check the type of the next event.
*/
public boolean checkEvent(Event.ID choice) {
peekEvent();
return currentEvent != null && currentEvent.is(choice);
}
/**
* Peek the next event (keeping it in the stream)
*/
public Event peekEvent() {
if (currentEvent == null && (state != null)) {
currentEvent = state.produce();
}
return currentEvent;
}
/**
* Get the next event and proceed further.
*/
public Event getEvent() {
peekEvent();
Event value = currentEvent;
currentEvent = null;
return value;
}
private CommentEvent produceCommentEvent(CommentToken token) {
Mark startMark = token.getStartMark();
Mark endMark = token.getEndMark();
String value = token.getValue();
CommentType type = token.getCommentType();
// state = state, that no change in state
return new CommentEvent(type, value, startMark, endMark);
}
/**
*
* stream ::= STREAM-START implicit_document? explicit_document* STREAM-END
* implicit_document ::= block_node DOCUMENT-END*
* explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END*
*
*/
private class ParseStreamStart implements Production {
public Event produce() {
// Parse the stream start.
StreamStartToken token = (StreamStartToken) scanner.getToken();
Event event = new StreamStartEvent(token.getStartMark(), token.getEndMark());
// Prepare the next state.
state = new ParseImplicitDocumentStart();
return event;
}
}
private class ParseImplicitDocumentStart implements Production {
public Event produce() {
// Parse an implicit document.
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseImplicitDocumentStart();
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (!scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart, Token.ID.StreamEnd)) {
Token token = scanner.peekToken();
Mark startMark = token.getStartMark();
Mark endMark = startMark;
Event event = new DocumentStartEvent(startMark, endMark, false, null, null);
// Prepare the next state.
states.push(new ParseDocumentEnd());
state = new ParseBlockNode();
return event;
}
return new ParseDocumentStart().produce();
}
}
private class ParseDocumentStart implements Production {
public Event produce() {
// Parse any extra document end indicators.
while (scanner.checkToken(Token.ID.DocumentEnd)) {
scanner.getToken();
}
// Parse an explicit document.
Event event;
if (!scanner.checkToken(Token.ID.StreamEnd)) {
scanner.resetDocumentIndex();
Token token = scanner.peekToken();
Mark startMark = token.getStartMark();
VersionTagsTuple tuple = processDirectives();
while (scanner.checkToken(Token.ID.Comment)) {
// the comments in the directive are ignored because they are not part of the Node tree
scanner.getToken();
}
if (!scanner.checkToken(Token.ID.StreamEnd)) {
if (!scanner.checkToken(Token.ID.DocumentStart)) {
throw new ParserException(null, null,
"expected '', but found '" + scanner.peekToken().getTokenId() + "'",
scanner.peekToken().getStartMark());
}
token = scanner.getToken();
Mark endMark = token.getEndMark();
event =
new DocumentStartEvent(startMark, endMark, true, tuple.getVersion(), tuple.getTags());
states.push(new ParseDocumentEnd());
state = new ParseDocumentContent();
return event;
}
}
// Parse the end of the stream.
StreamEndToken token = (StreamEndToken) scanner.getToken();
event = new StreamEndEvent(token.getStartMark(), token.getEndMark());
if (!states.isEmpty()) {
throw new YAMLException("Unexpected end of stream. States left: " + states);
}
if (!marks.isEmpty()) {
throw new YAMLException("Unexpected end of stream. Marks left: " + marks);
}
state = null;
return event;
}
}
private class ParseDocumentEnd implements Production {
public Event produce() {
// Parse the document end.
Token token = scanner.peekToken();
Mark startMark = token.getStartMark();
Mark endMark = startMark;
boolean explicit = false;
if (scanner.checkToken(Token.ID.DocumentEnd)) {
token = scanner.getToken();
endMark = token.getEndMark();
explicit = true;
}
Event event = new DocumentEndEvent(startMark, endMark, explicit);
// Prepare the next state.
state = new ParseDocumentStart();
return event;
}
}
private class ParseDocumentContent implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseDocumentContent();
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (scanner.checkToken(Token.ID.Directive, Token.ID.DocumentStart, Token.ID.DocumentEnd,
Token.ID.StreamEnd)) {
Event event = processEmptyScalar(scanner.peekToken().getStartMark());
state = states.pop();
return event;
}
return new ParseBlockNode().produce();
}
}
/**
* https://yaml.org/spec/1.1/#id898785 says "If the document specifies no directives, it is parsed
* using the same settings as the previous document. If the document does specify any directives,
* all directives of previous documents, if any, are ignored." TODO the last statement is not
* respected (as in PyYAML, to work the same)
*
* @return directives to be applied for the current document
*/
@SuppressWarnings("unchecked")
private VersionTagsTuple processDirectives() {
HashMap tagHandles = new HashMap(directives.getTags());
for (String key : DEFAULT_TAGS.keySet()) {
tagHandles.remove(key);
}
// keep only added tag handlers
directives = new VersionTagsTuple(null, tagHandles);
while (scanner.checkToken(Token.ID.Directive)) {
@SuppressWarnings("rawtypes")
DirectiveToken token = (DirectiveToken) scanner.getToken();
if (token.getName().equals("YAML")) {
if (directives.getVersion() != null) {
throw new ParserException(null, null, "found duplicate YAML directive",
token.getStartMark());
}
List value = (List) token.getValue();
Integer major = value.get(0);
if (major != 1) {
throw new ParserException(null, null,
"found incompatible YAML document (version 1.* is required)", token.getStartMark());
}
Integer minor = value.get(1);
if (minor == 0) {
directives = new VersionTagsTuple(Version.V1_0, tagHandles);
} else {
directives = new VersionTagsTuple(Version.V1_1, tagHandles);
}
} else if (token.getName().equals("TAG")) {
List value = (List) token.getValue();
String handle = value.get(0);
String prefix = value.get(1);
if (tagHandles.containsKey(handle)) {
throw new ParserException(null, null, "duplicate tag handle " + handle,
token.getStartMark());
}
tagHandles.put(handle, prefix);
}
}
HashMap detectedTagHandles = new HashMap<>();
if (!tagHandles.isEmpty()) {
// copy from tagHandles
detectedTagHandles = new HashMap<>(tagHandles);
}
// add default tag handlers to resolve tags
for (String key : DEFAULT_TAGS.keySet()) {
// do not overwrite re-defined tags
if (!tagHandles.containsKey(key)) {
tagHandles.put(key, DEFAULT_TAGS.get(key));
}
}
// data for the events (no default tags added)
return new VersionTagsTuple(directives.getVersion(), detectedTagHandles);
}
/**
*
* block_node_or_indentless_sequence ::= ALIAS
* | properties (block_content | indentless_block_sequence)?
* | block_content
* | indentless_block_sequence
* block_node ::= ALIAS
* | properties block_content?
* | block_content
* flow_node ::= ALIAS
* | properties flow_content?
* | flow_content
* properties ::= TAG ANCHOR? | ANCHOR TAG?
* block_content ::= block_collection | flow_collection | SCALAR
* flow_content ::= flow_collection | SCALAR
* block_collection ::= block_sequence | block_mapping
* flow_collection ::= flow_sequence | flow_mapping
*
*/
private class ParseBlockNode implements Production {
public Event produce() {
return parseNode(true, false);
}
}
private Event parseFlowNode() {
return parseNode(false, false);
}
private Event parseBlockNodeOrIndentlessSequence() {
return parseNode(true, true);
}
private Event parseNode(boolean block, boolean indentlessSequence) {
Event event;
Mark startMark = null;
Mark endMark = null;
Mark tagMark = null;
if (scanner.checkToken(Token.ID.Alias)) {
AliasToken token = (AliasToken) scanner.getToken();
event = new AliasEvent(token.getValue(), token.getStartMark(), token.getEndMark());
state = states.pop();
} else {
String anchor = null;
TagTuple tagTokenTag = null;
if (scanner.checkToken(Token.ID.Anchor)) {
AnchorToken token = (AnchorToken) scanner.getToken();
startMark = token.getStartMark();
endMark = token.getEndMark();
anchor = token.getValue();
if (scanner.checkToken(Token.ID.Tag)) {
TagToken tagToken = (TagToken) scanner.getToken();
tagMark = tagToken.getStartMark();
endMark = tagToken.getEndMark();
tagTokenTag = tagToken.getValue();
}
} else if (scanner.checkToken(Token.ID.Tag)) {
TagToken tagToken = (TagToken) scanner.getToken();
startMark = tagToken.getStartMark();
tagMark = startMark;
endMark = tagToken.getEndMark();
tagTokenTag = tagToken.getValue();
if (scanner.checkToken(Token.ID.Anchor)) {
AnchorToken token = (AnchorToken) scanner.getToken();
endMark = token.getEndMark();
anchor = token.getValue();
}
}
String tag = null;
if (tagTokenTag != null) {
String handle = tagTokenTag.getHandle();
String suffix = tagTokenTag.getSuffix();
if (handle != null) {
if (!directives.getTags().containsKey(handle)) {
throw new ParserException("while parsing a node", startMark,
"found undefined tag handle " + handle, tagMark);
}
tag = directives.getTags().get(handle) + suffix;
} else {
tag = suffix;
}
}
if (startMark == null) {
startMark = scanner.peekToken().getStartMark();
endMark = startMark;
}
event = null;
boolean implicit = tag == null || tag.equals("!");
if (indentlessSequence && scanner.checkToken(Token.ID.BlockEntry)) {
endMark = scanner.peekToken().getEndMark();
event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.BLOCK);
state = new ParseIndentlessSequenceEntryKey();
} else {
if (scanner.checkToken(Token.ID.Scalar)) {
ScalarToken token = (ScalarToken) scanner.getToken();
endMark = token.getEndMark();
ImplicitTuple implicitValues;
if ((token.getPlain() && tag == null) || "!".equals(tag)) {
implicitValues = new ImplicitTuple(true, false);
} else if (tag == null) {
implicitValues = new ImplicitTuple(false, true);
} else {
implicitValues = new ImplicitTuple(false, false);
}
event = new ScalarEvent(anchor, tag, implicitValues, token.getValue(), startMark, endMark,
token.getStyle());
state = states.pop();
} else if (scanner.checkToken(Token.ID.FlowSequenceStart)) {
endMark = scanner.peekToken().getEndMark();
event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.FLOW);
state = new ParseFlowSequenceFirstEntry();
} else if (scanner.checkToken(Token.ID.FlowMappingStart)) {
endMark = scanner.peekToken().getEndMark();
event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.FLOW);
state = new ParseFlowMappingFirstKey();
} else if (block && scanner.checkToken(Token.ID.BlockSequenceStart)) {
endMark = scanner.peekToken().getStartMark();
event = new SequenceStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.BLOCK);
state = new ParseBlockSequenceFirstEntry();
} else if (block && scanner.checkToken(Token.ID.BlockMappingStart)) {
endMark = scanner.peekToken().getStartMark();
event = new MappingStartEvent(anchor, tag, implicit, startMark, endMark,
DumperOptions.FlowStyle.BLOCK);
state = new ParseBlockMappingFirstKey();
} else if (anchor != null || tag != null) {
// Empty scalars are allowed even if a tag or an anchor is
// specified.
event = new ScalarEvent(anchor, tag, new ImplicitTuple(implicit, false), "", startMark,
endMark, DumperOptions.ScalarStyle.PLAIN);
state = states.pop();
} else {
Token token = scanner.peekToken();
throw new ParserException("while parsing a " + (block ? "block" : "flow") + " node",
startMark, "expected the node content, but found '" + token.getTokenId() + "'",
token.getStartMark());
}
}
}
return event;
}
// block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)*
// BLOCK-END
private class ParseBlockSequenceFirstEntry implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseBlockSequenceEntryKey().produce();
}
}
private class ParseBlockSequenceEntryKey implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseBlockSequenceEntryKey();
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (scanner.checkToken(Token.ID.BlockEntry)) {
BlockEntryToken token = (BlockEntryToken) scanner.getToken();
return new ParseBlockSequenceEntryValue(token).produce();
}
if (!scanner.checkToken(Token.ID.BlockEnd)) {
Token token = scanner.peekToken();
throw new ParserException("while parsing a block collection", marks.pop(),
"expected , but found '" + token.getTokenId() + "'", token.getStartMark());
}
Token token = scanner.getToken();
Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
marks.pop();
return event;
}
}
private class ParseBlockSequenceEntryValue implements Production {
BlockEntryToken token;
public ParseBlockSequenceEntryValue(final BlockEntryToken token) {
this.token = token;
}
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseBlockSequenceEntryValue(token);
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.BlockEnd)) {
states.push(new ParseBlockSequenceEntryKey());
return new ParseBlockNode().produce();
} else {
state = new ParseBlockSequenceEntryKey();
return processEmptyScalar(token.getEndMark());
}
}
}
// indentless_sequence ::= (BLOCK-ENTRY block_node?)+
private class ParseIndentlessSequenceEntryKey implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseIndentlessSequenceEntryKey();
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (scanner.checkToken(Token.ID.BlockEntry)) {
BlockEntryToken token = (BlockEntryToken) scanner.getToken();
return new ParseIndentlessSequenceEntryValue(token).produce();
}
Token token = scanner.peekToken();
Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
return event;
}
}
private class ParseIndentlessSequenceEntryValue implements Production {
BlockEntryToken token;
public ParseIndentlessSequenceEntryValue(final BlockEntryToken token) {
this.token = token;
}
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseIndentlessSequenceEntryValue(token);
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (!scanner.checkToken(Token.ID.BlockEntry, Token.ID.Key, Token.ID.Value,
Token.ID.BlockEnd)) {
states.push(new ParseIndentlessSequenceEntryKey());
return new ParseBlockNode().produce();
} else {
state = new ParseIndentlessSequenceEntryKey();
return processEmptyScalar(token.getEndMark());
}
}
}
private class ParseBlockMappingFirstKey implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseBlockMappingKey().produce();
}
}
private class ParseBlockMappingKey implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseBlockMappingKey();
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (scanner.checkToken(Token.ID.Key)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
states.push(new ParseBlockMappingValue());
return parseBlockNodeOrIndentlessSequence();
} else {
state = new ParseBlockMappingValue();
return processEmptyScalar(token.getEndMark());
}
}
if (!scanner.checkToken(Token.ID.BlockEnd)) {
Token token = scanner.peekToken();
throw new ParserException("while parsing a block mapping", marks.pop(),
"expected , but found '" + token.getTokenId() + "'", token.getStartMark());
}
Token token = scanner.getToken();
Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
state = states.pop();
marks.pop();
return event;
}
}
private class ParseBlockMappingValue implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Value)) {
Token token = scanner.getToken();
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseBlockMappingValueComment();
return state.produce();
} else if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
states.push(new ParseBlockMappingKey());
return parseBlockNodeOrIndentlessSequence();
} else {
state = new ParseBlockMappingKey();
return processEmptyScalar(token.getEndMark());
}
} else if (scanner.checkToken(Token.ID.Scalar)) {
states.push(new ParseBlockMappingKey());
return parseBlockNodeOrIndentlessSequence();
}
state = new ParseBlockMappingKey();
Token token = scanner.peekToken();
return processEmptyScalar(token.getStartMark());
}
}
private class ParseBlockMappingValueComment implements Production {
List tokens = new LinkedList<>();
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
tokens.add((CommentToken) scanner.getToken());
return produce();
} else if (!scanner.checkToken(Token.ID.Key, Token.ID.Value, Token.ID.BlockEnd)) {
if (!tokens.isEmpty()) {
return produceCommentEvent(tokens.remove(0));
}
states.push(new ParseBlockMappingKey());
return parseBlockNodeOrIndentlessSequence();
} else {
state = new ParseBlockMappingValueCommentList(tokens);
return processEmptyScalar(scanner.peekToken().getStartMark());
}
}
}
private class ParseBlockMappingValueCommentList implements Production {
List tokens;
public ParseBlockMappingValueCommentList(final List tokens) {
this.tokens = tokens;
}
public Event produce() {
if (!tokens.isEmpty()) {
return produceCommentEvent(tokens.remove(0));
}
return new ParseBlockMappingKey().produce();
}
}
/**
*
* flow_sequence ::= FLOW-SEQUENCE-START
* (flow_sequence_entry FLOW-ENTRY)*
* flow_sequence_entry?
* FLOW-SEQUENCE-END
* flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
* Note that while production rules for both flow_sequence_entry and
* flow_mapping_entry are equal, their interpretations are different.
* For `flow_sequence_entry`, the part `KEY flow_node? (VALUE flow_node?)?`
* generate an inline mapping (set syntax).
*
*/
private class ParseFlowSequenceFirstEntry implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseFlowSequenceEntry(true).produce();
}
}
private class ParseFlowSequenceEntry implements Production {
private final boolean first;
public ParseFlowSequenceEntry(boolean first) {
this.first = first;
}
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseFlowSequenceEntry(first);
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
if (!first) {
if (scanner.checkToken(Token.ID.FlowEntry)) {
scanner.getToken();
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseFlowSequenceEntry(true);
return produceCommentEvent((CommentToken) scanner.getToken());
}
} else {
Token token = scanner.peekToken();
throw new ParserException("while parsing a flow sequence", marks.pop(),
"expected ',' or ']', but got " + token.getTokenId(), token.getStartMark());
}
}
if (scanner.checkToken(Token.ID.Key)) {
Token token = scanner.peekToken();
Event event = new MappingStartEvent(null, null, true, token.getStartMark(),
token.getEndMark(), DumperOptions.FlowStyle.FLOW);
state = new ParseFlowSequenceEntryMappingKey();
return event;
} else if (!scanner.checkToken(Token.ID.FlowSequenceEnd)) {
states.push(new ParseFlowSequenceEntry(false));
return parseFlowNode();
}
}
Token token = scanner.getToken();
Event event = new SequenceEndEvent(token.getStartMark(), token.getEndMark());
if (!scanner.checkToken(Token.ID.Comment)) {
state = states.pop();
} else {
state = new ParseFlowEndComment();
}
marks.pop();
return event;
}
}
private class ParseFlowEndComment implements Production {
public Event produce() {
Event event = produceCommentEvent((CommentToken) scanner.getToken());
if (!scanner.checkToken(Token.ID.Comment)) {
state = states.pop();
}
return event;
}
}
private class ParseFlowSequenceEntryMappingKey implements Production {
public Event produce() {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
states.push(new ParseFlowSequenceEntryMappingValue());
return parseFlowNode();
} else {
state = new ParseFlowSequenceEntryMappingValue();
return processEmptyScalar(token.getEndMark());
}
}
}
private class ParseFlowSequenceEntryMappingValue implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Value)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowSequenceEnd)) {
states.push(new ParseFlowSequenceEntryMappingEnd());
return parseFlowNode();
} else {
state = new ParseFlowSequenceEntryMappingEnd();
return processEmptyScalar(token.getEndMark());
}
} else {
state = new ParseFlowSequenceEntryMappingEnd();
Token token = scanner.peekToken();
return processEmptyScalar(token.getStartMark());
}
}
}
private class ParseFlowSequenceEntryMappingEnd implements Production {
public Event produce() {
state = new ParseFlowSequenceEntry(false);
Token token = scanner.peekToken();
return new MappingEndEvent(token.getStartMark(), token.getEndMark());
}
}
/**
*
* flow_mapping ::= FLOW-MAPPING-START
* (flow_mapping_entry FLOW-ENTRY)*
* flow_mapping_entry?
* FLOW-MAPPING-END
* flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)?
*
*/
private class ParseFlowMappingFirstKey implements Production {
public Event produce() {
Token token = scanner.getToken();
marks.push(token.getStartMark());
return new ParseFlowMappingKey(true).produce();
}
}
private class ParseFlowMappingKey implements Production {
private final boolean first;
public ParseFlowMappingKey(boolean first) {
this.first = first;
}
public Event produce() {
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseFlowMappingKey(first);
return produceCommentEvent((CommentToken) scanner.getToken());
}
if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
if (!first) {
if (scanner.checkToken(Token.ID.FlowEntry)) {
scanner.getToken();
if (scanner.checkToken(Token.ID.Comment)) {
state = new ParseFlowMappingKey(true);
return produceCommentEvent((CommentToken) scanner.getToken());
}
} else {
Token token = scanner.peekToken();
throw new ParserException("while parsing a flow mapping", marks.pop(),
"expected ',' or '}', but got " + token.getTokenId(), token.getStartMark());
}
}
if (scanner.checkToken(Token.ID.Key)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.Value, Token.ID.FlowEntry, Token.ID.FlowMappingEnd)) {
states.push(new ParseFlowMappingValue());
return parseFlowNode();
} else {
state = new ParseFlowMappingValue();
return processEmptyScalar(token.getEndMark());
}
} else if (!scanner.checkToken(Token.ID.FlowMappingEnd)) {
states.push(new ParseFlowMappingEmptyValue());
return parseFlowNode();
}
}
Token token = scanner.getToken();
Event event = new MappingEndEvent(token.getStartMark(), token.getEndMark());
marks.pop();
if (!scanner.checkToken(Token.ID.Comment)) {
state = states.pop();
} else {
state = new ParseFlowEndComment();
}
return event;
}
}
private class ParseFlowMappingValue implements Production {
public Event produce() {
if (scanner.checkToken(Token.ID.Value)) {
Token token = scanner.getToken();
if (!scanner.checkToken(Token.ID.FlowEntry, Token.ID.FlowMappingEnd)) {
states.push(new ParseFlowMappingKey(false));
return parseFlowNode();
} else {
state = new ParseFlowMappingKey(false);
return processEmptyScalar(token.getEndMark());
}
} else {
state = new ParseFlowMappingKey(false);
Token token = scanner.peekToken();
return processEmptyScalar(token.getStartMark());
}
}
}
private class ParseFlowMappingEmptyValue implements Production {
public Event produce() {
state = new ParseFlowMappingKey(false);
return processEmptyScalar(scanner.peekToken().getStartMark());
}
}
/**
*
* block_mapping ::= BLOCK-MAPPING_START
* ((KEY block_node_or_indentless_sequence?)?
* (VALUE block_node_or_indentless_sequence?)?)*
* BLOCK-END
*
*/
private Event processEmptyScalar(Mark mark) {
return new ScalarEvent(null, null, new ImplicitTuple(true, false), "", mark, mark,
DumperOptions.ScalarStyle.PLAIN);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy