/*******************************************************************************
* Copyright (c) 2007, 2008 Edgar Espina.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.deved.antlride.internal.core.builder;
import static org.deved.antlride.core.AntlrConstants.ANTLR_BUILDER_RUNTIME;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.deved.antlride.core.AntlrConfiguration;
import org.deved.antlride.core.AntlrConstants;
import org.deved.antlride.core.AntlrCore;
import org.deved.antlride.core.AntlrLanguageTargetName;
import org.deved.antlride.core.AntlrLanguageToolkit;
import org.deved.antlride.core.build.AntlrBuildUnit;
import org.deved.antlride.core.build.AntlrSourceParserRepository;
import org.deved.antlride.core.integration.AntlrLanguageTargetService;
import org.deved.antlride.core.model.GrammarType;
import org.deved.antlride.core.model.IGrammar;
import org.deved.antlride.core.model.dltk.ast.DASTGrammar;
import org.deved.antlride.core.resources.AntlrLanguageTarget;
import org.deved.antlride.core.resources.AntlrLanguageTargetRepository;
import org.deved.antlride.core.resources.AntlrPackage;
import org.deved.antlride.core.resources.AntlrPackages;
import org.deved.antlride.core.util.AntlrTextHelper;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.dltk.compiler.problem.ProblemSeverities;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.builder.IBuildContext;
import org.eclipse.dltk.core.builder.ISourceLineTracker;
import org.eclipse.dltk.utils.TextUtils;
public class DefaultAntlrBuildUnit implements AntlrBuildUnit {
public static final String ID = DefaultAntlrBuildUnit.class.getName();
private static final String ANTLR_GEN_RESOURCE_PREFIX = "___antlr_gen__resource_";
private static final String ANTLR_ROOT_PREFIX = "___antlr___root_";
private static final String ANTLR_DEPENDENT_PREFIX = "___antlr___dependent_";
private static final QualifiedName GENERATED_RESOURCES = new QualifiedName(
AntlrCore.PLUGIN_ID, "___generated_resources_");
private static final QualifiedName ROOTS = new QualifiedName(
AntlrCore.PLUGIN_ID, "___roots_");
private static final QualifiedName DEPENDENTS = new QualifiedName(
AntlrCore.PLUGIN_ID, "___dependents_");
private static final String SYS_PROPERTY = "-D%s=%s";
protected IFile file;
protected IGrammar grammar;
protected AntlrConfiguration configuration;
private AntlrPackage antlrPackage;
private IPath outputPath;
protected IWorkspaceRoot workspaceRoot;
private IContainer outputContainer;
private Collection<IResource> excludedResources;
private IProgressMonitor monitor;
private Collection<String> generatedResources;
public Collection<String> addSystemProperties;
private IPath absoluteLibFolder;
protected char[] contents;
protected ISourceLineTracker lineTracker;
private IPath libFolder;
private String description;
public DefaultAntlrBuildUnit(IBuildContext buildContext) {
DASTGrammar ast = (DASTGrammar) buildContext
.get(IBuildContext.ATTR_MODULE_DECLARATION);
if (ast != null) {
grammar = ast.getGrammar();
}
if (grammar == null) {
// forced? why???
grammar = AntlrSourceParserRepository.getGrammar(buildContext
.getSourceModule());
}
init(buildContext.getFile());
loadGeneratedResources();
lineTracker = buildContext.getLineTracker();
contents = buildContext.getContents();
}
public DefaultAntlrBuildUnit(ISourceModule sourceModule) {
grammar = AntlrSourceParserRepository.getGrammar(sourceModule);
init((IFile) sourceModule.getResource());
try {
contents = sourceModule.getSourceAsCharArray();
} catch (ModelException e) {
contents = new char[0];
AntlrCore.error(e);
}
lineTracker = TextUtils.createLineTracker(contents);
}
public DefaultAntlrBuildUnit(IGrammar grammar) {
this.grammar = grammar;
IFile resource = ResourcesPlugin.getWorkspace().getRoot()
.getFile(grammar.getFile());
init(resource);
}
private void init(IFile file) {
this.file = file;
configuration = new AntlrConfiguration(file);
String packageName = configuration.getOption(ANTLR_BUILDER_RUNTIME);
antlrPackage = AntlrPackages.getPackage(packageName);
if (antlrPackage == null && packageName != null
&& packageName.length() > 0) {
throw new IllegalStateException("Invalid package: ANTLR-"
+ packageName);
}
workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
excludedResources = new ArrayList<IResource>();
addSystemProperties = new HashSet<String>();
monitor = new NullProgressMonitor();
try {
file.setPersistentProperty(AntlrConstants.Q_ANTLR_GRAMMAR_TYPE,
grammar.getGrammarType().name());
} catch (CoreException e) {
e.printStackTrace();
}
}
public Set<IFile> getRoots() {
return readFilesFromPersistentProperty(getFile(), ROOTS,
ANTLR_ROOT_PREFIX);
}
private Set<IFile> readFilesFromPersistentProperty(IFile owner,
QualifiedName property, String prefix) {
int count;
try {
count = Integer.parseInt(owner.getPersistentProperty(property));
} catch (Exception ex) {
count = 0;
}
Set<IFile> files = new HashSet<IFile>(count);
for (int i = 0; i < count; i++) {
QualifiedName qname = new QualifiedName(AntlrCore.PLUGIN_ID, prefix
+ i);
String path;
try {
path = owner.getPersistentProperty(qname);
} catch (CoreException e) {
path = null;
}
if (path != null) {
IFile f = workspaceRoot.getFile(Path.fromPortableString(path));
if (f.exists()) {
files.add(f);
}
}
}
return files;
}
private void saveFilesToPersistentProperty(IFile owner, Set<IFile> files,
QualifiedName property, String prefix) {
int count = 0;
for (IFile file : files) {
if (file.exists()) {
try {
QualifiedName qname = new QualifiedName(
AntlrCore.PLUGIN_ID, prefix + count);
owner.setPersistentProperty(qname, file.getFullPath()
.toString());
count++;
} catch (CoreException e) {
e.printStackTrace();
}
}
}
try {
if (ANTLR_ROOT_PREFIX.equals(prefix)) {
// dependent grammar mark as dependent
owner.setPersistentProperty(DEPENDENT_GRAMMAR, "true");
}
owner.setPersistentProperty(property, "" + count);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void setDependents(Set<IFile> dependents) {
IFile owner = getFile();
saveFilesToPersistentProperty(owner, dependents, DEPENDENTS,
ANTLR_DEPENDENT_PREFIX);
// set the root grammar
for (IFile file : dependents) {
if (file.exists()) {
Set<IFile> roots = readFilesFromPersistentProperty(file, ROOTS,
ANTLR_ROOT_PREFIX);
roots.add(owner);
saveFilesToPersistentProperty(file, roots, ROOTS,
ANTLR_ROOT_PREFIX);
}
}
}
public Set<IFile> getDependents() {
return readFilesFromPersistentProperty(getFile(), DEPENDENTS,
ANTLR_DEPENDENT_PREFIX);
}
public void addSystemProperty(String name, Object value) {
addSystemProperties.add(systemProperty(name, value));
}
public Collection<String> getSystemProperties() {
Collection<String> list = new HashSet<String>();
list.add(systemProperty("gERROR", ProblemSeverities.Error.ordinal()));
list.add(systemProperty("gWARNING", ProblemSeverities.Warning.ordinal()));
list.add(systemProperty("gFILE", getPath().lastSegment()));
list.add(systemProperty("gINCLUDE_STACKTRACE",
configuration.getIncludeStackStraceOnInternalErrors()));
list.add(systemProperty("gout", getOutputFolder().toOSString()));
// additional properties
list.addAll(addSystemProperties);
return list;
}
public char[] getContents() {
return contents;
}
public ISourceLineTracker getLineTracker() {
return lineTracker;
}
public String getBuildClassName() {
return "org.deved.antlride.runtime.Tool2";
}
public IPath getAbsoluteLibraryPath() {
if (absoluteLibFolder == null) {
absoluteLibFolder = getOutputFolder();
IFile tokenVocabFile = getTokenVocabFile();
if (tokenVocabFile != null) {
absoluteLibFolder = tokenVocabFile.getParent().getLocation();
}
File file = absoluteLibFolder.toFile();
if (!file.exists()) {
file.mkdirs();
}
}
return absoluteLibFolder;
}
public IPath getLibraryPath() {
if (libFolder == null) {
libFolder = getOutputContainer().getFullPath();
IFile tokenVocabFile = getTokenVocabFile();
if (tokenVocabFile != null) {
libFolder = tokenVocabFile.getParent().getFullPath();
}
File file = libFolder.toFile();
if (!file.exists()) {
file.mkdirs();
}
}
return libFolder;
}
public Collection<? extends String> getApplicationArgs() {
List<String> args = new ArrayList<String>();
if (configuration.getNfa()) {
args.add("-nfa");
}
if (configuration.getDfa()) {
args.add("-dfa");
}
if (configuration.getReport()) {
args.add("-report");
}
if (configuration.getProfile()) {
args.add("-profile");
}
// -Xdfaverbose
if (configuration.getXDfaVerbose()) {
args.add("-Xdfaverbose");
}
// -Xnoprune
if (configuration.getXNoPrune()) {
args.add("-Xnoprune");
}
// -Xnocollapse
if (configuration.getXNoCollapse()) {
args.add("-Xnocollapse");
}
// -Xnomergestopstates
if (configuration.getXNoMergeStopStates()) {
args.add("-Xnomergestopstates");
}
// -debug
if (configuration.getDebug()) {
args.add("-debug");
}
// -trace
if (configuration.getTrace()) {
args.add("-trace");
}
// -XdbgST
if (configuration.getXdbgSt()) {
args.add("-XdbgST");
}
// -Xm
String Xm = configuration.getOption(AntlrConstants.ANTLR_BUILDER_X_M);
if (!"4".equals(Xm)) {
// not the default value
args.add("-Xm");
args.add(Xm);
}
// - Xmaxdfaedges
String Xmaxdfaedges = configuration
.getOption(AntlrConstants.ANTLR_BUILDER_X_MAX_DFA_EDGES);
if (!"65534".equals(Xmaxdfaedges)) {
// not the default value
args.add("-Xmaxdfaedges");
args.add(Xmaxdfaedges);
}
// -Xconversiontimeout
String Xconversiontimeout = configuration
.getOption(AntlrConstants.ANTLR_BUILDER_X_CONVERSION_TIME_OUT);
if (!"1000".equals(Xconversiontimeout)) {
// not the default value
args.add("-Xconversiontimeout");
args.add(Xconversiontimeout);
}
// -Xmaxswitchcaselabels
String Xmaxswitchcaselabels = configuration
.getOption(AntlrConstants.ANTLR_CODE_GENERATOR_X_MAX_SWITCH_CASE_LABELS);
if (!"300".equals(Xmaxswitchcaselabels)) {
// not the default value
args.add("-Xmaxswitchcaselabels");
args.add(Xmaxswitchcaselabels);
}
// -Xminswitchalts
String Xminswitchalts = configuration
.getOption(AntlrConstants.ANTLR_CODE_GENERATOR_X_MIN_SWITCH_ALTS);
if (!"3".equals(Xminswitchalts)) {
// not the default value
args.add("-Xminswitchalts");
args.add(Xminswitchalts);
}
return args;
}
public IFile getTokenVocabFile() {
if (grammar.isParserGrammar() || grammar.isTreeParserGrammar()) {
String tokenVocab = grammar.getOption("tokenVocab");
if (tokenVocab != null && tokenVocab.length() > 0) {
return AntlrSourceParserRepository.lookupFile(
grammar.getFolder(), tokenVocab + ".g");
}
}
return null;
}
public IFile[] getDependencies() {
Collection<IFile> deps = new HashSet<IFile>();
if (grammar.isPrototypeGrammar()) {
Set<IFile> roots = getRoots();
if (roots.size() > 0) {
IFile rootFile = roots.iterator().next();
deps.addAll(readFilesFromPersistentProperty(rootFile,
DEPENDENTS, ANTLR_DEPENDENT_PREFIX));
}
} else if (grammar.hasImports()) {
// composite
deps.addAll(readFilesFromPersistentProperty(file, DEPENDENTS,
ANTLR_DEPENDENT_PREFIX));
}
return deps.toArray(new IFile[deps.size()]);
}
private int getGeneratedResourceCount() {
int genResourceCount;
try {
String s = getOwner().getPersistentProperty(GENERATED_RESOURCES);
genResourceCount = Integer.parseInt(s);
} catch (NumberFormatException ex) {
genResourceCount = 0;
} catch (NullPointerException ex) {
genResourceCount = 0;
} catch (CoreException ex) {
genResourceCount = 0;
}
return genResourceCount;
}
private void setGeneratedResourceCount(int count) throws CoreException {
file.setPersistentProperty(GENERATED_RESOURCES, Integer.toString(count));
}
private IFile getOwner() {
IFile file = getFile();
try {
if (getGrammar().isPrototypeGrammar()) {
Set<IFile> roots = getRoots();
if (roots.size() > 0) {
file = roots.iterator().next();
}
}
} catch (Exception ex) {
AntlrCore.error("Couldn't get owner for " + file, ex);
}
return file;
}
private void loadGeneratedResources() {
int genResourceCount = getGeneratedResourceCount();
generatedResources = new ArrayList<String>();
IFile file = getOwner();
for (int i = 0; i < genResourceCount; i++) {
try {
QualifiedName qname = new QualifiedName(AntlrCore.PLUGIN_ID,
ANTLR_GEN_RESOURCE_PREFIX + i);
generatedResources.add(file.getPersistentProperty(qname));
} catch (CoreException e) {
e.printStackTrace();
}
}
try {
file.setPersistentProperty(GENERATED_RESOURCES, "0");
} catch (CoreException e) {
e.printStackTrace();
}
}
public void cleanupResources() {
for (String path : generatedResources) {
try {
IFile genfile = workspaceRoot.getFile(new Path(path));
genfile.delete(true, monitor);
} catch (CoreException ex) {
AntlrCore.error(ex);
}
}
}
public boolean isGeneratedResource(IResource resource) {
boolean generated = false;
try {
String owner = resource
.getPersistentProperty(AntlrConstants.Q_ANTLR_RESOURCE_OWNER);
if (owner != null) {
generated = getPath().lastSegment().equals(
new Path(owner).lastSegment());
if (!generated && getGrammar().isPrototypeGrammar()) {
Set<IFile> roots = getRoots();
if (roots.size() > 0) {
generated = roots.iterator().next().getFullPath()
.lastSegment()
.equals(new Path(owner).lastSegment());
}
}
}
} catch (CoreException ex) {
AntlrCore.error(ex);
}
return generated;
}
public void excludeResource(IResource resource) {
excludedResources.add(resource);
}
public IProgressMonitor getMonitor() {
return monitor;
}
public IContainer getOutputContainer() {
if (outputContainer == null) {
outputContainer = workspaceRoot
.getContainerForLocation(getOutputFolder());
}
return outputContainer;
}
public boolean markAsGeneratedResource(IResource resource) {
if (!excludedResources.contains(resource) && resource instanceof IFile) {
try {
boolean derived = configuration.getMarkResourcesAsDerived();
resource.setDerived(derived);
IPath owner = getOwner().getFullPath();
resource.setPersistentProperty(
AntlrConstants.Q_ANTLR_RESOURCE_OWNER, owner.toString());
// register generated resource at grammar file
registerGeneratedResource(resource);
return true;
} catch (CoreException ex) {
AntlrCore.error(ex);
}
}
return false;
}
private void registerGeneratedResource(IResource resource) {
try {
int nextResource = getGeneratedResourceCount();
QualifiedName qname = new QualifiedName(AntlrCore.PLUGIN_ID,
ANTLR_GEN_RESOURCE_PREFIX + nextResource);
file.setPersistentProperty(qname, resource.getFullPath().toString());
setGeneratedResourceCount(nextResource + 1);
} catch (CoreException ex) {
AntlrCore.error(ex);
}
}
public String getPackageClasspath() {
return antlrPackage.getClasspathAsString();
}
public String getClasspath() {
String language = grammar.getOption("language");
AntlrLanguageTargetService languageTargetService = AntlrLanguageToolkit
.getDefault().getLanguageTargetService(language);
String[] projectClasspath = null;
if (languageTargetService != null) {
try {
Map<String, Object> classpathInformation = languageTargetService
.getClasspathInformation(new NullProgressMonitor(),
this);
projectClasspath = (String[]) classpathInformation
.get("classpath");
description = (String) classpathInformation.get("description");
} catch (CoreException e) {
AntlrCore.error(e);
}
}
StringBuilder classpath = new StringBuilder();
// use the defined packages
// add custom target
AntlrLanguageTarget[] languageTargets = AntlrLanguageTargetRepository
.list();
for (AntlrLanguageTarget antlrLanguageTarget : languageTargets) {
classpath.append(antlrLanguageTarget.getPath());
classpath.append(File.pathSeparator);
}
if (projectClasspath != null) {
// use the project classpath
for (String classpathentry : projectClasspath) {
classpath.append(classpathentry);
classpath.append(File.pathSeparator);
}
classpath.setLength(classpath.length()
- File.pathSeparator.length());
return classpath.toString();
} else {
classpath.append(antlrPackage.getClasspathAsString());
}
return classpath.toString();
}
public IPath getOutputFolder() {
if (outputPath == null) {
// language
String lang = grammar.getOption("language");
// grammar type
GrammarType grammarType = grammar.getGrammarType();
// -o output dir
String outputDir = configuration.getOption("-o");
outputPath = Path.fromOSString(outputDir);
// append java package?
if (AntlrLanguageTargetRepository.likeLanguage(
AntlrLanguageTargetName.Java, lang)
&& configuration.getAppendJavaPackage()) {
String pathSuffix = null;
if (grammarType == GrammarType.LEXER) {
pathSuffix = AntlrTextHelper.getLexerJavaPackage(grammar);
} else {
pathSuffix = AntlrTextHelper.getJavaPackage(grammar);
}
if (pathSuffix != null && pathSuffix.length() > 0) {
outputPath = outputPath.append(pathSuffix.replace('.',
File.separatorChar));
}
}
File file = outputPath.toFile();
if (!file.exists()) {
file.mkdirs();
}
}
return outputPath;
}
public boolean canBuild() {
if (grammar == null)
return false;
if (antlrPackage == null)
return false;
if (grammar.isPrototypeGrammar()) {
return getRoots().size() > 0;
}
return true;
}
public AntlrConfiguration getConfiguration() {
return configuration;
}
public IFile getFile() {
return file;
}
public IGrammar getGrammar() {
return grammar;
}
public IContainer getFolder() {
return getFile().getParent();
}
public IPath getAbsolutePath() {
if (grammar.isPrototypeGrammar()) {
Set<IFile> roots = getRoots();
if (roots.size() > 0) {
return roots.iterator().next().getLocation();
}
}
return file.getLocation();
}
public IPath getPath() {
return file.getFullPath();
}
public IPath getFolderPath() {
return getFolder().getFullPath();
}
public IPath getAbsoluteFolderPath() {
return getFolder().getLocation();
}
public String getDescription() {
StringBuilder builder = new StringBuilder();
if (description == null) {
builder.append(antlrPackage.getDescription()).append(
".\nUsing project classpath: No.");
} else {
builder.append(description).append(
".\nUsing project classpath: Yes.");
}
return builder.toString();
}
public static String systemProperty(String name, Object value) {
return String.format(SYS_PROPERTY, name, value);
}
}