/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.visage.tools.comp;
import org.visage.api.VisageBindStatus;
import org.visage.tools.tree.*;
import org.visage.tools.util.MsgSym;
import com.sun.tools.mjavac.util.Context;
import com.sun.tools.mjavac.util.JCDiagnostic;
import com.sun.tools.mjavac.util.List;
import com.sun.tools.mjavac.util.Log;
/**
*
* @author Robert Field
*/
public class VisageBoundContextAnalysis extends VisageTreeScanner {
protected static final Context.Key<VisageBoundContextAnalysis> bindAnalysisKey =
new Context.Key<VisageBoundContextAnalysis>();
private final Log log;
private final JCDiagnostic.Factory diags;
private VisageBindStatus bindStatus;
public static VisageBoundContextAnalysis instance(Context context) {
VisageBoundContextAnalysis instance = context.get(bindAnalysisKey);
if (instance == null) {
instance = new VisageBoundContextAnalysis(context);
}
return instance;
}
VisageBoundContextAnalysis(Context context) {
context.put(bindAnalysisKey, this);
log = Log.instance(context);
diags = JCDiagnostic.Factory.instance(context);
bindStatus = VisageBindStatus.UNBOUND;
}
public void analyzeBindContexts(VisageEnv<VisageAttrContext> attrEnv) {
scan(attrEnv.tree);
}
private void mark(VisageBoundMarkable tree) {
tree.markBound(bindStatus);
}
@Override
public void visitScript(VisageScript tree) {
bindStatus = VisageBindStatus.UNBOUND;
super.visitScript(tree);
}
@Override
public void visitVarInit(VisageVarInit tree) {
}
private void analyzeVar(VisageAbstractVar tree) {
// any changes here should also go into visitOverrideClassVar
VisageBindStatus prevBindStatus = bindStatus;
bindStatus = tree.isBound()?
tree.getBindStatus() :
prevBindStatus;
mark(tree);
scan(tree.getInitializer());
bindStatus = prevBindStatus;
for (VisageOnReplace.Kind triggerKind : VisageOnReplace.Kind.values()) {
VisageOnReplace trigger = tree.getTrigger(triggerKind);
if (trigger != null) {
if (bindStatus != VisageBindStatus.UNBOUND) {
log.error(trigger.pos(), MsgSym.MESSAGE_TRIGGER_IN_BIND_NOT_ALLOWED, triggerKind);
}
}
}
scan(tree.getOnReplace());
scan(tree.getOnInvalidate());
}
@Override
public void visitVar(VisageVar tree) {
analyzeVar(tree);
}
@Override
public void visitOverrideClassVar(VisageOverrideClassVar tree) {
analyzeVar(tree);
}
@Override
public void visitClassDeclaration(VisageClassDeclaration tree) {
// these start over in a class definition
VisageBindStatus prevBindStatus = bindStatus;
bindStatus = VisageBindStatus.UNBOUND;
super.visitClassDeclaration(tree);
bindStatus = prevBindStatus;
}
@Override
public void visitFunctionDefinition(VisageFunctionDefinition tree) {
// start over in a function definition
VisageBindStatus prevBindStatus = bindStatus;
bindStatus = tree.isBound()? VisageBindStatus.UNIDIBIND : VisageBindStatus.UNBOUND;
// don't use super, since we don't want to cancel the inBindContext
scan(tree.getParams());
scan(tree.getBodyExpression());
bindStatus = prevBindStatus;
}
@Override
public void visitForExpressionInClause(VisageForExpressionInClause tree) {
mark(tree);
super.visitForExpressionInClause(tree);
}
@Override
public void visitFunctionValue(VisageFunctionValue tree) {
// these start over in a function value
VisageBindStatus prevBindStatus = bindStatus;
bindStatus = VisageBindStatus.UNBOUND;
super.visitFunctionValue(tree);
bindStatus = prevBindStatus;
}
@Override
public void visitObjectLiteralPart(VisageObjectLiteralPart tree) {
VisageBindStatus prevBindStatus = bindStatus;
bindStatus = tree.isExplicitlyBound()?
tree.getBindStatus() :
prevBindStatus;
tree.markBound(bindStatus);
scan(tree.getExpression());
bindStatus = prevBindStatus;
}
@Override
public void visitAssignop(VisageAssignOp tree) {
if (bindStatus != VisageBindStatus.UNBOUND) {
log.error(tree.pos(), MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT, "compound assignment");
}
super.visitAssignop(tree);
}
@Override
public void visitAssign(VisageAssign tree) {
if (bindStatus != VisageBindStatus.UNBOUND) {
log.error(tree.pos(), MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT, "=");
}
super.visitAssign(tree);
}
@Override
public void visitUnary(VisageUnary tree) {
mark(tree);
if (bindStatus != VisageBindStatus.UNBOUND) {
switch (tree.getVisageTag()) {
case PREINC:
case POSTINC:
log.error(tree.pos(), MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT, "++");
break;
case PREDEC:
case POSTDEC:
log.error(tree.pos(), MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT, "--");
break;
}
}
super.visitUnary(tree);
}
@Override
public void visitInterpolateValue(final VisageInterpolateValue tree) {
VisageBindStatus prevBindStatus = bindStatus;
bindStatus = VisageBindStatus.UNBOUND; //TODO: ???
super.visitInterpolateValue(tree);
bindStatus = prevBindStatus;
}
@Override
public void visitKeyFrameLiteral(VisageKeyFrameLiteral tree) {
if (bindStatus != VisageBindStatus.UNBOUND) {
log.error(tree.pos(),
MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT,
diags.fragment(MsgSym.MESSAGE_VISAGE_KEYFRAME_LIT));
}
super.visitKeyFrameLiteral(tree);
}
@Override
public void visitTry(VisageTry tree) {
if (bindStatus != VisageBindStatus.UNBOUND) {
log.error(tree.pos(),
MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT,
diags.fragment(MsgSym.MESSAGE_VISAGE_TRY_CATCH));
}
super.visitTry(tree);
}
@Override
public void visitBlockExpression(VisageBlock tree) {
mark(tree);
if (bindStatus != VisageBindStatus.UNBOUND) {
for (List<VisageExpression> l = tree.stats; l.nonEmpty(); l = l.tail) {
if (l.head.getVisageTag() != VisageTag.VAR_DEF) {
log.error(l.head.pos(), MsgSym.MESSAGE_VISAGE_NOT_ALLOWED_IN_BIND_CONTEXT, l.head.toString());
}
}
}
super.visitBlockExpression(tree);
}
@Override
public void visitIfExpression(VisageIfExpression tree) {
mark(tree);
super.visitIfExpression(tree);
}
@Override
public void visitFunctionInvocation(VisageFunctionInvocation tree) {
mark(tree);
super.visitFunctionInvocation(tree);
}
@Override
public void visitParens(VisageParens tree) {
mark(tree);
super.visitParens(tree);
}
@Override
public void visitBinary(VisageBinary tree) {
mark(tree);
super.visitBinary(tree);
}
@Override
public void visitTypeCast(VisageTypeCast tree) {
mark(tree);
super.visitTypeCast(tree);
}
@Override
public void visitInstanceOf(VisageInstanceOf tree) {
mark(tree);
super.visitInstanceOf(tree);
}
@Override
public void visitSelect(VisageSelect tree) {
mark(tree);
super.visitSelect(tree);
}
@Override
public void visitIdent(VisageIdent tree) {
mark(tree);
super.visitIdent(tree);
}
@Override
public void visitLiteral(VisageLiteral tree) {
mark(tree);
super.visitLiteral(tree);
}
@Override
public void visitSequenceEmpty(VisageSequenceEmpty tree) {
mark(tree);
super.visitSequenceEmpty(tree);
}
@Override
public void visitSequenceRange(VisageSequenceRange tree) {
mark(tree);
super.visitSequenceRange(tree);
}
@Override
public void visitSequenceExplicit(VisageSequenceExplicit tree) {
mark(tree);
super.visitSequenceExplicit(tree);
}
@Override
public void visitSequenceIndexed(VisageSequenceIndexed tree) {
mark(tree);
super.visitSequenceIndexed(tree);
}
@Override
public void visitSequenceSlice(VisageSequenceSlice tree) {
mark(tree);
super.visitSequenceSlice(tree);
}
@Override
public void visitStringExpression(VisageStringExpression tree) {
mark(tree);
super.visitStringExpression(tree);
}
@Override
public void visitInstanciate(VisageInstanciate tree) {
mark(tree);
super.visitInstanciate(tree);
}
@Override
public void visitForExpression(VisageForExpression tree) {
mark(tree);
super.visitForExpression(tree);
}
@Override
public void visitIndexof(VisageIndexof tree) {
mark(tree);
super.visitIndexof(tree);
}
@Override
public void visitTimeLiteral(VisageTimeLiteral tree) {
mark(tree);
super.visitTimeLiteral(tree);
}
@Override
public void visitLengthLiteral(VisageLengthLiteral tree) {
mark(tree);
super.visitLengthLiteral(tree);
}
@Override
public void visitAngleLiteral(VisageAngleLiteral tree) {
mark(tree);
super.visitAngleLiteral(tree);
}
@Override
public void visitColorLiteral(VisageColorLiteral tree) {
mark(tree);
super.visitColorLiteral(tree);
}
}