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    using InvalidOperationException = System.InvalidOperationException;
35
36    public class TreePatternParser {
37        protected TreePatternLexer tokenizer;
38        protected int ttype;
39        protected TreeWizard wizard;
40        protected ITreeAdaptor adaptor;
41
42        public TreePatternParser(TreePatternLexer tokenizer, TreeWizard wizard, ITreeAdaptor adaptor) {
43            this.tokenizer = tokenizer;
44            this.wizard = wizard;
45            this.adaptor = adaptor;
46            ttype = tokenizer.NextToken(); // kickstart
47        }
48
49        public virtual object Pattern() {
50            if (ttype == TreePatternLexer.BEGIN) {
51                return ParseTree();
52            } else if (ttype == TreePatternLexer.ID) {
53                object node = ParseNode();
54                if (ttype == TreePatternLexer.EOF) {
55                    return node;
56                }
57                return null; // extra junk on end
58            }
59            return null;
60        }
61
62        public virtual object ParseTree() {
63            if (ttype != TreePatternLexer.BEGIN)
64                throw new InvalidOperationException("No beginning.");
65
66            ttype = tokenizer.NextToken();
67            object root = ParseNode();
68            if (root == null) {
69                return null;
70            }
71            while (ttype == TreePatternLexer.BEGIN ||
72                    ttype == TreePatternLexer.ID ||
73                    ttype == TreePatternLexer.PERCENT ||
74                    ttype == TreePatternLexer.DOT) {
75                if (ttype == TreePatternLexer.BEGIN) {
76                    object subtree = ParseTree();
77                    adaptor.AddChild(root, subtree);
78                } else {
79                    object child = ParseNode();
80                    if (child == null) {
81                        return null;
82                    }
83                    adaptor.AddChild(root, child);
84                }
85            }
86
87            if (ttype != TreePatternLexer.END)
88                throw new InvalidOperationException("No end.");
89
90            ttype = tokenizer.NextToken();
91            return root;
92        }
93
94        public virtual object ParseNode() {
95            // "%label:" prefix
96            string label = null;
97            if (ttype == TreePatternLexer.PERCENT) {
98                ttype = tokenizer.NextToken();
99                if (ttype != TreePatternLexer.ID) {
100                    return null;
101                }
102                label = tokenizer.sval.ToString();
103                ttype = tokenizer.NextToken();
104                if (ttype != TreePatternLexer.COLON) {
105                    return null;
106                }
107                ttype = tokenizer.NextToken(); // move to ID following colon
108            }
109
110            // Wildcard?
111            if (ttype == TreePatternLexer.DOT) {
112                ttype = tokenizer.NextToken();
113                IToken wildcardPayload = new CommonToken(0, ".");
114                TreeWizard.TreePattern node =
115                    new TreeWizard.WildcardTreePattern(wildcardPayload);
116                if (label != null) {
117                    node.label = label;
118                }
119                return node;
120            }
121
122            // "ID" or "ID[arg]"
123            if (ttype != TreePatternLexer.ID) {
124                return null;
125            }
126            string tokenName = tokenizer.sval.ToString();
127            ttype = tokenizer.NextToken();
128            if (tokenName.Equals("nil")) {
129                return adaptor.Nil();
130            }
131            string text = tokenName;
132            // check for arg
133            string arg = null;
134            if (ttype == TreePatternLexer.ARG) {
135                arg = tokenizer.sval.ToString();
136                text = arg;
137                ttype = tokenizer.NextToken();
138            }
139
140            // create node
141            int treeNodeType = wizard.GetTokenType(tokenName);
142            if (treeNodeType == TokenTypes.Invalid) {
143                return null;
144            }
145            object node2;
146            node2 = adaptor.Create(treeNodeType, text);
147            if (label != null && node2.GetType() == typeof(TreeWizard.TreePattern)) {
148                ((TreeWizard.TreePattern)node2).label = label;
149            }
150            if (arg != null && node2.GetType() == typeof(TreeWizard.TreePattern)) {
151                ((TreeWizard.TreePattern)node2).hasTextArg = true;
152            }
153            return node2;
154        }
155    }
156}
157