package bluej.parser.nodes;
import java.io.Reader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import bluej.debugger.gentype.GenTypeClass;
import bluej.debugger.gentype.Reflective;
import bluej.editor.moe.MoeSyntaxDocument;
import bluej.editor.moe.MoeSyntaxDocument.Element;
import bluej.editor.moe.Token;
import bluej.editor.moe.Token.TokenType;
import bluej.parser.ExpressionTypeInfo;
import bluej.parser.DocumentReader;
import bluej.parser.JavaParser;
import bluej.parser.TokenStream;
import bluej.parser.entity.EntityResolver;
import bluej.parser.entity.JavaEntity;
import bluej.parser.entity.PackageOrClass;
import bluej.parser.entity.ParsedReflective;
import bluej.parser.entity.TypeEntity;
import bluej.parser.entity.ValueEntity;
import bluej.parser.lexer.JavaLexer;
import bluej.parser.lexer.JavaTokenFilter;
import bluej.parser.lexer.JavaTokenTypes;
import bluej.parser.lexer.LocatableToken;
import bluej.parser.nodes.NodeTree.NodeAndPosition;
import bluej.utility.GeneralCache;
import threadchecker.OnThread;
import threadchecker.Tag;
| A ParentParsedNode extension with Java specific functionality.
| Amongst other things this extends the ParsedNode into an
| EntityResolver implementation.
|
| @author Davin McCall
|
public abstract class JavaParentNode
extends ParentParsedNode
implements EntityResolver{
protected GeneralCache<String,JavaEntity> valueEntityCache =
new GeneralCache<String,JavaEntity>(10);
protected GeneralCache<String,PackageOrClass> pocEntityCache =
new GeneralCache<String,PackageOrClass>(10);
protected JavaParentNode parentNode;
protected Map<String,ParsedNode> classNodes = new HashMap<>();
protected Map<String,Set<FieldNode>> variables = new HashMap<>();
public JavaParentNode(JavaParentNode parent)
{
super(parent);
parentNode = parent;
}
@Override
protected JavaParentNode getParentNode()
{
return parentNode;
}
@Override
public void insertNode(ParsedNode child, int position, int size)
{
getNodeTree().insertNode(child, position, size);
int childType = child.getNodeType();
String childName = child.getName();
if (childName != null) {
if (childType == NODETYPE_TYPEDEF) {
classNodes.put(childName, child);
}
}
}
| Insert a FieldNode representing a variable/field declaration into this node.
|
public void insertVariable(FieldNode varNode, int pos, int size)
{
super.insertNode(varNode, pos, size);
Set<FieldNode> varList = variables.get(varNode.getName());
if (varList == null) {
varList = new HashSet<FieldNode>(1);
variables.put(varNode.getName(), varList);
}
varList.add(varNode);
}
| Insert a field child (alias for insertVariable).
|
public void insertField(FieldNode child, int position, int size)
{
insertVariable(child, position, size);
}
@Override
public void childChangedName(ParsedNode child, String oldName)
{
super.childChangedName(child, oldName);
if (child.getNodeType() == NODETYPE_TYPEDEF) {
if (classNodes.get(oldName) == child) {
classNodes.remove(oldName);
}
classNodes.put(child.getName(), child);
}
if (child.getNodeType() == NODETYPE_FIELD) {
Set<FieldNode> varset = variables.get(oldName);
if (varset != null) {
varset.remove(child);
if (varset.isEmpty()) {
variables.remove(oldName);
}
}
varset = variables.get(child.getName());
if (varset == null) {
varset = new HashSet<>();
variables.put(child.getName(), varset);
}
varset.add((FieldNode) child);
}
}
@Override
protected void childRemoved(NodeAndPosition<ParsedNode> child,
NodeStructureListener listener)
{
super.childRemoved(child, listener);
String childName = child.getNode().getName();
if (childName != null) {
if (classNodes.get(childName) == child.getNode()) {
classNodes.remove(childName);
}
Set<FieldNode> varset = variables.get(childName);
if (varset != null) {
varset.remove(child.getNode());
if (varset.isEmpty())
{
variables.remove(childName);
}
}
}
}
| Find a type node for a type definition with the given name.
|
public ParsedNode getTypeNode(String name)
{
return classNodes.get(name);
}
|
| @see bluej.parser.entity.EntityResolver#resolveQualifiedClass(java.lang.String)
|
public TypeEntity resolveQualifiedClass(String name)
{
if (parentNode != null) {
return parentNode.resolveQualifiedClass(name);
}
return null;
}
|
| @see bluej.parser.entity.EntityResolver#resolvePackageOrClass(java.lang.String, java.lang.String)
|
public PackageOrClass resolvePackageOrClass(String name, Reflective querySource)
{
ParsedNode cnode = classNodes.get(name);
if (cnode != null) {
return new TypeEntity(new ParsedReflective((ParsedTypeNode) cnode));
}
String accessp = name + ":" + (querySource != null ? querySource.getName() : "");
PackageOrClass rval = pocEntityCache.get(accessp);
if (rval != null || pocEntityCache.containsKey(accessp)) {
return rval;
}
if (parentNode != null) {
rval = parentNode.resolvePackageOrClass(name, querySource);
pocEntityCache.put(accessp, rval);
}
return rval;
}
| Resolve a package or type, based on what is visible from the given position in the node.
| This allows for forward declarations not being visible.
|
@OnThread(Tag.FXPlatform)
public PackageOrClass resolvePackageOrClass(String name, Reflective querySource, int fromPosition)
{
return resolvePackageOrClass(name, querySource);
}
|
| @see bluej.parser.entity.EntityResolver#getValueEntity(java.lang.String, java.lang.String)
|
public JavaEntity getValueEntity(String name, Reflective querySource)
{
Set<FieldNode> varset = variables.get(name);
if (varset != null && ! varset.isEmpty()) {
FieldNode var = varset.iterator().next();
JavaEntity fieldType = var.getFieldType().resolveAsType();
if (fieldType != null) {
return new ValueEntity(fieldType.getType());
}
}
String accessp = name + ":" + (querySource != null ? querySource.getName() : "");
JavaEntity rval = valueEntityCache.get(accessp);
if (rval != null || valueEntityCache.containsKey(accessp)) {
return rval;
}
if (parentNode != null) {
rval = parentNode.getValueEntity(name, querySource, getOffsetFromParent());
}
if (rval == null) {
rval = resolvePackageOrClass(name, querySource, getOffsetFromParent());
}
valueEntityCache.put(accessp, rval);
return rval;
}
| Resolve a value, based on what is visible from a given position within the node.
| This allows for forward declarations not being visible.
|
@OnThread(Tag.FXPlatform)
public JavaEntity getValueEntity(String name, Reflective querySource, int fromPosition)
{
return getValueEntity(name, querySource);
}
| Resolve a value, based on what is visible from a given position within the node,
| not allowing for forward declarations.
|
| @param name reference symbol
| @param querySource container of reference symbol for resolution purpose
| @param fromPosition position within the node to resolve at
| @return A JavaEntity reflecting the result of the resolution
|
@OnThread(Tag.FXPlatform)
protected JavaEntity getPositionedValueEntity(String name, Reflective querySource, int fromPosition)
{
Set<FieldNode> varset = variables.get(name);
if (varset != null) {
Iterator<FieldNode> i = varset.iterator();
while (i.hasNext()){
FieldNode var = i.next();
if (var.getOffsetFromParent() <= fromPosition) {
JavaEntity fieldType = var.getFieldType().resolveAsType();
if (fieldType != null) {
return new ValueEntity(fieldType.getType());
}
}
}
}
JavaEntity rval = null;
if (parentNode != null) {
rval = parentNode.getValueEntity(name, querySource, getOffsetFromParent());
}
if (rval == null) {
rval = resolvePackageOrClass(name, querySource, fromPosition);
}
return rval;
}
@Override
@OnThread(Tag.FXPlatform)
protected ExpressionTypeInfo getExpressionType(int pos, int nodePos, JavaEntity defaultType, MoeSyntaxDocument document)
{
valueEntityCache.clear();
pocEntityCache.clear();
NodeAndPosition<ParsedNode> child = getNodeTree().findNodeAtOrBefore(pos, nodePos);
if (child != null && child.getEnd() >= pos) {
return child.getNode().getExpressionType(pos, child.getPosition(), defaultType, document);
}
int startpos = nodePos;
if (child != null) {
startpos = child.getEnd();
}
Element map = document.getDefaultRootElement();
int line = map.getElementIndex(pos) + 1;
Element lineEl = map.getElement(line - 1);
startpos = Math.max(startpos, lineEl.getStartOffset());
int col = startpos - map.getElement(line - 1).getStartOffset() + 1;
Reader r = new DocumentReader(document, startpos, pos);
JavaLexer lexer = new JavaLexer(r, line, col, startpos);
JavaTokenFilter filter = new JavaTokenFilter(lexer);
LocatableToken token = filter.nextToken();
LocatableToken prevToken = null;
while (token.getType() != JavaTokenTypes.EOF){
prevToken = token;
token = filter.nextToken();
}
if (prevToken != null && prevToken.getEndLine() != token.getEndLine()) {
if (prevToken.getEndColumn() != token.getEndColumn()) {
prevToken = null;
}
}
if (prevToken != null && startpos == nodePos) {
if (parentNode != null) {
int offset = getOffsetFromParent();
int ppos = nodePos - offset;
child = parentNode.getNodeTree().findNodeAtOrBefore(nodePos - 1, ppos);
if (child != null && child.getNode().getNodeType() == ParsedNode.NODETYPE_EXPRESSION
&& child.getEnd() == nodePos) {
ExpressionTypeInfo suggests = ExpressionNode.suggestAsExpression(pos, child.getPosition(),
this, defaultType, document);
if (suggests != null) {
return suggests;
}
}
}
}
GenTypeClass atype = (defaultType != null) ? defaultType.getType().asClass() : null;
if (atype == null) {
return null;
}
boolean isStaticCtxt = (defaultType.resolveAsType() != null);
if (prevToken != null && ! Character.isJavaIdentifierPart(prevToken.getText().codePointAt(0))) {
prevToken = null;
}
return new ExpressionTypeInfo(atype, atype, prevToken, isStaticCtxt, true);
}
@Override
public Token getMarkTokensFor(int pos, int length, int nodePos,
MoeSyntaxDocument document)
{
Token tok = new Token(0, TokenType.END);
if (length == 0) {
return tok;
}
Token dummyTok = tok;
NodeAndPosition<ParsedNode> np = getNodeTree().findNodeAtOrAfter(pos, nodePos);
while (np != null && np.getEnd() == pos) {np = np.nextSibling();
}
int cp = pos;
while (np != null && np.getPosition() < (pos + length)){
if (cp < np.getPosition()) {
int nextTokLen = np.getPosition() - cp;
tok.next = tokenizeText(document, cp, nextTokLen);
while (tok.next.id != TokenType.END) {tok = tok.next;
}
cp = np.getPosition();
}
int remaining = pos + length - cp;
remaining = Math.min(remaining, np.getEnd() - cp);
if (remaining != 0) {
tok.next = np.getNode().getMarkTokensFor(cp, remaining, np.getPosition(), document);
cp += remaining;
while (tok.next.id != TokenType.END){
tok = tok.next;
}
}
np = np.nextSibling();
}
if (cp < pos + length) {
int nextTokLen = pos + length - cp;
tok.next = tokenizeText(document, cp, nextTokLen);
while (tok.next.id != TokenType.END) {tok = tok.next;
}
}
tok.next = new Token(0, TokenType.END);
return dummyTok.next;
}
protected static Token tokenizeText(MoeSyntaxDocument document, int pos, int length)
{
DocumentReader dr = new DocumentReader(document, pos, pos+length);
TokenStream lexer = JavaParser.getLexer(dr);
TokenStream tokenStream = new JavaTokenFilter(lexer, null);
Token dummyTok = new Token(0, TokenType.END);
Token token = dummyTok;
boolean lastWasWildcard = false;
int curcol = 1;
while (length > 0){
LocatableToken lt = (LocatableToken) tokenStream.nextToken();
if (lt.getLine() > 1 || lt.getColumn() - curcol >= length) {
token.next = new Token(length, TokenType.DEFAULT);
token = token.next;
break;
}
if (lt.getColumn() > curcol) {
token.next = new Token(lt.getColumn() - curcol, TokenType.DEFAULT);
token = token.next;
length -= token.length;
curcol += token.length;
}
TokenType tokType = TokenType.DEFAULT;
if (JavaParser.isPrimitiveType(lt)) {
tokType = TokenType.PRIMITIVE;
}
else if (JavaParser.isModifier(lt)) {
tokType = TokenType.KEYWORD1;
}
else if (lt.getType() == JavaTokenTypes.STRING_LITERAL) {
tokType = TokenType.STRING_LITERAL;
}
else if (lt.getType() == JavaTokenTypes.CHAR_LITERAL) {
tokType = TokenType.CHAR_LITERAL;
}
else {
switch (lt.getType()) {
case JavaTokenTypes.LITERAL_assert:
case JavaTokenTypes.LITERAL_for:
case JavaTokenTypes.LITERAL_switch:
case JavaTokenTypes.LITERAL_while:
case JavaTokenTypes.LITERAL_do:
case JavaTokenTypes.LITERAL_try:
case JavaTokenTypes.LITERAL_catch:
case JavaTokenTypes.LITERAL_throw:
case JavaTokenTypes.LITERAL_throws:
case JavaTokenTypes.LITERAL_finally:
case JavaTokenTypes.LITERAL_return:
case JavaTokenTypes.LITERAL_case:
case JavaTokenTypes.LITERAL_default:
case JavaTokenTypes.LITERAL_break:
case JavaTokenTypes.LITERAL_continue:
case JavaTokenTypes.LITERAL_if:
case JavaTokenTypes.LITERAL_else:
case JavaTokenTypes.LITERAL_new:
tokType = TokenType.KEYWORD1;
break;
case JavaTokenTypes.LITERAL_class:
case JavaTokenTypes.LITERAL_package:
case JavaTokenTypes.LITERAL_import:
case JavaTokenTypes.LITERAL_extends:
case JavaTokenTypes.LITERAL_interface:
case JavaTokenTypes.LITERAL_enum:
case JavaTokenTypes.LITERAL_implements:
tokType = TokenType.KEYWORD2;
break;
case JavaTokenTypes.LITERAL_super:
if (lastWasWildcard)
tokType = TokenType.KEYWORD2;
else{ tokType = TokenType.KEYWORD3;
}
break;
case JavaTokenTypes.LITERAL_this:
case JavaTokenTypes.LITERAL_null:
case JavaTokenTypes.LITERAL_true:
case JavaTokenTypes.LITERAL_false:
tokType = TokenType.KEYWORD3;
break;
case JavaTokenTypes.LITERAL_instanceof:
tokType = TokenType.OPERATOR;
break;
default:
}
}
lastWasWildcard = lt.getType() == JavaTokenTypes.QUESTION;
int toklen = lt.getLength();
if (lt.getEndLine() > 1) {
toklen = length;
}
token.next = new Token(toklen, tokType);
token = token.next;
length -= toklen;
curcol += toklen;
}
token.next = new Token(0, TokenType.END);
return dummyTok.next;
}
}
top,
use,
map,
abstract class JavaParentNode
. JavaParentNode
. getParentNode
. insertNode
. insertVariable
. insertField
. childChangedName
. childRemoved
. getTypeNode
. resolveQualifiedClass
. resolvePackageOrClass
. resolvePackageOrClass
. getValueEntity
. getValueEntity
. getPositionedValueEntity
. getExpressionType
. getMarkTokensFor
. tokenizeText
662 neLoCode
+ 23 LoComm