/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* This file was originally derived from the Polyglot extensible compiler framework.
*
* (C) Copyright 2000-2007 Polyglot project group, Cornell University
* (C) Copyright IBM Corporation 2007-2012.
*/
package polyglot.main;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Stack;
import polyglot.util.ErrorInfo;
import polyglot.util.ErrorQueue;
import polyglot.util.Position;
import polyglot.util.SimpleErrorQueue;
import polyglot.util.CollectionUtil;
import x10.util.CollectionFactory;
/** Class used for reporting debug messages. */
public class Reporter {
/**
* A collection of string names of topics which can be used with the -report
* command-line switch
*/
public final Collection<String> topics = CollectionFactory.newHashSet();
/**
* A collection of string names of topics which we should always check if we
* should report.
*/
protected Stack<String> stackedTopics;
/**
* The topics that the user has selected to report, mapped to the level they
* want to report them to.
*/
// This is teporarily public so that Report can get at it.
public final Map<String, Integer> reportTopics = CollectionFactory.newHashMap(); // Map[String,
// protected final Map<String, Integer> reportTopics = CollectionFactory.newHashMap(); // Map[String,
// Integer]
/** Error queue to which to write messages. */
protected ErrorQueue eq;
/**
* Indicates if there is no reporting at all. The normal case is that we do
* not report anything, so for efficiency reasons, since
* <code>should_report</code> is called so often, we'll use this flag to
* bypass a lot of the checking. When the options are processed, this flag
* should be changed.
*/
protected boolean noReporting = true;
/** Report topics understood by the base compiler. */
public final static String cfg = "cfg";
public final static String context = "context";
public final static String dataflow = "dataflow";
public final static String errors = "errors";
public final static String frontend = "frontend";
public final static String imports = "imports";
public final static String innerremover = "innerremover";
public final static String InstanceInvariantChecker = "InstanceInvariantChecker";
public final static String PositionInvariantChecker = "PositionInvariantChecker";
public final static String loader = "loader";
public final static String nativeclass = "nativeclass";
public final static String resolver = "resolver";
public final static String serialize = "serialize";
public final static String specificity = "specificity";
public final static String sysresolver = "sysresolver";
public final static String time = "time";
/**
* threshold specifies a percentage. Only report time that takes more than
* the percent of total time specified by this threshold.
*/
public final static String threshold = "threshold";
public final static String frequency = "frequency";
public final static String types = "types";
public final static String visit = "visit";
public final static String verbose = "verbose";
// This topic is the level of detail that should be in messages.
public final static String debug = "debug";
public Reporter() {
topics.add(cfg);
topics.add(context);
topics.add(dataflow);
topics.add(errors);
topics.add(frontend);
topics.add(imports);
topics.add(loader);
topics.add(resolver);
topics.add(serialize);
topics.add(specificity);
topics.add(time);
topics.add(threshold);
topics.add(frequency);
topics.add(types);
topics.add(visit);
topics.add(verbose);
topics.add(debug);
}
/**
* Return whether a message on <code>topic</code> of obscurity
* <code>level</code> should be reported, based on use of the -report
* command-line switches given by the user.
*/
public boolean should_report(String topic, int level) {
if (noReporting) return false;
return should_report(Collections.singletonList(topic), level);
}
/**
* Return whether a message on <code>topics</code> of obscurity
* <code>level</code> should be reported, based on use of the -report
* command-line switches given by the user.
*/
public boolean should_report(Collection<String> topics, int level) {
if (noReporting) return false;
if (stackedTopics != null) {
for (String topic : stackedTopics) {
if (level(topic) >= level) return true;
}
}
if (topics != null) {
for (String topic : topics) {
if (level(topic) >= level) return true;
}
}
return false;
}
/**
* Start reporting messages on <code>topic</code>.
*/
public void start_reporting(String topic) {
if (noReporting) return;
if (should_report(topic, 1)) {
if (stackedTopics == null) stackedTopics = new Stack<String>();
stackedTopics.push(topic);
}
}
/**
* Stop reporting messages on <code>topic</code>.
*/
public void stop_reporting(String topic) {
if (stackedTopics == null) return;
stackedTopics.remove(topic);
}
/** Add a topic to report */
public void addTopic(String topic, int level) {
Integer i = (Integer) reportTopics.get(topic);
if (i == null || i.intValue() < level) {
reportTopics.put(topic, new Integer(level));
}
noReporting = false;
}
/** Remove a topic to report */
public void removeTopic(String topic) {
reportTopics.remove(topic);
if (reportTopics.isEmpty()) {
noReporting = true;
}
}
/** Get the error queue, possibly creating it if not set. */
public ErrorQueue getQueue() {
if (eq == null) {
eq = new SimpleErrorQueue();
}
return eq;
}
/** Set the error queue. */
public void setQueue(ErrorQueue eq) {
this.eq = eq;
}
public int level(String name) {
Object i = reportTopics.get(name);
if (i == null)
return 0;
else
return ((Integer) i).intValue();
}
/**
* This is the standard way to report debugging information in the compiler.
* It reports a message of the specified level (which controls the
* presentation of the message. To test whether such message should be
* reported, use "should_report".
*
* NOTE: This is a change of spec from earlier versions of Report. NOTE: If
* position information is available, call report(int, String, Position)
* instead, to ensure the error is associated with the right file/location.
*/
public void report(int level, String message) {
report(level, message, null);
}
/**
* This is the standard way to report debugging information in the compiler.
* It reports a message of the specified level (which controls the
* presentation of the message. To test whether such message should be
* reported, use "should_report".
*
* NOTE: This is a change of spec from earlier versions of Report. NOTE:
* This version takes an explicit Position, so that position info gets
* properly associated with the ErrorInfo that gets created by enqueue().
*/
public void report(int level, String message, Position pos) {
StringBuffer buf = new StringBuffer(message.length() + level);
for (int j = 1; j < level; j++) {
buf.append(" ");
}
buf.append(message);
getQueue().enqueue(ErrorInfo.DEBUG, buf.toString(), pos);
}
}