variablescopevisitor.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 468 行 · 第 1/2 页

JAVA
468
字号
    private String getPropertyName(MethodNode m) {
        String name = m.getName();
        if (!(name.startsWith("set") || name.startsWith("get"))) return null;
        String pname = name.substring(3);
        if (pname.length() == 0) return null;
        String s = pname.substring(0, 1).toLowerCase();
        String rest = pname.substring(1);
        pname = s + rest;
        
        if (name.startsWith("get") && m.getReturnType()==ClassHelper.VOID_TYPE) {
            return null;
        }
        if (name.startsWith("set") && m.getParameters().length!=1) {
            return null;
        }
        return pname;
    }     
    
    // -------------------------------
    // different Variable based checks  
    // -------------------------------
    
    private Variable checkVariableNameForDeclaration(String name, Expression expression) {
        if ("super".equals(name) || "this".equals(name)) return null;

        VariableScope scope = currentScope;
        Variable var = new DynamicVariable(name,currentScope.isInStaticContext());
        Variable dummyStart = var;
        // try to find a declaration of a variable
        VariableScope dynamicScope = null;
        while (!scope.isRoot()) {
            if (dynamicScope==null && scope.isResolvingDynamic()) {
                dynamicScope = scope;
            }
            
            Map declares = scope.getDeclaredVariables();
            if (declares.get(var.getName())!=null) {
                var = (Variable) declares.get(var.getName());
                break;
            }
            Map localReferenced = scope.getReferencedLocalVariables(); 
            if (localReferenced.get(var.getName())!=null) {
                var = (Variable) localReferenced.get(var.getName());
                break;
            }

            Map classReferenced = scope.getReferencedClassVariables(); 
            if (classReferenced.get(var.getName())!=null) {
                var = (Variable) classReferenced.get(var.getName());
                break;
            }
            
            ClassNode classScope = scope.getClassScope();
            if (classScope!=null) {
                Variable member = findClassMember(classScope,var.getName());
                if (member!=null && (currentScope.isInStaticContext() ^ member instanceof DynamicVariable)) var = member;
                break;
            }            
            scope = scope.getParent();
        }

        VariableScope end = scope;

        if (scope.isRoot() && dynamicScope==null) {
            // no matching scope found
            declare(var,expression);
            addError("The variable " + var.getName() +
                     " is undefined in the current scope", expression);
        } else if (scope.isRoot() && dynamicScope!=null) {
            // no matching scope found, but there was a scope that
            // resolves dynamic
            scope = dynamicScope;
        } 
        
        if (!scope.isRoot()) {
            scope = currentScope;
            while (scope != end) {
                Map references = null;
                if (end.isClassScope() || end.isRoot() || 
                        (end.isReferencedClassVariable(name) && end.getDeclaredVariable(name)==null)) 
                {
                    references = scope.getReferencedClassVariables();
                } else {
                    references = scope.getReferencedLocalVariables();
                    var.setClosureSharedVariable(var.isClosureSharedVariable() || inClosure);
                }
                references.put(var.getName(),var);
                scope = scope.getParent();
            }
            if (end.isResolvingDynamic()) {
                if (end.getDeclaredVariable(var.getName())==null) {
                    end.getDeclaredVariables().put(var.getName(),var);
                }
            }
        }
        
        return var;
    }
    
    private void checkVariableContextAccess(Variable v, Expression expr) {
        if (v.isInStaticContext() || !currentScope.isInStaticContext()) return;        
        
        String msg =  v.getName()+
                      " is declared in a dynamic context, but you tried to"+
                      " access it from a static context.";
        addError(msg,expr);
        
        // declare a static variable to be able to continue the check
        DynamicVariable v2 = new DynamicVariable(v.getName(),currentScope.isInStaticContext());
        currentScope.getDeclaredVariables().put(v.getName(),v2);
    }
    
    // ------------------------------
    // code visit  
    // ------------------------------
    
    public void visitBlockStatement(BlockStatement block) {
        pushState();
        block.setVariableScope(currentScope);
        super.visitBlockStatement(block);
        popState();
    }
    
    public void visitForLoop(ForStatement forLoop) {
        pushState();
        forLoop.setVariableScope(currentScope);
        Parameter p = (Parameter) forLoop.getVariable();
        p.setInStaticContext(currentScope.isInStaticContext());
        declare(p, forLoop);        
        super.visitForLoop(forLoop);
        popState();
    }

    public void visitDeclarationExpression(DeclarationExpression expression) {
        // visit right side first to avoid the usage of a 
        // variable before its declaration
        expression.getRightExpression().visit(this);
        // no need to visit left side, just get the variable name
        VariableExpression vex = expression.getVariableExpression();
        vex.setInStaticContext(currentScope.isInStaticContext());
        declare(vex);
        vex.setAccessedVariable(vex);
    }
    
    public void visitVariableExpression(VariableExpression expression) {
        String name = expression.getName();
        Variable v = checkVariableNameForDeclaration(name,expression);
        if (v==null) return;
        expression.setAccessedVariable(v);
        checkVariableContextAccess(v,expression);
    }
    
    public void visitClosureExpression(ClosureExpression expression) {
        pushState();

        inClosure=true;
        // as result of the Paris meeting Closure resolves
        // always dynamically
        currentScope.setDynamicResolving(true);
        
        expression.setVariableScope(currentScope);

        if (expression.isParameterSpecified()) {
            Parameter[] parameters = expression.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                parameters[i].setInStaticContext(currentScope.isInStaticContext());
                declare(parameters[i],expression);
            }
        } else if (expression.getParameters()!=null){
            DynamicVariable var = new DynamicVariable("it",currentScope.isInStaticContext());
            currentScope.getDeclaredVariables().put("it",var);
        }

        super.visitClosureExpression(expression);
        popState();
    }
    
    public void visitCatchStatement(CatchStatement statement) {
        pushState();
        Parameter p = (Parameter) statement.getVariable();
        p.setInStaticContext(currentScope.isInStaticContext());
        declare(p, statement);
        super.visitCatchStatement(statement);
        popState();
    }
    
    public void visitFieldExpression(FieldExpression expression) {
        String name = expression.getFieldName();
        //TODO: change that to get the correct scope
        Variable v = checkVariableNameForDeclaration(name,expression);
        checkVariableContextAccess(v,expression);  
    }
    
    // ------------------------------
    // class visit  
    // ------------------------------
    
    public void visitClass(ClassNode node) {
        pushState();
        boolean dynamicMode = node.isScript();
        currentScope.setDynamicResolving(dynamicMode);
        currentScope.setClassScope(node);
        
        super.visitClass(node);
        popState();
    }

    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
        pushState(node.isStatic());
        
        node.setVariableScope(currentScope);
        declare(node.getParameters(),node);
        
        super.visitConstructorOrMethod(node, isConstructor);
        popState();
    }
    
    public void visitMethodCallExpression(MethodCallExpression call) {
    	if (call.isImplicitThis() && call.getMethod() instanceof ConstantExpression) {
            Object value = ((ConstantExpression) call.getMethod()).getText();
            if (! (value instanceof String)) {
                throw new GroovyBugError("tried to make a method call with an constant as"+
                                         " name, but the constant was no String.");
            }
            String methodName = (String) value;
	        Variable v = checkVariableNameForDeclaration(methodName,call);
	        if (v!=null && !(v instanceof DynamicVariable)) {
	            checkVariableContextAccess(v,call);
	        }
    	}
        super.visitMethodCallExpression(call);
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?