/* * See LICENSE file in distribution for copyright and licensing information. */ package org.pyyaml; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.yaml.snakeyaml.events.AliasEvent; import org.yaml.snakeyaml.events.DocumentEndEvent; import org.yaml.snakeyaml.events.DocumentStartEvent; import org.yaml.snakeyaml.events.Event; 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.parser.Parser; import org.yaml.snakeyaml.tokens.AliasToken; import org.yaml.snakeyaml.tokens.AnchorToken; import org.yaml.snakeyaml.tokens.DirectiveToken; import org.yaml.snakeyaml.tokens.DocumentStartToken; import org.yaml.snakeyaml.tokens.FlowEntryToken; import org.yaml.snakeyaml.tokens.FlowMappingEndToken; import org.yaml.snakeyaml.tokens.FlowMappingStartToken; import org.yaml.snakeyaml.tokens.FlowSequenceEndToken; import org.yaml.snakeyaml.tokens.FlowSequenceStartToken; import org.yaml.snakeyaml.tokens.KeyToken; 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.Token; import org.yaml.snakeyaml.tokens.ValueToken; public class CanonicalParser implements Parser { private LinkedList events; private boolean parsed; private CanonicalScanner scanner; public CanonicalParser(String data) { events = new LinkedList(); parsed = false; scanner = new CanonicalScanner(data); } // stream: STREAM-START document* STREAM-END private void parseStream() { scanner.getToken(StreamStartToken.class); events.add(new StreamStartEvent(null, null)); while (!scanner.checkToken(StreamEndToken.class)) { List> list = new ArrayList>(); list.add(DirectiveToken.class); list.add(DocumentStartToken.class); if (scanner.checkToken(list)) { parseDocument(); } else { throw new CanonicalException("document is expected, got " + scanner.tokens.get(0)); } } scanner.getToken(StreamEndToken.class); events.add(new StreamEndEvent(null, null)); } // document: DIRECTIVE? DOCUMENT-START node private void parseDocument() { if (scanner.checkToken(DirectiveToken.class)) { scanner.getToken(DirectiveToken.class); } scanner.getToken(DocumentStartToken.class); events.add(new DocumentStartEvent(null, null, true, new Integer[] { 1, 1 }, null)); parseNode(); events.add(new DocumentEndEvent(null, null, true)); } // node: ALIAS | ANCHOR? TAG? (SCALAR|sequence|mapping) private void parseNode() { if (scanner.checkToken(AliasToken.class)) { AliasToken token = (AliasToken) scanner.getToken(); events.add(new AliasEvent(token.getValue(), null, null)); } else { String anchor = null; if (scanner.checkToken(AnchorToken.class)) { AnchorToken token = (AnchorToken) scanner.getToken(); anchor = token.getValue(); } String tag = null; if (scanner.checkToken(TagToken.class)) { TagToken token = (TagToken) scanner.getToken(); tag = token.getValue()[0] + token.getValue()[1]; } if (scanner.checkToken(ScalarToken.class)) { ScalarToken token = (ScalarToken) scanner.getToken(); events.add(new ScalarEvent(anchor, tag, new boolean[] { false, false }, token .getValue(), null, null, null)); } else if (scanner.checkToken(FlowSequenceStartToken.class)) { events.add(new SequenceStartEvent(anchor, tag, false, null, null, null)); parseSequence(); } else if (scanner.checkToken(FlowMappingStartToken.class)) { events.add(new MappingStartEvent(anchor, tag, false, null, null, null)); parseMapping(); } else { throw new CanonicalException("SCALAR, '[', or '{' is expected, got " + scanner.tokens.get(0)); } } } // sequence: SEQUENCE-START (node (ENTRY node)*)? ENTRY? SEQUENCE-END private void parseSequence() { scanner.getToken(FlowSequenceStartToken.class); if (!scanner.checkToken(FlowSequenceEndToken.class)) { parseNode(); while (!scanner.checkToken(FlowSequenceEndToken.class)) { scanner.getToken(FlowEntryToken.class); if (!scanner.checkToken(FlowSequenceEndToken.class)) { parseNode(); } } } scanner.getToken(FlowSequenceEndToken.class); events.add(new SequenceEndEvent(null, null)); } // mapping: MAPPING-START (map_entry (ENTRY map_entry)*)? ENTRY? MAPPING-END private void parseMapping() { scanner.getToken(FlowMappingStartToken.class); if (!scanner.checkToken(FlowMappingEndToken.class)) { parseMapEntry(); while (!scanner.checkToken(FlowMappingEndToken.class)) { scanner.getToken(FlowEntryToken.class); if (!scanner.checkToken(FlowMappingEndToken.class)) { parseMapEntry(); } } } scanner.getToken(FlowMappingEndToken.class); events.add(new MappingEndEvent(null, null)); } // map_entry: KEY node VALUE node private void parseMapEntry() { scanner.getToken(KeyToken.class); parseNode(); scanner.getToken(ValueToken.class); parseNode(); } public void parse() { parseStream(); parsed = true; } public Event getEvent() { if (!parsed) { parse(); } return events.removeFirst(); } public boolean checkEvent(List> choices) { if (!parsed) { parse(); } if (!events.isEmpty()) { if (choices.isEmpty()) { return true; } for (Class class1 : choices) { if (class1.isInstance(events.peek())) { return true; } } } return false; } public boolean checkEvent(Class choice) { List> list = new ArrayList>(1); list.add(choice); return checkEvent(list); } public Event peekEvent() { if (!parsed) { parse(); } if (events.isEmpty()) { return null; } else { return events.get(0); } } }