/*
* This file is part of the OpenJML project.
* Author: David R. Cok
*/
package com.sun.tools.javac.parser;
import org.jmlspecs.annotation.NonNull;
import org.jmlspecs.annotation.Nullable;
import org.jmlspecs.openjml.JmlTree;
import org.jmlspecs.openjml.Utils;
import com.sun.tools.javac.code.Symtab;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.comp.JmlAttr;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.Log.WriterKind;
/* FIXME - do more to implement extensions */
/* TODO - needs documentation */
abstract public class StatementExtension {
protected static final Context.Key<StatementExtension> statementExtensionsKey =
new Context.Key<StatementExtension>();
/** The compilation context, set when derived classes are instantiated */
protected /*@ non_null */ Context context;
/** The parser in use, set when derived classes are instantiated */
protected /*@ non_null */ JmlParser parser;
/** The scanner in use, set when derived classes are instantiated */
protected /*@ non_null */ JmlScanner scanner;
protected /*@ non_null */ JmlTree.Maker jmlF;
/** The symbol table, set when the context is set */
protected Symtab syms;
/** The Utils instance */
protected Utils utils;
//@ public constraint context == \old(context);
/** A constructor needed by derived classes; this class should not be
* instantiated directly by users.
*/
protected StatementExtension(Context context) {
this.context = context;
this.syms = Symtab.instance(context);
this.utils = Utils.instance(context);
}
/** Writes an error message to the log, using the given DiagnosticPosition
* (typically gotten from tree.pos()),
* a key (as in the file org.jmlspecs.openjml.messages.properties)
* and arguments for that key
* @param pos the DiagnosticPosition used to identify the relevant location in the source file
* @param key the resource key holding the error message
* @param args (non-null) arguments for the key - there must be at least as many arguments as there are place-holders in the key string
*/
public void error(DiagnosticPosition pos, String key, Object ... args) {
Log.instance(context).error(pos,key,args);
}
/** Writes a warning message to the log, using the given DiagnosticPosition
* (typically gotten from tree.pos()), a key (as in the file org.jmlspecs.openjml.messages.resources)
* and arguments for that key
* @param pos the DiagnosticPosition used to identify the relevant location in the source file
* @param key the resource key holding the error message
* @param args (non-null) arguments for the key - there must be at least as many arguments as there are place-holders in the key string
*/
public void warning(DiagnosticPosition pos, String key, Object ... args) {
Log.instance(context).warning(pos,key,args);
}
/** Writes an informational message to the log's noticeWriter (as with
* println). To be used for informational or debugging information.
* @param msg the String to write
*/
public void info(@NonNull String msg) {
Log.instance(context).getWriter(WriterKind.NOTICE).println(msg);
}
/** Sets the end position of the given tree node to be the end position of
* the previously scanned token.
* @param <T> the type of the node being set
* @param tree the node whose end position is being set
* @return returns the same node
*/
public <T extends JCTree> T toP(T tree) {
return parser.toP(tree);
}
/** Called by JmlParser when it sees the token for this extension.
* The derived class implementation is responsible to scan tokens using
* the scanner (JmlParser.getScanner()) and return a JCExpression parse
* tree. When called, the current scanner token is the JmlToken itself;
* this method is responsible to scan the end of the expression (e.g. the
* terminating parenthesis) and no more. If an error occurs because of
* badly formed input, the method is required to return null and to
* recover as best it can. [ FIXME - return JCErroneous?]
* <BR>Useful methods:
* <BR>JmlParser.getScanner() - returns the current JmlScanner
* <BR>JmlScanner.token() - the current Java token, or CUSTOM if a JML token
* <BR>JmlScanner.jmlToken() - the current JML token (null if a Java token)
* <BR>JmlScanner.nextToken() - scans the next token
* <BR>JmlScanner.pos() - the current character position, used for error reporting
* <BR>JmlParser.syntaxError(...) - to report a parsing error
* <BR>TODO: warning and error and informational messages
* <BR>TODO: maker(), at(), primarySuffix, toP(), arguments(), others
*
* @param parser the JmlParser for this compilation unit and compilation context
* @param typeArgs any type arguments already seen (may be null)
* @return the AST for the expression
*/
abstract public JCStatement parse(JmlParser parser);
protected void init(JmlParser parser) {
this.parser = parser;
this.scanner = parser.getScanner();
this.jmlF = parser.maker();
}
// TODO: document
abstract public Type typecheck(JmlAttr attr, JCExpression expr, Env<AttrContext> env);
}