/*
 * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.glassfish.pfl.dynamic.codegen.impl;

import java.io.PrintStream ;

import java.util.Set ;
import java.util.Map ;
import java.util.IdentityHashMap ;

import java.lang.reflect.Modifier ;

import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.Variable ;

public final class Util {
    private Util() {}

    
Make sure that all variables reachable from node are marked not available, indicating that they are no longer in scope. Note that only defining occurrences of variables are to be considered here, as a scope that merely references a variable may be closed while the containing defining scope is still open.
/** Make sure that all variables reachable from node * are marked not available, indicating that they are * no longer in scope. Note that only defining occurrences * of variables are to be considered here, as a scope * that merely references a variable may be closed while * the containing defining scope is still open. */
public static void close( Node node ) { TreeWalkerContext context = new TreeWalkerContext() ; Visitor visitor = new TreeWalker( context ) { @Override public void blockStatementBeforeBodyStatement( BlockStatement arg, Statement stmt ) { if (stmt instanceof DefinitionStatement) { DefinitionStatement ds = DefinitionStatement.class.cast( stmt ) ; ((VariableInternal)ds.var()).close() ; } } @Override public void visitMethodGenerator( MethodGenerator arg ) { for (Variable var : arg.arguments()) { ((VariableInternal)var).close() ; } } @Override public void tryStatementBeforeBlock( TryStatement arg, Type type, Variable var, BlockStatement block ) { ((VariableInternal)var).close() ; } } ; context.push( visitor ) ; node.accept( visitor ) ; }
Throw an exception if any ExpressionInternal reachable from expr contains a Variable that is out of scope. Note that this is only useful for Expressions.
/** Throw an exception if any ExpressionInternal reachable * from expr contains a Variable that is out of scope. * Note that this is only useful for Expressions. */
public static void checkScope( ExpressionInternal expr ) { TreeWalkerContext context = new TreeWalkerContext() ; Visitor visitor = new TreeWalker( context ) { @Override public boolean preVariable( Variable arg ) { if (!((VariableInternal)arg).isAvailable()) throw new IllegalStateException( arg + " is no longer in scope" ) ; return false ; } } ; context.push( visitor ) ; expr.accept( visitor ) ; }
Check that node is really a tree, that is, when we traverse it with the visitor, we never encounter the same node twice.
/** Check that node is really a tree, that is, when we traverse it * with the visitor, we never encounter the same node twice. */
public static void checkTree( final Node node, final PrintStream pw ) { // Set up a visitor that counts how many times each unique node // object is encountered, then visit node. TreeWalkerContext context = new TreeWalkerContext() ; final Map<Node,Integer> map = new IdentityHashMap<Node,Integer>() ; Visitor visitor = new TreeWalker( context ) { @Override public boolean preNode( Node arg ) { Integer val = map.get( arg ) ; if (val == null) { val = 1 ; } else { val++ ; } map.put( arg, val ) ; return false ; } } ; context.push( visitor ) ; node.accept( visitor ) ; // Print out any Nodes that appear more than once // in the tree rooted at node. for (Map.Entry<Node,Integer> entry : map.entrySet()) { if (entry.getValue() > 1) { pw.print( "Node " + entry.getKey() + " appeared " + entry.getValue() + " times in the AST" ) ; } } } // Display all attributes of node. If the value of an attribute is itself // a node, display its attributes as well (recursively). At the end, // leave the Printer indented one level. private static void displayAttributes( final Node node, final CodegenPrinter pr ) { Set<Attribute<?>> attrs = Attribute.getAttributes( node ) ; for (Attribute<?> attr : attrs) { String typeName = attr.type().getName() ; int lastIndex = typeName.lastIndexOf( '.' ) ; if (lastIndex >= 0) typeName = typeName.substring( lastIndex + 1 ) ; Object obj = attr.get(node) ; String value = attr.get( node ).toString() ; pr.nl().p("|__:").p(attr.name()).p(":").p(typeName).p("=").p(value) ; if (obj instanceof Node) { pr.in() ; displayAttributes( Node.class.cast(obj), pr ) ; pr.out() ; } } } public static String getNodeIdString( Node obj ) { return "@" + obj.id() ; }
Display a tree for the node.
/** Display a tree for the node. */
public static void display( final Node node, final PrintStream pw ) { TreeWalkerContext context = new TreeWalkerContext() ; Visitor visitor = new TreeWalker( context ) { final CodegenPrinter pr = new CodegenPrinter( pw, 2, '.' ) ; private boolean done( Node node ) { displayAttributes( node, pr ) ; pr.in() ; return true ; } // Use this if no more specific type has a defined display // behavior in this visitor. @Override public boolean preNode( Node arg ) { pr.nl().p("Node").p(getNodeIdString(arg)) .p("[").p(arg.toString()).p("]") ; return done( arg ) ; } @Override public void postNode( Node arg ) { pr.out() ; } @Override public boolean preClassGenerator( ClassGeneratorImpl arg ) { pr.nl().p("ClassGenerator").p(getNodeIdString(arg)) .p("[").p(Modifier.toString(arg.modifiers())) .p(" ").p((arg.isInterface() ? "interface" : "class")) .p(" ").p(arg.name()).p("]") ; return done( arg ) ; } @Override public boolean preMethodGenerator( MethodGenerator arg ) { pr.nl().p( "MethodGenerator").p(getNodeIdString(arg)) .p("[").p(Modifier.toString(arg.modifiers())) .p(" ").p(arg.returnType().name()).p(" ").p(arg.name()).p("]") ; return done( arg ) ; } @Override public boolean preThrowStatement( ThrowStatement arg ) { pr.nl().p("ThrowStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preAssignmentStatement( AssignmentStatement arg ) { pr.nl().p("AssignmentStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preBlockStatement( BlockStatement arg ) { pr.nl().p("BlockStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preCaseBranch( CaseBranch arg ) { pr.nl().p("CaseBranch").p(getNodeIdString(arg)) .p("[").p(Integer.toString(arg.label())).p("]") ; return done( arg ) ; } @Override public boolean preDefinitionStatement( DefinitionStatement arg ) { pr.nl().p("DefinitionStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preIfStatement( IfStatement arg ) { pr.nl().p("IfStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public void ifStatementBeforeTruePart( IfStatement arg ) { pr.out().nl().p("IfStatement:true").in() ; } @Override public boolean ifStatementBeforeFalsePart( IfStatement arg ) { pr.out().nl().p("IfStatement:false").in() ; return true ; } @Override public boolean preBreakStatement( BreakStatement arg ) { pr.nl().p("BreakStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preReturnStatement( ReturnStatement arg ) { pr.nl().p("ReturnStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preSwitchStatement( SwitchStatement arg ) { pr.nl().p("SwitchStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public boolean preTryStatement( TryStatement arg ) { pr.nl().p("TryStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override public void tryStatementBeforeBlock( TryStatement arg, Type type, Variable var, BlockStatement block ) { VariableInternal ivar = (VariableInternal)var ; pr.out().nl().p("TryStatement:catch[").p("type=").p(type.name()) .p(",var=").p(ivar.ident()).p("]").in() ; ivar.accept( this ) ; } @Override public boolean tryStatementBeforeFinalPart( TryStatement arg ) { pr.out().nl().p("TryStatement:finally").in() ; return true ; } @Override public boolean preWhileStatement( WhileStatement arg ) { pr.nl().p("WhileStatement").p(getNodeIdString(arg)) ; return done( arg ) ; } @Override // All Expressions define a usable toString, so they all // can be handled by this method. public boolean preExpression( ExpressionInternal arg ) { pr.nl().p(arg.toString()) ; return done( arg ) ; } @Override public boolean preFieldGenerator( FieldGenerator arg ) { pr.nl().p(arg.toString()) ; return done( arg ) ; } } ; context.push( visitor ) ; node.accept( visitor ) ; } }