1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2005-2008 Terence Parr
4 * All rights reserved.
5 *
6 * Conversion to C#:
7 * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33namespace Antlr.Runtime.Tree
34{
35    using ConditionalAttribute = System.Diagnostics.ConditionalAttribute;
36    using Regex = System.Text.RegularExpressions.Regex;
37    using RegexOptions = System.Text.RegularExpressions.RegexOptions;
38
39    /** <summary>
40     *  A parser for a stream of tree nodes.  "tree grammars" result in a subclass
41     *  of this.  All the error reporting and recovery is shared with Parser via
42     *  the BaseRecognizer superclass.
43     *  </summary>
44    */
45    public class TreeParser : BaseRecognizer
46    {
47        public const int DOWN = TokenTypes.Down;
48        public const int UP = TokenTypes.Up;
49
50        // precompiled regex used by inContext
51        static string dotdot = ".*[^.]\\.\\.[^.].*";
52        static string doubleEtc = ".*\\.\\.\\.\\s+\\.\\.\\..*";
53        static Regex dotdotPattern = new Regex( dotdot, RegexOptions.Compiled );
54        static Regex doubleEtcPattern = new Regex( doubleEtc, RegexOptions.Compiled );
55
56        protected ITreeNodeStream input;
57
58        public TreeParser( ITreeNodeStream input )
59            : base() // highlight that we go to super to set state object
60        {
61            SetTreeNodeStream( input );
62        }
63
64        public TreeParser( ITreeNodeStream input, RecognizerSharedState state )
65            : base( state ) // share the state object with another parser
66        {
67            SetTreeNodeStream( input );
68        }
69
70        public override void Reset()
71        {
72            base.Reset(); // reset all recognizer state variables
73            if ( input != null )
74            {
75                input.Seek( 0 ); // rewind the input
76            }
77        }
78
79        /** <summary>Set the input stream</summary> */
80        public virtual void SetTreeNodeStream( ITreeNodeStream input )
81        {
82            this.input = input;
83        }
84
85        public virtual ITreeNodeStream GetTreeNodeStream()
86        {
87            return input;
88        }
89
90        public override string SourceName
91        {
92            get
93            {
94                return input.SourceName;
95            }
96        }
97
98        protected override object GetCurrentInputSymbol( IIntStream input )
99        {
100            return ( (ITreeNodeStream)input ).LT( 1 );
101        }
102
103        protected override object GetMissingSymbol( IIntStream input,
104                                          RecognitionException e,
105                                          int expectedTokenType,
106                                          BitSet follow )
107        {
108            string tokenText =
109                "<missing " + TokenNames[expectedTokenType] + ">";
110            ITreeAdaptor adaptor = ((ITreeNodeStream)e.Input).TreeAdaptor;
111            return adaptor.Create(new CommonToken(expectedTokenType, tokenText));
112        }
113
114        /** <summary>
115         *  Match '.' in tree parser has special meaning.  Skip node or
116         *  entire tree if node has children.  If children, scan until
117         *  corresponding UP node.
118         *  </summary>
119         */
120        public override void MatchAny( IIntStream ignore )
121        {
122            state.errorRecovery = false;
123            state.failed = false;
124            // always consume the current node
125            input.Consume();
126            // if the next node is DOWN, then the current node is a subtree:
127            // skip to corresponding UP. must count nesting level to get right UP
128            int look = input.LA( 1 );
129            if ( look == DOWN )
130            {
131                input.Consume();
132                int level = 1;
133                while ( level > 0 )
134                {
135                    switch ( input.LA( 1 ) )
136                    {
137                    case DOWN:
138                        level++;
139                        break;
140                    case UP:
141                        level--;
142                        break;
143                    case TokenTypes.EndOfFile:
144                        return;
145                    default:
146                        break;
147                    }
148                    input.Consume();
149                }
150            }
151        }
152
153        /** <summary>
154         *  We have DOWN/UP nodes in the stream that have no line info; override.
155         *  plus we want to alter the exception type.  Don't try to recover
156         *  from tree parser errors inline...
157         *  </summary>
158         */
159        protected override object RecoverFromMismatchedToken( IIntStream input, int ttype, BitSet follow )
160        {
161            throw new MismatchedTreeNodeException( ttype, (ITreeNodeStream)input );
162        }
163
164        /** <summary>
165         *  Prefix error message with the grammar name because message is
166         *  always intended for the programmer because the parser built
167         *  the input tree not the user.
168         *  </summary>
169         */
170        public override string GetErrorHeader( RecognitionException e )
171        {
172            return GrammarFileName + ": node from " +
173                   ( e.ApproximateLineInfo ? "after " : "" ) + "line " + e.Line + ":" + e.CharPositionInLine;
174        }
175
176        /** <summary>
177         *  Tree parsers parse nodes they usually have a token object as
178         *  payload. Set the exception token and do the default behavior.
179         *  </summary>
180         */
181        public override string GetErrorMessage( RecognitionException e, string[] tokenNames )
182        {
183            if ( this is TreeParser )
184            {
185                ITreeAdaptor adaptor = ( (ITreeNodeStream)e.Input ).TreeAdaptor;
186                e.Token = adaptor.GetToken( e.Node );
187                if ( e.Token == null )
188                { // could be an UP/DOWN node
189                    e.Token = new CommonToken( adaptor.GetType( e.Node ),
190                                              adaptor.GetText( e.Node ) );
191                }
192            }
193            return base.GetErrorMessage( e, tokenNames );
194        }
195
196        [Conditional("ANTLR_TRACE")]
197        public virtual void TraceIn( string ruleName, int ruleIndex )
198        {
199            base.TraceIn( ruleName, ruleIndex, input.LT( 1 ) );
200        }
201
202        [Conditional("ANTLR_TRACE")]
203        public virtual void TraceOut( string ruleName, int ruleIndex )
204        {
205            base.TraceOut( ruleName, ruleIndex, input.LT( 1 ) );
206        }
207
208    }
209}
210