/* Soot - a J*va Optimization Framework
 * Copyright (C) 2000 Patrice Pominville
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the Sable Research Group and others 1997-1999.  
 * See the 'credits' file distributed with Soot for the complete list of
 * contributors.  (Soot is distributed at http://www.sable.mcgill.ca/soot)
 */


package soot.jimple.parser;

import soot.jimple.JimpleBody;
import soot.jimple.parser.parser.*;
import soot.jimple.parser.lexer.*;
import soot.jimple.parser.node.*;
import java.io.*;
import java.util.*;

import soot.*;

/** 
    This class encapsulates a JimpleAST instance and provides methods
    to act on it.      
*/
public class JimpleAST
{
    private Start mTree = null;
    private HashMap<SootMethod, JimpleBody> methodToParsedBodyMap = null;

    /** Constructs a JimpleAST and generates its parse tree from the given InputStream.
     *
     * @param aJIS The InputStream to parse.
     */
    public JimpleAST(InputStream aJIS) throws ParserException, LexerException, IOException
    {
        Parser p =
            new Parser(new Lexer(
                    new PushbackReader(new BufferedReader(
                    new InputStreamReader(aJIS)), 1024)));
        mTree = p.parse();
    }

    /** Reads an entire class from jimple, creates the Soot objects & 
     * returns it. */
    public SootClass createSootClass()
    {        
        Walker w = new Walker(SootResolver.v());        
        mTree.apply(w);  
        return w.getSootClass();
    }

    /** 
     *   Applies a SkeletonExtractorWalker to the given SootClass, using the given Resolver to resolve 
     *   the reference types it contains. The given SootClass instance will be filled to contain 
     *   a class skeleton: that is no  Body instances will be created for the class' methods.
     *   @param sc a SootClass to fill in.
     */
    public void getSkeleton(SootClass sc)
    {
        Walker w = new SkeletonExtractorWalker(SootResolver.v(), sc);        
        mTree.apply(w);          
    }
    

    /**  Returns a body corresponding to the parsed jimple for m. 
     *   If necessary, applies the BodyExtractorWalker to initialize the bodies map. 
     *   @param m the method we want to get a body for.
     *   @return the actual body for the given method.
     */
    public Body getBody(SootMethod m)
    {
        if (methodToParsedBodyMap == null)
            stashBodiesForClass(m.getDeclaringClass());
        return methodToParsedBodyMap.get(m);
    } 


    /**
     *   Extracts the reference constant pool for this JimpleAST. 
     *   @return the Set of RefTypes for the reference types contained this AST.
     */
    public Set<String> getCstPool()
    {  
        CstPoolExtractor cpe = new CstPoolExtractor(mTree);
        return cpe.getCstPool();        
    }

    /** Returns the SootResolver currently in use. */
    public SootResolver getResolver()
    {
        return SootResolver.v();
    }

    /* Runs a Walker on the InputStream associated to this object.
     * The SootClass which we want bodies for is passed as the argument. 
     */
    private void stashBodiesForClass(SootClass sc) 
    {          
        methodToParsedBodyMap = new HashMap<SootMethod, JimpleBody>();

        Walker w = new BodyExtractorWalker(sc, SootResolver.v(), methodToParsedBodyMap);

        boolean oldPhantomValue = Scene.v().getPhantomRefs();

        Scene.v().setPhantomRefs(true);
        mTree.apply(w);
        Scene.v().setPhantomRefs(oldPhantomValue);
    }    
} // Parse