001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2007 Ola Bini <ola@ologix.com>
015: *
016: * Alternatively, the contents of this file may be used under the terms of
017: * either of the GNU General Public License Version 2 or later (the "GPL"),
018: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
019: * in which case the provisions of the GPL or the LGPL are applicable instead
020: * of those above. If you wish to allow use of your version of this file only
021: * under the terms of either the GPL or the LGPL, and not to allow others to
022: * use your version of this file under the terms of the CPL, indicate your
023: * decision by deleting the provisions above and replace them with the notice
024: * and other provisions required by the GPL or the LGPL. If you do not delete
025: * the provisions above, a recipient may use your version of this file under
026: * the terms of any one of the CPL, the GPL or the LGPL.
027: ***** END LICENSE BLOCK *****/package org.jvyamlb;
028:
029: import java.io.InputStream;
030: import java.io.FileInputStream;
031:
032: import java.util.HashMap;
033: import java.util.Iterator;
034: import java.util.LinkedList;
035: import java.util.List;
036: import java.util.Map;
037: import java.util.regex.Pattern;
038:
039: import org.jvyamlb.events.*;
040: import org.jvyamlb.tokens.*;
041:
042: import org.jruby.util.ByteList;
043:
044: /**
045: * @author <a href="mailto:ola.bini@ki.se">Ola Bini</a>
046: */
047: public class ParserImpl implements Parser {
048: // Memnonics for the production table
049: private final static int P_STREAM = 0;
050: private final static int P_STREAM_START = 1; // TERMINAL
051: private final static int P_STREAM_END = 2; // TERMINAL
052: private final static int P_IMPLICIT_DOCUMENT = 3;
053: private final static int P_EXPLICIT_DOCUMENT = 4;
054: private final static int P_DOCUMENT_START = 5;
055: private final static int P_DOCUMENT_START_IMPLICIT = 6;
056: private final static int P_DOCUMENT_END = 7;
057: private final static int P_BLOCK_NODE = 8;
058: private final static int P_BLOCK_CONTENT = 9;
059: private final static int P_PROPERTIES = 10;
060: private final static int P_PROPERTIES_END = 11;
061: private final static int P_FLOW_CONTENT = 12;
062: private final static int P_BLOCK_SEQUENCE = 13;
063: private final static int P_BLOCK_MAPPING = 14;
064: private final static int P_FLOW_SEQUENCE = 15;
065: private final static int P_FLOW_MAPPING = 16;
066: private final static int P_SCALAR = 17;
067: private final static int P_BLOCK_SEQUENCE_ENTRY = 18;
068: private final static int P_BLOCK_MAPPING_ENTRY = 19;
069: private final static int P_BLOCK_MAPPING_ENTRY_VALUE = 20;
070: private final static int P_BLOCK_NODE_OR_INDENTLESS_SEQUENCE = 21;
071: private final static int P_BLOCK_SEQUENCE_START = 22;
072: private final static int P_BLOCK_SEQUENCE_END = 23;
073: private final static int P_BLOCK_MAPPING_START = 24;
074: private final static int P_BLOCK_MAPPING_END = 25;
075: private final static int P_INDENTLESS_BLOCK_SEQUENCE = 26;
076: private final static int P_BLOCK_INDENTLESS_SEQUENCE_START = 27;
077: private final static int P_INDENTLESS_BLOCK_SEQUENCE_ENTRY = 28;
078: private final static int P_BLOCK_INDENTLESS_SEQUENCE_END = 29;
079: private final static int P_FLOW_SEQUENCE_START = 30;
080: private final static int P_FLOW_SEQUENCE_ENTRY = 31;
081: private final static int P_FLOW_SEQUENCE_END = 32;
082: private final static int P_FLOW_MAPPING_START = 33;
083: private final static int P_FLOW_MAPPING_ENTRY = 34;
084: private final static int P_FLOW_MAPPING_END = 35;
085: private final static int P_FLOW_INTERNAL_MAPPING_START = 36;
086: private final static int P_FLOW_INTERNAL_CONTENT = 37;
087: private final static int P_FLOW_INTERNAL_VALUE = 38;
088: private final static int P_FLOW_INTERNAL_MAPPING_END = 39;
089: private final static int P_FLOW_ENTRY_MARKER = 40;
090: private final static int P_FLOW_NODE = 41;
091: private final static int P_FLOW_MAPPING_INTERNAL_CONTENT = 42;
092: private final static int P_FLOW_MAPPING_INTERNAL_VALUE = 43;
093: private final static int P_ALIAS = 44;
094: private final static int P_EMPTY_SCALAR = 45;
095:
096: private final static Event DOCUMENT_END_TRUE = new DocumentEndEvent(
097: true);
098: private final static Event DOCUMENT_END_FALSE = new DocumentEndEvent(
099: false);
100: private final static Event MAPPING_END = new MappingEndEvent();
101: private final static Event SEQUENCE_END = new SequenceEndEvent();
102: private final static Event STREAM_END = new StreamEndEvent();
103: private final static Event STREAM_START = new StreamStartEvent();
104:
105: private static class ProductionEnvironment {
106: private List tags;
107: private List anchors;
108: private Map tagHandles;
109: private int[] yamlVersion;
110: private int[] defaultYamlVersion;
111:
112: public ProductionEnvironment(final YAMLConfig cfg) {
113: this .tags = new LinkedList();
114: this .anchors = new LinkedList();
115: this .tagHandles = new HashMap();
116: this .yamlVersion = null;
117: this .defaultYamlVersion = new int[2];
118: this .defaultYamlVersion[0] = Integer.parseInt(cfg.version()
119: .substring(0, cfg.version().indexOf('.')));
120: this .defaultYamlVersion[1] = Integer.parseInt(cfg.version()
121: .substring(cfg.version().indexOf('.') + 1));
122: }
123:
124: public List getTags() {
125: return this .tags;
126: }
127:
128: public List getAnchors() {
129: return this .anchors;
130: }
131:
132: public Map getTagHandles() {
133: return this .tagHandles;
134: }
135:
136: public int[] getYamlVersion() {
137: return this .yamlVersion;
138: }
139:
140: public int[] getFinalYamlVersion() {
141: if (null == this .yamlVersion) {
142: return this .defaultYamlVersion;
143: }
144: return this .yamlVersion;
145: }
146:
147: public void setYamlVersion(final int[] yamlVersion) {
148: this .yamlVersion = yamlVersion;
149: }
150:
151: public Event produce(final int current,
152: final IntStack parseStack, final Scanner scanner) {
153: switch (current) {
154: case P_STREAM: {
155: parseStack.push(P_STREAM_END);
156: parseStack.push(P_EXPLICIT_DOCUMENT);
157: parseStack.push(P_IMPLICIT_DOCUMENT);
158: parseStack.push(P_STREAM_START);
159: return null;
160: }
161: case P_STREAM_START: {
162: scanner.getToken();
163: return STREAM_START;
164: }
165: case P_STREAM_END: {
166: scanner.getToken();
167: return STREAM_END;
168: }
169: case P_IMPLICIT_DOCUMENT: {
170: final Token curr = scanner.peekToken();
171: if (!(curr instanceof DirectiveToken
172: || curr instanceof DocumentStartToken || curr instanceof StreamEndToken)) {
173: parseStack.push(P_DOCUMENT_END);
174: parseStack.push(P_BLOCK_NODE);
175: parseStack.push(P_DOCUMENT_START_IMPLICIT);
176: }
177: return null;
178: }
179: case P_EXPLICIT_DOCUMENT: {
180: if (!(scanner.peekToken() instanceof StreamEndToken)) {
181: parseStack.push(P_EXPLICIT_DOCUMENT);
182: parseStack.push(P_DOCUMENT_END);
183: parseStack.push(P_BLOCK_NODE);
184: parseStack.push(P_DOCUMENT_START);
185: }
186: return null;
187: }
188: case P_DOCUMENT_START: {
189: Token tok = scanner.peekToken();
190: final Object[] directives = processDirectives(this ,
191: scanner);
192: if (!(scanner.peekToken() instanceof DocumentStartToken)) {
193: throw new ParserException(null,
194: "expected '<document start>', but found "
195: + tok.getClass().getName(), null);
196: }
197: scanner.getToken();
198: return new DocumentStartEvent(true,
199: (int[]) directives[0], (Map) directives[1]);
200: }
201: case P_DOCUMENT_START_IMPLICIT: {
202: final Object[] directives = processDirectives(this ,
203: scanner);
204: return new DocumentStartEvent(false,
205: (int[]) directives[0], (Map) directives[1]);
206: }
207: case P_DOCUMENT_END: {
208: Token tok = scanner.peekToken();
209: boolean explicit = false;
210: while (scanner.peekToken() instanceof DocumentEndToken) {
211: scanner.getToken();
212: explicit = true;
213: }
214: return explicit ? DOCUMENT_END_TRUE
215: : DOCUMENT_END_FALSE;
216: }
217: case P_BLOCK_NODE: {
218: final Token curr = scanner.peekToken();
219: if (curr instanceof DirectiveToken
220: || curr instanceof DocumentStartToken
221: || curr instanceof DocumentEndToken
222: || curr instanceof StreamEndToken) {
223: parseStack.push(P_EMPTY_SCALAR);
224: } else {
225: if (curr instanceof AliasToken) {
226: parseStack.push(P_ALIAS);
227: } else {
228: parseStack.push(P_PROPERTIES_END);
229: parseStack.push(P_BLOCK_CONTENT);
230: parseStack.push(P_PROPERTIES);
231: }
232: }
233: return null;
234: }
235: case P_BLOCK_CONTENT: {
236: final Token tok = scanner.peekToken();
237: if (tok instanceof BlockSequenceStartToken) {
238: parseStack.push(P_BLOCK_SEQUENCE);
239: } else if (tok instanceof BlockMappingStartToken) {
240: parseStack.push(P_BLOCK_MAPPING);
241: } else if (tok instanceof FlowSequenceStartToken) {
242: parseStack.push(P_FLOW_SEQUENCE);
243: } else if (tok instanceof FlowMappingStartToken) {
244: parseStack.push(P_FLOW_MAPPING);
245: } else if (tok instanceof ScalarToken) {
246: parseStack.push(P_SCALAR);
247: } else {
248: // Part of solution for JRUBY-718
249: boolean[] implicit = new boolean[] { false, false };
250: return new ScalarEvent((String) this .getAnchors()
251: .get(0), (String) this .getTags().get(0),
252: implicit, new ByteList(new byte[0], false),
253: '\'');
254: }
255: return null;
256: }
257: case P_PROPERTIES: {
258: String anchor = null;
259: Object tag = null;
260: if (scanner.peekToken() instanceof AnchorToken) {
261: anchor = ((AnchorToken) scanner.getToken())
262: .getValue();
263: if (scanner.peekToken() instanceof TagToken) {
264: tag = ((TagToken) scanner.getToken())
265: .getValue();
266: }
267: } else if (scanner.peekToken() instanceof TagToken) {
268: tag = ((TagToken) scanner.getToken()).getValue();
269: if (scanner.peekToken() instanceof AnchorToken) {
270: anchor = ((AnchorToken) scanner.getToken())
271: .getValue();
272: }
273: }
274: if (tag != null && !tag.equals("!")) {
275: final String handle = ScannerImpl
276: .into(((ByteList[]) tag)[0]);
277: String suffix = ScannerImpl
278: .into(((ByteList[]) tag)[1]);
279: int ix = -1;
280: if ((ix = suffix.indexOf("^")) != -1) {
281: suffix = suffix.substring(0, ix)
282: + suffix.substring(ix + 1);
283: }
284: if (handle != null) {
285: if (!this .getTagHandles().containsKey(handle)) {
286: throw new ParserException(
287: "while parsing a node",
288: "found undefined tag handle "
289: + handle, null);
290: }
291: if ((ix = suffix.indexOf("/")) != -1) {
292: String before = suffix.substring(0, ix);
293: String after = suffix.substring(ix + 1);
294: if (ONLY_WORD.matcher(before).matches()) {
295: tag = "tag:" + before
296: + ".yaml.org,2002:" + after;
297: } else {
298: if (before.startsWith("tag:")) {
299: tag = before + ":" + after;
300: } else {
301: tag = "tag:" + before + ":" + after;
302: }
303: }
304: } else {
305: tag = ((String) this .getTagHandles().get(
306: handle))
307: + suffix;
308: }
309: } else {
310: tag = suffix;
311: }
312: }
313: this .getAnchors().add(0, anchor);
314: this .getTags().add(0, tag);
315: return null;
316: }
317: case P_PROPERTIES_END: {
318: this .getAnchors().remove(0);
319: this .getTags().remove(0);
320: return null;
321: }
322: case P_FLOW_CONTENT: {
323: final Token tok = scanner.peekToken();
324: if (tok instanceof FlowSequenceStartToken) {
325: parseStack.push(P_FLOW_SEQUENCE);
326: } else if (tok instanceof FlowMappingStartToken) {
327: parseStack.push(P_FLOW_MAPPING);
328: } else if (tok instanceof ScalarToken) {
329: parseStack.push(P_SCALAR);
330: } else {
331: throw new ParserException(
332: "while scanning a flow node",
333: "expected the node content, but found "
334: + tok.getClass().getName(), null);
335: }
336: return null;
337: }
338: case P_BLOCK_SEQUENCE: {
339: parseStack.push(P_BLOCK_SEQUENCE_END);
340: parseStack.push(P_BLOCK_SEQUENCE_ENTRY);
341: parseStack.push(P_BLOCK_SEQUENCE_START);
342: return null;
343: }
344: case P_BLOCK_MAPPING: {
345: parseStack.push(P_BLOCK_MAPPING_END);
346: parseStack.push(P_BLOCK_MAPPING_ENTRY);
347: parseStack.push(P_BLOCK_MAPPING_START);
348: return null;
349: }
350: case P_FLOW_SEQUENCE: {
351: parseStack.push(P_FLOW_SEQUENCE_END);
352: parseStack.push(P_FLOW_SEQUENCE_ENTRY);
353: parseStack.push(P_FLOW_SEQUENCE_START);
354: return null;
355: }
356: case P_FLOW_MAPPING: {
357: parseStack.push(P_FLOW_MAPPING_END);
358: parseStack.push(P_FLOW_MAPPING_ENTRY);
359: parseStack.push(P_FLOW_MAPPING_START);
360: return null;
361: }
362: case P_SCALAR: {
363: final ScalarToken tok = (ScalarToken) scanner
364: .getToken();
365: boolean[] implicit = null;
366: if ((tok.getPlain() && this .getTags().get(0) == null)
367: || "!".equals(this .getTags().get(0))) {
368: implicit = new boolean[] { true, false };
369: } else if (this .getTags().get(0) == null) {
370: implicit = new boolean[] { false, true };
371: } else {
372: implicit = new boolean[] { false, false };
373: }
374: return new ScalarEvent((String) this .getAnchors()
375: .get(0), (String) this .getTags().get(0),
376: implicit, tok.getValue(), tok.getStyle());
377: }
378: case P_BLOCK_SEQUENCE_ENTRY: {
379: if (scanner.peekToken() instanceof BlockEntryToken) {
380: scanner.getToken();
381: if (!(scanner.peekToken() instanceof BlockEntryToken || scanner
382: .peekToken() instanceof BlockEndToken)) {
383: parseStack.push(P_BLOCK_SEQUENCE_ENTRY);
384: parseStack.push(P_BLOCK_NODE);
385: } else {
386: parseStack.push(P_BLOCK_SEQUENCE_ENTRY);
387: parseStack.push(P_EMPTY_SCALAR);
388: }
389: }
390: return null;
391: }
392: case P_BLOCK_MAPPING_ENTRY: {
393: if (scanner.peekToken() instanceof KeyToken
394: || scanner.peekToken() instanceof ValueToken) {
395: if (scanner.peekToken() instanceof KeyToken) {
396: scanner.getToken();
397: final Token curr = scanner.peekToken();
398: if (!(curr instanceof KeyToken
399: || curr instanceof ValueToken || curr instanceof BlockEndToken)) {
400: parseStack.push(P_BLOCK_MAPPING_ENTRY);
401: parseStack
402: .push(P_BLOCK_MAPPING_ENTRY_VALUE);
403: parseStack
404: .push(P_BLOCK_NODE_OR_INDENTLESS_SEQUENCE);
405: } else {
406: parseStack.push(P_BLOCK_MAPPING_ENTRY);
407: parseStack
408: .push(P_BLOCK_MAPPING_ENTRY_VALUE);
409: parseStack.push(P_EMPTY_SCALAR);
410: }
411: } else {
412: parseStack.push(P_BLOCK_MAPPING_ENTRY);
413: parseStack.push(P_BLOCK_MAPPING_ENTRY_VALUE);
414: parseStack.push(P_EMPTY_SCALAR);
415: }
416: }
417: return null;
418: }
419: case P_BLOCK_MAPPING_ENTRY_VALUE: {
420: if (scanner.peekToken() instanceof KeyToken
421: || scanner.peekToken() instanceof ValueToken) {
422: if (scanner.peekToken() instanceof ValueToken) {
423: scanner.getToken();
424: final Token curr = scanner.peekToken();
425: if (!(curr instanceof KeyToken
426: || curr instanceof ValueToken || curr instanceof BlockEndToken)) {
427: parseStack
428: .push(P_BLOCK_NODE_OR_INDENTLESS_SEQUENCE);
429: } else {
430: parseStack.push(P_EMPTY_SCALAR);
431: }
432: } else {
433: parseStack.push(P_EMPTY_SCALAR);
434: }
435: }
436: return null;
437: }
438: case P_BLOCK_NODE_OR_INDENTLESS_SEQUENCE: {
439: if (scanner.peekToken() instanceof AliasToken) {
440: parseStack.push(P_ALIAS);
441: } else {
442: if (scanner.peekToken() instanceof BlockEntryToken) {
443: parseStack.push(P_INDENTLESS_BLOCK_SEQUENCE);
444: parseStack.push(P_PROPERTIES);
445: } else {
446: parseStack.push(P_BLOCK_CONTENT);
447: parseStack.push(P_PROPERTIES);
448: }
449: }
450: return null;
451: }
452: case P_BLOCK_SEQUENCE_START: {
453: final boolean implicit = this .getTags().get(0) == null
454: || this .getTags().get(0).equals("!");
455: scanner.getToken();
456: return new SequenceStartEvent((String) this
457: .getAnchors().get(0), (String) this .getTags()
458: .get(0), implicit, false);
459: }
460: case P_BLOCK_SEQUENCE_END: {
461: Token tok = null;
462: if (!(scanner.peekToken() instanceof BlockEndToken)) {
463: tok = scanner.peekToken();
464: throw new ParserException(
465: "while scanning a block collection",
466: "expected <block end>, but found "
467: + tok.getClass().getName(), null);
468: }
469: scanner.getToken();
470: return SEQUENCE_END;
471: }
472: case P_BLOCK_MAPPING_START: {
473: final boolean implicit = this .getTags().get(0) == null
474: || this .getTags().get(0).equals("!");
475: scanner.getToken();
476: return new MappingStartEvent((String) this .getAnchors()
477: .get(0), (String) this .getTags().get(0),
478: implicit, false);
479: }
480: case P_BLOCK_MAPPING_END: {
481: Token tok = null;
482: if (!(scanner.peekToken() instanceof BlockEndToken)) {
483: tok = scanner.peekToken();
484: throw new ParserException(
485: "while scanning a block mapping",
486: "expected <block end>, but found "
487: + tok.getClass().getName(), null);
488: }
489: scanner.getToken();
490: return MAPPING_END;
491: }
492: case P_INDENTLESS_BLOCK_SEQUENCE: {
493: parseStack.push(P_BLOCK_INDENTLESS_SEQUENCE_END);
494: parseStack.push(P_INDENTLESS_BLOCK_SEQUENCE_ENTRY);
495: parseStack.push(P_BLOCK_INDENTLESS_SEQUENCE_START);
496: return null;
497: }
498: case P_BLOCK_INDENTLESS_SEQUENCE_START: {
499: final boolean implicit = this .getTags().get(0) == null
500: || this .getTags().get(0).equals("!");
501: return new SequenceStartEvent((String) this
502: .getAnchors().get(0), (String) this .getTags()
503: .get(0), implicit, false);
504: }
505: case P_INDENTLESS_BLOCK_SEQUENCE_ENTRY: {
506: if (scanner.peekToken() instanceof BlockEntryToken) {
507: scanner.getToken();
508: final Token curr = scanner.peekToken();
509: if (!(curr instanceof BlockEntryToken
510: || curr instanceof KeyToken
511: || curr instanceof ValueToken || curr instanceof BlockEndToken)) {
512: parseStack
513: .push(P_INDENTLESS_BLOCK_SEQUENCE_ENTRY);
514: parseStack.push(P_BLOCK_NODE);
515: } else {
516: parseStack
517: .push(P_INDENTLESS_BLOCK_SEQUENCE_ENTRY);
518: parseStack.push(P_EMPTY_SCALAR);
519: }
520: }
521: return null;
522: }
523: case P_BLOCK_INDENTLESS_SEQUENCE_END: {
524: return SEQUENCE_END;
525: }
526: case P_FLOW_SEQUENCE_START: {
527: final boolean implicit = this .getTags().get(0) == null
528: || this .getTags().get(0).equals("!");
529: scanner.getToken();
530: return new SequenceStartEvent((String) this
531: .getAnchors().get(0), (String) this .getTags()
532: .get(0), implicit, true);
533: }
534: case P_FLOW_SEQUENCE_ENTRY: {
535: if (!(scanner.peekToken() instanceof FlowSequenceEndToken)) {
536: if (scanner.peekToken() instanceof KeyToken) {
537: parseStack.push(P_FLOW_SEQUENCE_ENTRY);
538: parseStack.push(P_FLOW_ENTRY_MARKER);
539: parseStack.push(P_FLOW_INTERNAL_MAPPING_END);
540: parseStack.push(P_FLOW_INTERNAL_VALUE);
541: parseStack.push(P_FLOW_INTERNAL_CONTENT);
542: parseStack.push(P_FLOW_INTERNAL_MAPPING_START);
543: } else {
544: parseStack.push(P_FLOW_SEQUENCE_ENTRY);
545: parseStack.push(P_FLOW_NODE);
546: parseStack.push(P_FLOW_ENTRY_MARKER);
547: }
548: }
549: return null;
550: }
551: case P_FLOW_SEQUENCE_END: {
552: scanner.getToken();
553: return SEQUENCE_END;
554: }
555: case P_FLOW_MAPPING_START: {
556: final boolean implicit = this .getTags().get(0) == null
557: || this .getTags().get(0).equals("!");
558: scanner.getToken();
559: return new MappingStartEvent((String) this .getAnchors()
560: .get(0), (String) this .getTags().get(0),
561: implicit, true);
562: }
563: case P_FLOW_MAPPING_ENTRY: {
564: if (!(scanner.peekToken() instanceof FlowMappingEndToken)) {
565: if (scanner.peekToken() instanceof KeyToken) {
566: parseStack.push(P_FLOW_MAPPING_ENTRY);
567: parseStack.push(P_FLOW_ENTRY_MARKER);
568: parseStack.push(P_FLOW_MAPPING_INTERNAL_VALUE);
569: parseStack
570: .push(P_FLOW_MAPPING_INTERNAL_CONTENT);
571: } else {
572: parseStack.push(P_FLOW_MAPPING_ENTRY);
573: parseStack.push(P_FLOW_NODE);
574: parseStack.push(P_FLOW_ENTRY_MARKER);
575: }
576: }
577: return null;
578: }
579: case P_FLOW_MAPPING_END: {
580: scanner.getToken();
581: return MAPPING_END;
582: }
583: case P_FLOW_INTERNAL_MAPPING_START: {
584: scanner.getToken();
585: return new MappingStartEvent(null, null, true, true);
586: }
587: case P_FLOW_INTERNAL_CONTENT: {
588: final Token curr = scanner.peekToken();
589: if (!(curr instanceof ValueToken
590: || curr instanceof FlowEntryToken || curr instanceof FlowSequenceEndToken)) {
591: parseStack.push(P_FLOW_NODE);
592: } else {
593: parseStack.push(P_EMPTY_SCALAR);
594: }
595: return null;
596: }
597: case P_FLOW_INTERNAL_VALUE: {
598: if (scanner.peekToken() instanceof ValueToken) {
599: scanner.getToken();
600: if (!((scanner.peekToken() instanceof FlowEntryToken) || (scanner
601: .peekToken() instanceof FlowSequenceEndToken))) {
602: parseStack.push(P_FLOW_NODE);
603: } else {
604: parseStack.push(P_EMPTY_SCALAR);
605: }
606: } else {
607: parseStack.push(P_EMPTY_SCALAR);
608: }
609: return null;
610: }
611: case P_FLOW_INTERNAL_MAPPING_END: {
612: return MAPPING_END;
613: }
614: case P_FLOW_ENTRY_MARKER: {
615: if (scanner.peekToken() instanceof FlowEntryToken) {
616: scanner.getToken();
617: }
618: return null;
619: }
620: case P_FLOW_NODE: {
621: if (scanner.peekToken() instanceof AliasToken) {
622: parseStack.push(P_ALIAS);
623: } else {
624: parseStack.push(P_PROPERTIES_END);
625: parseStack.push(P_FLOW_CONTENT);
626: parseStack.push(P_PROPERTIES);
627: }
628: return null;
629: }
630: case P_FLOW_MAPPING_INTERNAL_CONTENT: {
631: final Token curr = scanner.peekToken();
632: if (!(curr instanceof ValueToken
633: || curr instanceof FlowEntryToken || curr instanceof FlowMappingEndToken)) {
634: scanner.getToken();
635: parseStack.push(P_FLOW_NODE);
636: } else {
637: parseStack.push(P_EMPTY_SCALAR);
638: }
639: return null;
640: }
641: case P_FLOW_MAPPING_INTERNAL_VALUE: {
642: if (scanner.peekToken() instanceof ValueToken) {
643: scanner.getToken();
644: if (!(scanner.peekToken() instanceof FlowEntryToken || scanner
645: .peekToken() instanceof FlowMappingEndToken)) {
646: parseStack.push(P_FLOW_NODE);
647: } else {
648: parseStack.push(P_EMPTY_SCALAR);
649: }
650: } else {
651: parseStack.push(P_EMPTY_SCALAR);
652: }
653: return null;
654: }
655: case P_ALIAS: {
656: final AliasToken tok = (AliasToken) scanner.getToken();
657: return new AliasEvent(tok.getValue());
658: }
659: case P_EMPTY_SCALAR: {
660: return processEmptyScalar();
661: }
662: }
663:
664: return null;
665: }
666: }
667:
668: private final static Map DEFAULT_TAGS_1_0 = new HashMap();
669: private final static Map DEFAULT_TAGS_1_1 = new HashMap();
670: static {
671: DEFAULT_TAGS_1_0.put("!", "tag:yaml.org,2002:");
672: DEFAULT_TAGS_1_0.put("!!", "");
673:
674: DEFAULT_TAGS_1_1.put("!", "!");
675: DEFAULT_TAGS_1_1.put("!!", "tag:yaml.org,2002:");
676: }
677: private final static Pattern ONLY_WORD = Pattern.compile("^\\w+$");
678:
679: private static Event processEmptyScalar() {
680: return new ScalarEvent(null, null,
681: new boolean[] { true, false }, new ByteList(
682: ByteList.NULL_ARRAY), (char) 0);
683: }
684:
685: private static Object[] processDirectives(
686: final ProductionEnvironment env, final Scanner scanner) {
687: while (scanner.peekToken() instanceof DirectiveToken) {
688: final DirectiveToken tok = (DirectiveToken) scanner
689: .getToken();
690: if (tok.getName().equals("YAML")) {
691: if (env.getYamlVersion() != null) {
692: throw new ParserException(null,
693: "found duplicate YAML directive", null);
694: }
695: final int major = Integer.parseInt(tok.getValue()[0]);
696: final int minor = Integer.parseInt(tok.getValue()[1]);
697: if (major != 1) {
698: throw new ParserException(
699: null,
700: "found incompatible YAML document (version 1.* is required)",
701: null);
702: }
703: env.setYamlVersion(new int[] { major, minor });
704: } else if (tok.getName().equals("TAG")) {
705: final String handle = tok.getValue()[0];
706: final String prefix = tok.getValue()[1];
707: if (env.getTagHandles().containsKey(handle)) {
708: throw new ParserException(null,
709: "duplicate tag handle " + handle, null);
710: }
711: env.getTagHandles().put(handle, prefix);
712: }
713: }
714: Object[] value = new Object[2];
715: value[0] = env.getFinalYamlVersion();
716:
717: if (!env.getTagHandles().isEmpty()) {
718: value[1] = new HashMap(env.getTagHandles());
719: }
720:
721: final Map baseTags = ((int[]) value[0])[1] == 0 ? DEFAULT_TAGS_1_0
722: : DEFAULT_TAGS_1_1;
723: for (final Iterator iter = baseTags.keySet().iterator(); iter
724: .hasNext();) {
725: final Object key = iter.next();
726: if (!env.getTagHandles().containsKey(key)) {
727: env.getTagHandles().put(key, baseTags.get(key));
728: }
729: }
730: return value;
731: }
732:
733: private Scanner scanner = null;
734: private YAMLConfig cfg = null;
735:
736: public ParserImpl(final Scanner scanner) {
737: this (scanner, YAML.config());
738: }
739:
740: public ParserImpl(final Scanner scanner, final YAMLConfig cfg) {
741: this .scanner = scanner;
742: this .cfg = cfg;
743: }
744:
745: private Event currentEvent = null;
746:
747: public boolean checkEvent(final Class[] choices) {
748: parseStream();
749: if (this .currentEvent == null) {
750: this .currentEvent = parseStreamNext();
751: }
752: if (this .currentEvent != null) {
753: if (choices.length == 0) {
754: return true;
755: }
756: for (int i = 0, j = choices.length; i < j; i++) {
757: if (choices[i].isInstance(this .currentEvent)) {
758: return true;
759: }
760: }
761: }
762: return false;
763: }
764:
765: public Event peekEvent() {
766: parseStream();
767: if (this .currentEvent == null) {
768: this .currentEvent = parseStreamNext();
769: }
770: return this .currentEvent;
771: }
772:
773: public Event getEvent() {
774: parseStream();
775: if (this .currentEvent == null) {
776: this .currentEvent = parseStreamNext();
777: }
778: final Event value = this .currentEvent;
779: this .currentEvent = null;
780: return value;
781: }
782:
783: private class EventIterator implements Iterator {
784: public boolean hasNext() {
785: return null != peekEvent();
786: }
787:
788: public Object next() {
789: return getEvent();
790: }
791:
792: public void remove() {
793: }
794: }
795:
796: public Iterator eachEvent() {
797: return new EventIterator();
798: }
799:
800: public Iterator iterator() {
801: return eachEvent();
802: }
803:
804: private IntStack parseStack = null;
805: private ProductionEnvironment pEnv = null;
806:
807: public void parseStream() {
808: if (null == parseStack) {
809: this .parseStack = new IntStack();
810: this .parseStack.push(P_STREAM);
811: this .pEnv = new ProductionEnvironment(cfg);
812: }
813: }
814:
815: public Event parseStreamNext() {
816: while (!parseStack.isEmpty()) {
817: final Event value = this .pEnv.produce(
818: this .parseStack.pop(), this .parseStack,
819: this .scanner);
820: if (null != value) {
821: return value;
822: }
823: }
824: this .pEnv = null;
825: return null;
826: }
827:
828: public static void tmainx(final String[] args) throws Exception {
829: final String filename = args[0];
830: System.out.println("Reading of file: \"" + filename + "\"");
831:
832: final ByteList input = new ByteList(1024);
833: final InputStream reader = new FileInputStream(filename);
834: byte[] buff = new byte[1024];
835: int read = 0;
836: while (true) {
837: read = reader.read(buff);
838: input.append(buff, 0, read);
839: if (read < 1024) {
840: break;
841: }
842: }
843: reader.close();
844: final long before = System.currentTimeMillis();
845: for (int i = 0; i < 1; i++) {
846: final Parser pars = new ParserImpl(new ScannerImpl(input));
847: for (final Iterator iter = pars.eachEvent(); iter.hasNext(); iter
848: .next()) {
849: }
850: }
851: final long after = System.currentTimeMillis();
852: final long time = after - before;
853: final double timeS = (after - before) / 1000.0;
854: System.out.println("Walking through the events for the file: "
855: + filename + " took " + time + "ms, or " + timeS
856: + " seconds");
857: }
858:
859: public static void tmain(final String[] args) throws Exception {
860: final String filename = args[0];
861: System.out.println("Reading of file: \"" + filename + "\"");
862:
863: final InputStream reader = new FileInputStream(filename);
864: final long before = System.currentTimeMillis();
865: for (int i = 0; i < 1; i++) {
866: final Parser pars = new ParserImpl(new ScannerImpl(reader));
867: for (final Iterator iter = pars.eachEvent(); iter.hasNext(); iter
868: .next()) {
869: }
870: }
871: reader.close();
872: final long after = System.currentTimeMillis();
873: final long time = after - before;
874: final double timeS = (after - before) / 1000.0;
875: System.out.println("Walking through the events for the file: "
876: + filename + " took " + time + "ms, or " + timeS
877: + " seconds");
878: }
879:
880: public static void main(final String[] args) throws Exception {
881: final String filename = args[0];
882: final Parser pars = new ParserImpl(new ScannerImpl(
883: new FileInputStream(filename)));
884: for (final Iterator iter = pars.eachEvent(); iter.hasNext();) {
885: System.out.println(iter.next());
886: }
887: }
888: }// ParserImpl
|