1d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen/****************************************************************
2d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * Licensed to the Apache Software Foundation (ASF) under one   *
3d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * or more contributor license agreements.  See the NOTICE file *
4d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * distributed with this work for additional information        *
5d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * regarding copyright ownership.  The ASF licenses this file   *
6d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * to you under the Apache License, Version 2.0 (the            *
7d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * "License"); you may not use this file except in compliance   *
8d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * with the License.  You may obtain a copy of the License at   *
9d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *                                                              *
10d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *   http://www.apache.org/licenses/LICENSE-2.0                 *
11d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *                                                              *
12d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * Unless required by applicable law or agreed to in writing,   *
13d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * software distributed under the License is distributed on an  *
14d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * KIND, either express or implied.  See the License for the    *
16d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * specific language governing permissions and limitations      *
17d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * under the License.                                           *
18d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen ****************************************************************/
19d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
20d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenpackage org.apache.james.mime4j.field.address;
21d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
22d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport java.util.ArrayList;
23d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport java.util.Iterator;
24d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
25d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.decoder.DecoderUtil;
26d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTaddr_spec;
27d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTaddress;
28d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTaddress_list;
29d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTangle_addr;
30d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTdomain;
31d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTgroup_body;
32d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTlocal_part;
33d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTmailbox;
34d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTname_addr;
35d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTphrase;
36d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.ASTroute;
37d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.Node;
38d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.SimpleNode;
39d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenimport org.apache.james.mime4j.field.address.parser.Token;
40d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
41d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen/**
42d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * Transforms the JJTree-generated abstract syntax tree
43d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen * into a graph of org.apache.james.mime4j.field.address objects.
44d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *
45d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen *
46d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen */
47d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chenclass Builder {
48d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
49d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private static Builder singleton = new Builder();
50d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
51d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	public static Builder getInstance() {
52d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return singleton;
53d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
54d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
55d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
56d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
57d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	public AddressList buildAddressList(ASTaddress_list node) {
58d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ArrayList<Address> list = new ArrayList<Address>();
59d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
60d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
61d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			Address address = buildAddress(childNode);
62d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			list.add(address);
63d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
64d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return new AddressList(list, true);
65d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
66d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
67d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private Address buildAddress(ASTaddress node) {
68d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
69d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		Node n = it.nextNode();
70d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (n instanceof ASTaddr_spec) {
71d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return buildAddrSpec((ASTaddr_spec)n);
72d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
73d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else if (n instanceof ASTangle_addr) {
74d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return buildAngleAddr((ASTangle_addr)n);
75d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
76d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else if (n instanceof ASTphrase) {
77d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			String name = buildString((ASTphrase)n, false);
78d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			Node n2 = it.nextNode();
79d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			if (n2 instanceof ASTgroup_body) {
80d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				return new Group(name, buildGroupBody((ASTgroup_body)n2));
81d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			}
82d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			else if (n2 instanceof ASTangle_addr) {
83d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen                name = DecoderUtil.decodeEncodedWords(name);
84d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2));
85d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			}
86d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			else {
87d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				throw new IllegalStateException();
88d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			}
89d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
90d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else {
91d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new IllegalStateException();
92d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
93d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
94d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
95d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
96d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
97d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private MailboxList buildGroupBody(ASTgroup_body node) {
98d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ArrayList<Address> results = new ArrayList<Address>();
99d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
100d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		while (it.hasNext()) {
101d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			Node n = it.nextNode();
102d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			if (n instanceof ASTmailbox)
103d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				results.add(buildMailbox((ASTmailbox)n));
104d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			else
105d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				throw new IllegalStateException();
106d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
107d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return new MailboxList(results, true);
108d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
109d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
110d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private Mailbox buildMailbox(ASTmailbox node) {
111d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
112d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		Node n = it.nextNode();
113d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (n instanceof ASTaddr_spec) {
114d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return buildAddrSpec((ASTaddr_spec)n);
115d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
116d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else if (n instanceof ASTangle_addr) {
117d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return buildAngleAddr((ASTangle_addr)n);
118d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
119d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else if (n instanceof ASTname_addr) {
120d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return buildNameAddr((ASTname_addr)n);
121d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
122d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else {
123d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new IllegalStateException();
124d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
125d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
126d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
127d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private NamedMailbox buildNameAddr(ASTname_addr node) {
128d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
129d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		Node n = it.nextNode();
130d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		String name;
131d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (n instanceof ASTphrase) {
132d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			name = buildString((ASTphrase)n, false);
133d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
134d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else {
135d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new IllegalStateException();
136d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
137d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
138d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		n = it.nextNode();
139d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (n instanceof ASTangle_addr) {
140d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen            name = DecoderUtil.decodeEncodedWords(name);
141d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n));
142d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
143d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else {
144d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new IllegalStateException();
145d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
146d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
147d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
148d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private Mailbox buildAngleAddr(ASTangle_addr node) {
149d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
150d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		DomainList route = null;
151d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		Node n = it.nextNode();
152d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (n instanceof ASTroute) {
153d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			route = buildRoute((ASTroute)n);
154d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			n = it.nextNode();
155d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
156d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else if (n instanceof ASTaddr_spec)
157d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			; // do nothing
158d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else
159d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new IllegalStateException();
160d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
161d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (n instanceof ASTaddr_spec)
162d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return buildAddrSpec(route, (ASTaddr_spec)n);
163d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		else
164d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new IllegalStateException();
165d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
166d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
167d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private DomainList buildRoute(ASTroute node) {
168d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ArrayList<String> results = new ArrayList<String>(node.jjtGetNumChildren());
169d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
170d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		while (it.hasNext()) {
171d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			Node n = it.nextNode();
172d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			if (n instanceof ASTdomain)
173d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				results.add(buildString((ASTdomain)n, true));
174d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			else
175d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				throw new IllegalStateException();
176d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
177d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return new DomainList(results, true);
178d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
179d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
180d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private Mailbox buildAddrSpec(ASTaddr_spec node) {
181d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return buildAddrSpec(null, node);
182d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
183d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
184d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		ChildNodeIterator it = new ChildNodeIterator(node);
185d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		String localPart = buildString((ASTlocal_part)it.nextNode(), true);
186d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		String domain = buildString((ASTdomain)it.nextNode(), true);
187d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return new Mailbox(route, localPart, domain);
188d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
189d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
190d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
191d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private String buildString(SimpleNode node, boolean stripSpaces) {
192d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		Token head = node.firstToken;
193d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		Token tail = node.lastToken;
194d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		StringBuffer out = new StringBuffer();
195d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
196d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		while (head != tail) {
197d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			out.append(head.image);
198d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			head = head.next;
199d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			if (!stripSpaces)
200d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen				addSpecials(out, head.specialToken);
201d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
202d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		out.append(tail.image);
203d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
204d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		return out.toString();
205d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
206d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
207d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private void addSpecials(StringBuffer out, Token specialToken) {
208d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		if (specialToken != null) {
209d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			addSpecials(out, specialToken.specialToken);
210d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			out.append(specialToken.image);
211d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
212d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
213d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
214d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	private static class ChildNodeIterator implements Iterator<Node> {
215d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
216d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		private SimpleNode simpleNode;
217d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		private int index;
218d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		private int len;
219d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
220d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		public ChildNodeIterator(SimpleNode simpleNode) {
221d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			this.simpleNode = simpleNode;
222d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			this.len = simpleNode.jjtGetNumChildren();
223d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			this.index = 0;
224d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
225d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
226d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		public void remove() {
227d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			throw new UnsupportedOperationException();
228d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
229d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
230d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		public boolean hasNext() {
231d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return index < len;
232d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
233d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
234d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		public Node next() {
235d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return nextNode();
236d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
237d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
238d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		public Node nextNode() {
239d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen			return simpleNode.jjtGetChild(index++);
240d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen		}
241d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen
242d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen	}
243d186a38568ddec7efcba054ccc2fe8ed9b8945fcNancy Chen}
244