Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: editor/tools/plugins/com.google.dart.engine/src/com/google/dart/engine/internal/builder/HtmlUnitBuilder.java

Issue 82903007: Improved HTML parsing (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Clean-up Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013, the Dart project authors. 2 * Copyright (c) 2013, the Dart project authors.
3 * 3 *
4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u se this file except 4 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not u se this file except
5 * in compliance with the License. You may obtain a copy of the License at 5 * in compliance with the License. You may obtain a copy of the License at
6 * 6 *
7 * http://www.eclipse.org/legal/epl-v10.html 7 * http://www.eclipse.org/legal/epl-v10.html
8 * 8 *
9 * Unless required by applicable law or agreed to in writing, software distribut ed under the License 9 * Unless required by applicable law or agreed to in writing, software distribut ed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K IND, either express 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY K IND, either express
11 * or implied. See the License for the specific language governing permissions a nd limitations under 11 * or implied. See the License for the specific language governing permissions a nd limitations under
12 * the License. 12 * the License.
13 */ 13 */
14 package com.google.dart.engine.internal.builder; 14 package com.google.dart.engine.internal.builder;
15 15
16 import com.google.common.annotations.VisibleForTesting; 16 import com.google.common.annotations.VisibleForTesting;
17 import com.google.dart.engine.AnalysisEngine; 17 import com.google.dart.engine.AnalysisEngine;
18 import com.google.dart.engine.ast.CompilationUnit; 18 import com.google.dart.engine.ast.Expression;
19 import com.google.dart.engine.context.AnalysisException; 19 import com.google.dart.engine.context.AnalysisException;
20 import com.google.dart.engine.element.HtmlScriptElement; 20 import com.google.dart.engine.element.HtmlScriptElement;
21 import com.google.dart.engine.error.AnalysisError; 21 import com.google.dart.engine.error.AnalysisError;
22 import com.google.dart.engine.error.ErrorCode; 22 import com.google.dart.engine.error.ErrorCode;
23 import com.google.dart.engine.error.HtmlWarningCode; 23 import com.google.dart.engine.error.HtmlWarningCode;
24 import com.google.dart.engine.html.ast.EmbeddedExpression;
25 import com.google.dart.engine.html.ast.HtmlScriptTagNode;
24 import com.google.dart.engine.html.ast.HtmlUnit; 26 import com.google.dart.engine.html.ast.HtmlUnit;
25 import com.google.dart.engine.html.ast.XmlAttributeNode; 27 import com.google.dart.engine.html.ast.XmlAttributeNode;
26 import com.google.dart.engine.html.ast.XmlTagNode; 28 import com.google.dart.engine.html.ast.XmlTagNode;
27 import com.google.dart.engine.html.ast.visitor.XmlVisitor; 29 import com.google.dart.engine.html.ast.visitor.XmlVisitor;
28 import com.google.dart.engine.html.scanner.Token;
29 import com.google.dart.engine.html.scanner.TokenType; 30 import com.google.dart.engine.html.scanner.TokenType;
30 import com.google.dart.engine.internal.context.InternalAnalysisContext; 31 import com.google.dart.engine.internal.context.InternalAnalysisContext;
31 import com.google.dart.engine.internal.context.RecordingErrorListener; 32 import com.google.dart.engine.internal.context.RecordingErrorListener;
32 import com.google.dart.engine.internal.element.EmbeddedHtmlScriptElementImpl; 33 import com.google.dart.engine.internal.element.EmbeddedHtmlScriptElementImpl;
33 import com.google.dart.engine.internal.element.ExternalHtmlScriptElementImpl; 34 import com.google.dart.engine.internal.element.ExternalHtmlScriptElementImpl;
34 import com.google.dart.engine.internal.element.HtmlElementImpl; 35 import com.google.dart.engine.internal.element.HtmlElementImpl;
35 import com.google.dart.engine.internal.element.LibraryElementImpl; 36 import com.google.dart.engine.internal.element.LibraryElementImpl;
36 import com.google.dart.engine.internal.resolver.Library; 37 import com.google.dart.engine.internal.resolver.Library;
37 import com.google.dart.engine.internal.resolver.LibraryResolver; 38 import com.google.dart.engine.internal.resolver.LibraryResolver;
38 import com.google.dart.engine.parser.Parser;
39 import com.google.dart.engine.scanner.Scanner;
40 import com.google.dart.engine.scanner.SubSequenceReader;
41 import com.google.dart.engine.source.Source; 39 import com.google.dart.engine.source.Source;
42 import com.google.dart.engine.utilities.io.UriUtilities; 40 import com.google.dart.engine.utilities.io.UriUtilities;
43 import com.google.dart.engine.utilities.source.LineInfo; 41 import com.google.dart.engine.utilities.source.LineInfo;
44 import com.google.dart.engine.utilities.source.LineInfo.Location;
45 42
46 import java.net.URI; 43 import java.net.URI;
47 import java.net.URISyntaxException; 44 import java.net.URISyntaxException;
48 import java.util.ArrayList; 45 import java.util.ArrayList;
49 import java.util.HashSet; 46 import java.util.HashSet;
50 import java.util.Set; 47 import java.util.Set;
51 48
52 /** 49 /**
53 * Instances of the class {@code HtmlUnitBuilder} build an element model for a s ingle HTML unit. 50 * Instances of the class {@code HtmlUnitBuilder} build an element model for a s ingle HTML unit.
54 */ 51 */
55 public class HtmlUnitBuilder implements XmlVisitor<Void> { 52 public class HtmlUnitBuilder implements XmlVisitor<Void> {
56 private static final String APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application /dart\"";
57 private static final String APPLICATION_DART_IN_SINGLE_QUOTES = "'application/ dart'";
58 private static final String SCRIPT = "script";
59 private static final String SRC = "src"; 53 private static final String SRC = "src";
60 private static final String TYPE = "type";
61 54
62 /** 55 /**
63 * The analysis context in which the element model will be built. 56 * The analysis context in which the element model will be built.
64 */ 57 */
65 private final InternalAnalysisContext context; 58 private final InternalAnalysisContext context;
66 59
67 /** 60 /**
68 * The error listener to which errors will be reported. 61 * The error listener to which errors will be reported.
69 */ 62 */
70 private RecordingErrorListener errorListener; 63 private RecordingErrorListener errorListener;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 /** 149 /**
157 * Return an array containing information about all of the libraries that were resolved. 150 * Return an array containing information about all of the libraries that were resolved.
158 * 151 *
159 * @return an array containing the libraries that were resolved 152 * @return an array containing the libraries that were resolved
160 */ 153 */
161 public Set<Library> getResolvedLibraries() { 154 public Set<Library> getResolvedLibraries() {
162 return resolvedLibraries; 155 return resolvedLibraries;
163 } 156 }
164 157
165 @Override 158 @Override
159 public Void visitHtmlScriptTagNode(HtmlScriptTagNode node) {
160 if (parentNodes.contains(node)) {
161 return reportCircularity(node);
162 }
163 parentNodes.add(node);
164 try {
165 Source htmlSource = htmlElement.getSource();
166 XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
167 String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute .getText();
168 if (node.getAttributeEnd().getType() == TokenType.GT && scriptSourcePath = = null) {
169 EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl (node);
170 try {
171 LibraryResolver resolver = new LibraryResolver(context);
172 LibraryElementImpl library = (LibraryElementImpl) resolver.resolveEmbe ddedLibrary(
173 htmlSource,
174 modificationStamp,
175 node.getScript(),
176 true);
177 script.setScriptLibrary(library);
178 resolvedLibraries.addAll(resolver.getResolvedLibraries());
179 errorListener.addAll(resolver.getErrorListener());
180 } catch (AnalysisException exception) {
181 //TODO (danrubel): Handle or forward the exception
182 AnalysisEngine.getInstance().getLogger().logError(exception);
183 }
184 node.setScriptElement(script);
185 scripts.add(script);
186 } else {
187 ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl (node);
188 if (scriptSourcePath != null) {
189 try {
190 scriptSourcePath = UriUtilities.encode(scriptSourcePath);
191 // Force an exception to be thrown if the URI is invalid so that we can report the
192 // problem.
193 new URI(scriptSourcePath);
194 Source scriptSource = context.getSourceFactory().resolveUri(
195 htmlSource,
196 scriptSourcePath);
197 script.setScriptSource(scriptSource);
198 if (scriptSource == null || !scriptSource.exists()) {
199 reportValueError(
200 HtmlWarningCode.URI_DOES_NOT_EXIST,
201 scriptAttribute,
202 scriptSourcePath);
203 }
204 } catch (URISyntaxException exception) {
205 reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, scrip tSourcePath);
206 }
207 }
208 node.setScriptElement(script);
209 scripts.add(script);
210 }
211 } finally {
212 parentNodes.remove(node);
213 }
214 return null;
215 }
216
217 @Override
166 public Void visitHtmlUnit(HtmlUnit node) { 218 public Void visitHtmlUnit(HtmlUnit node) {
167 parentNodes = new ArrayList<XmlTagNode>(); 219 parentNodes = new ArrayList<XmlTagNode>();
168 scripts = new ArrayList<HtmlScriptElement>(); 220 scripts = new ArrayList<HtmlScriptElement>();
169 try { 221 try {
170 node.visitChildren(this); 222 node.visitChildren(this);
171 htmlElement.setScripts(scripts.toArray(new HtmlScriptElement[scripts.size( )])); 223 htmlElement.setScripts(scripts.toArray(new HtmlScriptElement[scripts.size( )]));
172 } finally { 224 } finally {
173 scripts = null; 225 scripts = null;
174 parentNodes = null; 226 parentNodes = null;
175 } 227 }
176 return null; 228 return null;
177 } 229 }
178 230
179 @Override 231 @Override
180 public Void visitXmlAttributeNode(XmlAttributeNode node) { 232 public Void visitXmlAttributeNode(XmlAttributeNode node) {
233 for (EmbeddedExpression expression : node.getExpressions()) {
234 resolveExpression(expression.getExpression());
235 }
181 return null; 236 return null;
182 } 237 }
183 238
184 @Override 239 @Override
185 public Void visitXmlTagNode(XmlTagNode node) { 240 public Void visitXmlTagNode(XmlTagNode node) {
186 if (parentNodes.contains(node)) { 241 if (parentNodes.contains(node)) {
187 // 242 return reportCircularity(node);
188 // This should not be possible, but we have an error report that suggests that it happened at
189 // least once. This code will guard against infinite recursion and might h elp us identify the
190 // cause of the issue.
191 //
192 StringBuilder builder = new StringBuilder();
193 builder.append("Found circularity in XML nodes: ");
194 boolean first = true;
195 for (XmlTagNode pathNode : parentNodes) {
196 if (first) {
197 first = false;
198 } else {
199 builder.append(", ");
200 }
201 String tagName = pathNode.getTag().getLexeme();
202 if (pathNode == node) {
203 builder.append("*");
204 builder.append(tagName);
205 builder.append("*");
206 } else {
207 builder.append(tagName);
208 }
209 }
210 AnalysisEngine.getInstance().getLogger().logError(builder.toString());
211 return null;
212 } 243 }
213 parentNodes.add(node); 244 parentNodes.add(node);
214 try { 245 try {
215 if (isScriptNode(node)) { 246 for (EmbeddedExpression expression : node.getExpressions()) {
216 Source htmlSource = htmlElement.getSource(); 247 resolveExpression(expression.getExpression());
217 XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
218 String scriptSourcePath = scriptAttribute == null ? null : scriptAttribu te.getText();
219 if (node.getAttributeEnd().getType() == TokenType.GT && scriptSourcePath == null) {
220 EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementIm pl(node);
221 String contents = node.getContent();
222
223 //TODO (danrubel): Move scanning embedded scripts into AnalysisContext Impl
224 // so that clients such as builder can scan, parse, and get errors wit hout resolving
225 int attributeEnd = node.getAttributeEnd().getEnd();
226 Location location = lineInfo.getLocation(attributeEnd);
227 Scanner scanner = new Scanner(
228 htmlSource,
229 new SubSequenceReader(contents, attributeEnd),
230 errorListener);
231 scanner.setSourceStart(location.getLineNumber(), location.getColumnNum ber());
232 com.google.dart.engine.scanner.Token firstToken = scanner.tokenize();
233 int[] lineStarts = scanner.getLineStarts();
234
235 //TODO (danrubel): Move parsing embedded scripts into AnalysisContextI mpl
236 // so that clients such as builder can scan, parse, and get errors wit hout resolving
237 Parser parser = new Parser(htmlSource, errorListener);
238 CompilationUnit unit = parser.parseCompilationUnit(firstToken);
239 // unit.setLineInfo(new LineInfo(lineStarts));
240
241 try {
242 LibraryResolver resolver = new LibraryResolver(context);
243 LibraryElementImpl library = (LibraryElementImpl) resolver.resolveEm beddedLibrary(
244 htmlSource,
245 modificationStamp,
246 unit,
247 true);
248 script.setScriptLibrary(library);
249 resolvedLibraries.addAll(resolver.getResolvedLibraries());
250 errorListener.addAll(resolver.getErrorListener());
251 } catch (AnalysisException exception) {
252 //TODO (danrubel): Handle or forward the exception
253 AnalysisEngine.getInstance().getLogger().logError(exception);
254 }
255 scripts.add(script);
256 } else {
257 ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementIm pl(node);
258 if (scriptSourcePath != null) {
259 try {
260 scriptSourcePath = UriUtilities.encode(scriptSourcePath);
261 // Force an exception to be thrown if the URI is invalid so that w e can report the
262 // problem.
263 new URI(scriptSourcePath);
264 Source scriptSource = context.getSourceFactory().resolveUri(
265 htmlSource,
266 scriptSourcePath);
267 script.setScriptSource(scriptSource);
268 if (scriptSource == null || !scriptSource.exists()) {
269 reportValueError(
270 HtmlWarningCode.URI_DOES_NOT_EXIST,
271 scriptAttribute,
272 scriptSourcePath);
273 }
274 } catch (URISyntaxException exception) {
275 reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, scr iptSourcePath);
276 }
277 }
278 scripts.add(script);
279 }
280 } else {
281 node.visitChildren(this);
282 } 248 }
249 node.visitChildren(this);
283 } finally { 250 } finally {
284 parentNodes.remove(node); 251 parentNodes.remove(node);
285 } 252 }
286 return null; 253 return null;
287 } 254 }
288 255
289 /** 256 /**
290 * Return the first source attribute for the given tag node, or {@code null} i f it does not exist. 257 * Return the first source attribute for the given tag node, or {@code null} i f it does not exist.
291 * 258 *
292 * @param node the node containing attributes 259 * @param node the node containing attributes
293 * @return the source attribute contained in the given tag 260 * @return the source attribute contained in the given tag
294 */ 261 */
295 private XmlAttributeNode getScriptSourcePath(XmlTagNode node) { 262 private XmlAttributeNode getScriptSourcePath(XmlTagNode node) {
296 for (XmlAttributeNode attribute : node.getAttributes()) { 263 for (XmlAttributeNode attribute : node.getAttributes()) {
297 if (attribute.getName().getLexeme().equals(SRC)) { 264 if (attribute.getName().getLexeme().equals(SRC)) {
298 return attribute; 265 return attribute;
299 } 266 }
300 } 267 }
301 return null; 268 return null;
302 } 269 }
303 270
271 private Void reportCircularity(XmlTagNode node) {
272 //
273 // This should not be possible, but we have an error report that suggests th at it happened at
274 // least once. This code will guard against infinite recursion and might hel p us identify the
275 // cause of the issue.
276 //
277 StringBuilder builder = new StringBuilder();
278 builder.append("Found circularity in XML nodes: ");
279 boolean first = true;
280 for (XmlTagNode pathNode : parentNodes) {
281 if (first) {
282 first = false;
283 } else {
284 builder.append(", ");
285 }
286 String tagName = pathNode.getTag().getLexeme();
287 if (pathNode == node) {
288 builder.append("*");
289 builder.append(tagName);
290 builder.append("*");
291 } else {
292 builder.append(tagName);
293 }
294 }
295 AnalysisEngine.getInstance().getLogger().logError(builder.toString());
296 return null;
297 }
298
304 /** 299 /**
305 * Determine if the specified node is a Dart script.
306 *
307 * @param node the node to be tested (not {@code null})
308 * @return {@code true} if the node is a Dart script
309 */
310 private boolean isScriptNode(XmlTagNode node) {
311 if (node.getTagNodes().size() != 0 || !node.getTag().getLexeme().equals(SCRI PT)) {
312 return false;
313 }
314 for (XmlAttributeNode attribute : node.getAttributes()) {
315 if (attribute.getName().getLexeme().equals(TYPE)) {
316 Token valueToken = attribute.getValue();
317 if (valueToken != null) {
318 String value = valueToken.getLexeme();
319 if (value.equals(APPLICATION_DART_IN_DOUBLE_QUOTES)
320 || value.equals(APPLICATION_DART_IN_SINGLE_QUOTES)) {
321 return true;
322 }
323 }
324 }
325 }
326 return false;
327 }
328
329 /**
330 * Report an error with the given error code at the given location. Use the gi ven arguments to 300 * Report an error with the given error code at the given location. Use the gi ven arguments to
331 * compose the error message. 301 * compose the error message.
332 * 302 *
333 * @param errorCode the error code of the error to be reported 303 * @param errorCode the error code of the error to be reported
334 * @param offset the offset of the first character to be highlighted 304 * @param offset the offset of the first character to be highlighted
335 * @param length the number of characters to be highlighted 305 * @param length the number of characters to be highlighted
336 * @param arguments the arguments used to compose the error message 306 * @param arguments the arguments used to compose the error message
337 */ 307 */
338 private void reportError(ErrorCode errorCode, int offset, int length, Object.. . arguments) { 308 private void reportError(ErrorCode errorCode, int offset, int length, Object.. . arguments) {
339 errorListener.onError(new AnalysisError( 309 errorListener.onError(new AnalysisError(
(...skipping 12 matching lines...) Expand all
352 * @param offset the offset of the first character to be highlighted 322 * @param offset the offset of the first character to be highlighted
353 * @param length the number of characters to be highlighted 323 * @param length the number of characters to be highlighted
354 * @param arguments the arguments used to compose the error message 324 * @param arguments the arguments used to compose the error message
355 */ 325 */
356 private void reportValueError(ErrorCode errorCode, XmlAttributeNode attribute, 326 private void reportValueError(ErrorCode errorCode, XmlAttributeNode attribute,
357 Object... arguments) { 327 Object... arguments) {
358 int offset = attribute.getValue().getOffset() + 1; 328 int offset = attribute.getValue().getOffset() + 1;
359 int length = attribute.getValue().getLength() - 2; 329 int length = attribute.getValue().getLength() - 2;
360 reportError(errorCode, offset, length, arguments); 330 reportError(errorCode, offset, length, arguments);
361 } 331 }
332
333 private void resolveExpression(Expression expression) {
334 // TODO(brianwilkerson) Implement this. We need to figure out the right cont ext in which to
335 // resolve the expression.
336 }
362 } 337 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698