001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.parsing;
018
019import java.util.Stack;
020
021/**
022 * Simple {@link Stack}-based structure for tracking the logical position during
023 * a parsing process. {@link Entry entries} are added to the stack at each point
024 * during the parse phase in a reader-specific manner.
025 *
026 * <p>Calling {@link #toString()} will render a tree-style view of the current logical
027 * position in the parse phase. This representation is intended for use in error messages.
028 *
029 * @author Rob Harrop
030 * @since 2.0
031 */
032public final class ParseState {
033
034        /**
035         * Internal {@link Stack} storage.
036         */
037        private final Stack<Entry> state;
038
039
040        /**
041         * Create a new {@code ParseState} with an empty {@link Stack}.
042         */
043        public ParseState() {
044                this.state = new Stack<Entry>();
045        }
046
047        /**
048         * Create a new {@code ParseState} whose {@link Stack} is a clone
049         * of that of the passed in {@code ParseState}.
050         */
051        @SuppressWarnings("unchecked")
052        private ParseState(ParseState other) {
053                this.state = (Stack<Entry>) other.state.clone();
054        }
055
056
057        /**
058         * Add a new {@link Entry} to the {@link Stack}.
059         */
060        public void push(Entry entry) {
061                this.state.push(entry);
062        }
063
064        /**
065         * Remove an {@link Entry} from the {@link Stack}.
066         */
067        public void pop() {
068                this.state.pop();
069        }
070
071        /**
072         * Return the {@link Entry} currently at the top of the {@link Stack} or
073         * {@code null} if the {@link Stack} is empty.
074         */
075        public Entry peek() {
076                return (this.state.empty() ? null : this.state.peek());
077        }
078
079        /**
080         * Create a new instance of {@link ParseState} which is an independent snapshot
081         * of this instance.
082         */
083        public ParseState snapshot() {
084                return new ParseState(this);
085        }
086
087
088        /**
089         * Returns a tree-style representation of the current {@code ParseState}.
090         */
091        @Override
092        public String toString() {
093                StringBuilder sb = new StringBuilder(64);
094                int i = 0;
095                for (ParseState.Entry entry : this.state) {
096                        if (i > 0) {
097                                sb.append('\n');
098                                for (int j = 0; j < i; j++) {
099                                        sb.append('\t');
100                                }
101                                sb.append("-> ");
102                        }
103                        sb.append(entry);
104                        i++;
105                }
106                return sb.toString();
107        }
108
109
110        /**
111         * Marker interface for entries into the {@link ParseState}.
112         */
113        public interface Entry {
114
115        }
116
117}