/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.ecmascript.ast;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.mozilla.javascript.CompilerEnvirons;
import org.mozilla.javascript.Parser;
import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.Comment;
import org.mozilla.javascript.ast.ErrorCollector;
import org.mozilla.javascript.ast.ParseProblem;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ecmascript.EcmascriptParserOptions;
public class EcmascriptParser {
protected final EcmascriptParserOptions parserOptions;
private Map<Integer, String> suppressMap;
private String suppressMarker = "NOPMD"; // that's the default value
public EcmascriptParser(EcmascriptParserOptions parserOptions) {
this.parserOptions = parserOptions;
if (parserOptions.getSuppressMarker() != null) {
suppressMarker = parserOptions.getSuppressMarker();
}
}
protected AstRoot parseEcmascript(final String sourceCode, final List<ParseProblem> parseProblems)
throws ParseException {
final CompilerEnvirons compilerEnvirons = new CompilerEnvirons();
compilerEnvirons.setRecordingComments(parserOptions.isRecordingComments());
compilerEnvirons.setRecordingLocalJsDocComments(parserOptions.isRecordingLocalJsDocComments());
compilerEnvirons.setLanguageVersion(parserOptions.getRhinoLanguageVersion().getVersion());
// Scope's don't appear to get set right without this
compilerEnvirons.setIdeMode(true);
compilerEnvirons.setWarnTrailingComma(true);
// see bug #1150 "EmptyExpression" for valid statements!
compilerEnvirons.setReservedKeywordAsIdentifier(true);
// TODO We should do something with Rhino errors...
final ErrorCollector errorCollector = new ErrorCollector();
final Parser parser = new Parser(compilerEnvirons, errorCollector);
// TODO Fix hardcode
final String sourceURI = "unknown";
final int beginLineno = 1;
AstRoot astRoot = parser.parse(sourceCode, sourceURI, beginLineno);
parseProblems.addAll(errorCollector.getErrors());
return astRoot;
}
public EcmascriptNode<AstRoot> parse(final Reader reader) {
try {
final List<ParseProblem> parseProblems = new ArrayList<>();
final String sourceCode = IOUtils.toString(reader);
final AstRoot astRoot = parseEcmascript(sourceCode, parseProblems);
final EcmascriptTreeBuilder treeBuilder = new EcmascriptTreeBuilder(sourceCode, parseProblems);
EcmascriptNode<AstRoot> tree = treeBuilder.build(astRoot);
suppressMap = new HashMap<>();
if (astRoot.getComments() != null) {
for (Comment comment : astRoot.getComments()) {
int nopmd = comment.getValue().indexOf(suppressMarker);
if (nopmd > -1) {
String suppression = comment.getValue().substring(nopmd + suppressMarker.length());
EcmascriptNode<Comment> node = treeBuilder.build(comment);
suppressMap.put(node.getBeginLine(), suppression);
}
}
}
return tree;
} catch (IOException e) {
throw new ParseException(e);
}
}
public Map<Integer, String> getSuppressMap() {
return suppressMap;
}
}