Package flex2.compiler.as3

Source Code of flex2.compiler.as3.As3Compiler

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*/

package flex2.compiler.as3;

import flex2.compiler.AbstractSubCompiler;
import flex2.compiler.CompilerContext;
import flex2.compiler.CompilationUnit;
import flex2.compiler.CompilerBenchmarkHelper;
import flex2.compiler.Source;
import flex2.compiler.SymbolTable;
import flex2.compiler.abc.AbcClass;
import flex2.compiler.abc.MetaData;
import flex2.compiler.as3.reflect.TypeTable;
import flex2.compiler.as3.reflect.NodeMagic;
import flex2.compiler.css.StyleConflictException;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.util.CompilerMessage;
import flex2.compiler.util.LineNumberMap;
import flex2.compiler.util.MimeMappings;
import flex2.compiler.util.MultiName;
import flex2.compiler.util.MultiNameMap;
import flex2.compiler.util.Name;
import flex2.compiler.util.NameFormatter;
import flex2.compiler.util.QName;
import flex2.compiler.util.QNameList;
import flex2.compiler.util.QNameSet;
import flex2.compiler.util.ThreadLocalToolkit;
import macromedia.asc.embedding.ConfigVar;
import macromedia.asc.embedding.LintEvaluator;
import macromedia.asc.embedding.WarningConstants;
import macromedia.asc.embedding.avmplus.GlobalBuilder;
import macromedia.asc.embedding.avmplus.RuntimeConstants;
import macromedia.asc.parser.*;
import macromedia.asc.semantics.*;
import macromedia.asc.util.Context;
import macromedia.asc.util.ContextStatics;
import macromedia.asc.util.IntegerPool;
import macromedia.asc.util.ObjectList;
import macromedia.asc.util.Slots;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
* The sub-compiler used to compile .as files.  Many of the other
* sub-compilers wrap an instance of this class.  In addition to being
* the primary interface with ASC, this class also handles invoking
* the compiler extensions and collecting benchmark data.
*
* @author Clement Wong
* @see macromedia.asc.parser.Parser
* @see macromedia.asc.semantics.ConstantEvaluator
* @see macromedia.asc.semantics.FlowAnalyzer
*/
public class As3Compiler extends AbstractSubCompiler implements flex2.compiler.SubCompiler
{
  static
  {
    // C: Is static method call really a good idea?
    TypeValue.init();
    ObjectValue.init();
  }

  public static final String AttrTypeTable = TypeTable.class.getName();
    private static final String COMPILER_NAME = "as3";

    /**
     * Implementation of ASC's CompilerHandler which uses the
     * ThreadLocalToolkit's Logger to log errors and warnings.
     */
  public static class CompilerHandler extends macromedia.asc.embedding.CompilerHandler
  {
    public CompilerHandler()
    {
      super();
    }

    public CompilerHandler(Source s)
    {
      this.s = s;
    }

    private Source s;

    public void error2(String filename, int ln, int col, Object msg, String source)
    {
      ThreadLocalToolkit.log((CompilerMessage) msg, filename, ln, col, source);
    }

    public void warning2(String filename, int ln, int col, Object msg, String source)
    {
      ThreadLocalToolkit.log((CompilerMessage) msg, filename, ln, col, source);
    }

    public void error(String filename, int ln, int col, String msg, String source, int errorCode)
    {
      if (errorCode != -1)
      {
        ThreadLocalToolkit.logError(filename, ln, col, msg, source, errorCode);
      }
      else
      {
        ThreadLocalToolkit.logError(filename, ln, col, msg, source);
      }
    }

    public void warning(String filename, int ln, int col, String msg, String source, int errorCode)
    {
            msg = mapRenamedVariables(msg);

      if (errorCode != -1)
      {
        ThreadLocalToolkit.logWarning(filename, ln, col, msg, source, errorCode);
      }
      else
      {
        ThreadLocalToolkit.logWarning(filename, ln, col, msg, source);
      }
    }

    public void error(String filename, int ln, int col, String msg, String source)
    {
      ThreadLocalToolkit.logError(filename, ln, col, msg, source);
    }

    public void warning(String filename, int ln, int col, String msg, String source)
    {
      ThreadLocalToolkit.logWarning(filename, ln, col, msg, source);
    }

    public FileInclude findFileInclude(String parentPath, String filespec)
    {
      Object obj = s == null ? null : s.getSourceFragment(filespec);

      if (obj instanceof VirtualFile)
      {
        VirtualFile f = (VirtualFile) obj;
        if (f.getParent().equals(parentPath))
        {
          FileInclude incl = new FileInclude();
          try
          {
            if (f.isTextBased())
            {
              incl.text = f.toString();
            }
            else
            {
              incl.in = f.getInputStream();
            }
            incl.parentPath = parentPath;
            // If asc ever reports a problem, it will use the name for reporting...
            incl.fixed_filespec = f.getNameForReporting();
            return incl;
          }
          catch (IOException ex)
          {
            return null;
          }
        }
      }

      return null;
    }

        // flex2.compiler.mxml.MxmlLogAdapter has some similar logic.  Ideally it should be
        // consolidated and move into a shared Logger adapter/filter.
        private String mapRenamedVariables(String msg)
        {
            CompilerContext context = s.getCompilationUnit().getContext();
            Map renamedVariableMap = (Map) context.getAttribute(CompilerContext.RENAMED_VARIABLE_MAP);

            if (renamedVariableMap != null)
            {
                Iterator iterator = renamedVariableMap.entrySet().iterator();

                while ( iterator.hasNext() )
                {
                    Map.Entry entry = (Map.Entry) iterator.next();
                    String newVariableName = (String) entry.getKey();
                    String oldVariableName = (String) entry.getValue();
                    msg = msg.replaceAll("'" + newVariableName + "'", "'" + oldVariableName + "'");
                }
            }

            return msg;
        }
  }

  public As3Compiler(As3Configuration as3Configuration)
  {
    mimeTypes = new String[]{MimeMappings.AS};
    compilerExtensions = new ArrayList<Extension>();
    this.as3Configuration = as3Configuration;

    processCoachSettings();
  }

    private HashMap<Integer, Boolean> warnMap = null;
  private String[] mimeTypes;
  private List<Extension> compilerExtensions;
  private As3Configuration as3Configuration;
    private boolean coachWarningsAsErrors = false;

    /**
     * The name of this compiler as a simple String identifier.
     *
     * @return This Compiler's name.
     */
    public String getName()
    {
        return COMPILER_NAME;
    }

  public boolean isSupported(String mimeType)
  {
    return mimeTypes[0].equals(mimeType);
  }

  public String[] getSupportedMimeTypes()
  {
    return mimeTypes;
  }

  public void addCompilerExtension(Extension ext)
  {
    compilerExtensions.add(ext);
  }

  public Source preprocess(Source source)
  {
    return source;
  }

  public CompilationUnit parse1(Source source, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.PARSE1, source.getNameForReporting());
        }

    CompilationUnit unit = source.getCompilationUnit();

        if (unit != null && unit.hasTypeInfo)
        {
            return unit;
        }

    String path = source.getName();
    ProgramNode node = null;
        CompilerContext context = null;
        Context cx;

        if ((unit != null) && (unit.getSyntaxTree() != null))
        {
            node = (ProgramNode) unit.getSyntaxTree();
            cx = node.cx;
        }
        else
        {
            context = new CompilerContext();
            cx = new Context(symbolTable.perCompileData);
            cx.setScriptName(source.getName());
            cx.setPath(source.getParent());

            cx.setEmitter(symbolTable.emitter);
            cx.setHandler(new CompilerHandler(source));
            symbolTable.perCompileData.handler = cx.getHandler();

            context.setAscContext(cx);

            // conditional compilation: add config settings from the compiler configuration
            // this must be done BEFORE parsing
            final ObjectList<ConfigVar> arr = as3Configuration.getDefine();
            if (arr != null)
            {
                cx.config_vars.addAll(arr);
            }

            assert cx.getNodeFactory().compound_names.size() == 0 : "cleanNodeFactory() should have been called";

            if (source.isTextBased())
            {
                Parser parser = new Parser(cx, source.getInputText(), path, as3Configuration.doc(), false);
                node = parser.parseProgram();

                source.close();
                cleanNodeFactory(cx.getNodeFactory());
            }
            else
            {
                BufferedInputStream in = null;

                try
                {
                    in = new BufferedInputStream(source.getInputStream());
                    Parser parser = null;
                    if (as3Configuration.doc())
                    {
                        if (as3Configuration.getEncoding() == null)
                        {
                            parser = new Parser(cx, in, path, true, false);
                        }
                        else
                        {
                            parser = new Parser(cx, in, path, as3Configuration.getEncoding(), true, false);
                        }
                    }
                    else
                    {
                        if (as3Configuration.getEncoding() == null)
                        {
                            parser = new Parser(cx, in, path);
                        }
                        else
                        {
                            parser = new Parser(cx, in, path, as3Configuration.getEncoding());
                        }
                    }
                    node = parser.parseProgram();

                    cleanNodeFactory(cx.getNodeFactory());
                }
                catch (IOException ex)
                {
                    ThreadLocalToolkit.logError(source.getNameForReporting(), ex.getLocalizedMessage());
                }
                finally
                {
                    if (in != null)
                    {
                        try
                        {
                            in.close();
                        }
                        catch (IOException ex)
                        {
                        }
                    }
                }
            }

            if (ThreadLocalToolkit.errorCount() > 0)
            {
                return null;
            }
        }

    // conditional compilation: run the AS Configurator over the syntax tree
    // (this must be done before transferDefinitions(), as early as possible after parsing)
    node.evaluate(cx, new ConfigurationEvaluator());

        if (ThreadLocalToolkit.errorCount() > 0)
        {
            return null;
        }
       
        if (unit == null)
        {
            unit = source.newCompilationUnit(node, context);
        }

    SyntaxTreeEvaluator treeEvaluator = new SyntaxTreeEvaluator(unit);
    treeEvaluator.setLocalizationManager(ThreadLocalToolkit.getLocalizationManager());
    node.evaluate(cx, treeEvaluator);

    if (ThreadLocalToolkit.errorCount() > 0)
    {
      return null;
    }

    int size = (node.statements != null) ? node.statements.items.size() : 0;
    List<Node> definitions = new ArrayList<Node>((source.isSourcePathOwner() || source.isSourceListOwner() ||
                                  source.isResourceBundlePathOwner()) ? 1 : size);
    boolean inPackage = false;

    for (int i = 0; i < size; i++)
    {
      Node n = node.statements.items.get(i);
      if (n instanceof PackageDefinitionNode)
      {
        inPackage = !inPackage;
      }
      else if (n.isDefinition() && inPackage)
      {
        definitions.add(n);
      }
    }

    // context.setAttribute("definitions", definitions);
    transferDefinitions(unit.topLevelDefinitions, definitions);

    InheritanceEvaluator inheritanceEvaluator = new InheritanceEvaluator();
    node.evaluate(cx, inheritanceEvaluator);
 
        for (Name name : inheritanceEvaluator.getInheritance())
        {
            unit.inheritance.add(name);
        }
 
    TypeTable typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);

        if (typeTable == null)
        {
            typeTable = new TypeTable(symbolTable);
            symbolTable.getContext().setAttribute(AttrTypeTable, typeTable);
        }

    for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).parse1(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return null;
      }
    }

        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.PARSE1);
        }

    return unit;
  }

  public void parse2(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.PARSE2, unit.getSource().getNameForReporting());
        }
       
        if (unit.hasTypeInfo)
        {
            return;
        }

    TypeTable typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);

    for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).parse2(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return;
      }
    }

        // Useful when comparing abstract syntax trees
        /*
        String name = unit.getSource().getName().replace('\\', '/');
        int index = name.lastIndexOf('/');
        String className;

        if (index > 0)
        {
            className = name.substring(index + 1);
        }
        else
        {
            className = name;
        }
       
        flash.swf.tools.SyntaxTreeDumper.dump((ProgramNode) unit.getSyntaxTree(), "C:/tmp/" + className + ".xml");
        */

        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.PARSE2);
        }
  }

  public void analyze1(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.ANALYZE1, unit.getSource().getNameForReporting());
        }
       
        if (unit.hasTypeInfo)
        {
            return;
        }

        TypeTable typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);

    ProgramNode node = (ProgramNode) unit.getSyntaxTree();
    if (node.state != ProgramNode.Inheritance)
    {
      return;
    }

    CompilerContext context = unit.getContext();
    Context cx = context.getAscContext();
    symbolTable.perCompileData.handler = cx.getHandler();

    ObjectValue global = new ObjectValue(cx, new GlobalBuilder(), null);
    cx.pushScope(global); // first scope is always considered the global scope.

    // run FlowAnalyzer
    FlowGraphEmitter flowem = new FlowGraphEmitter(cx, unit.getSource().getName(), false);
    FlowAnalyzer flower = new FlowAnalyzer(flowem);
    context.setAttribute("FlowAnalyzer", flower);

    // 1. ProgramNode.state == Inheritance
    node.evaluate(cx, flower);
    cx.popScope();

    if (ThreadLocalToolkit.errorCount() > 0)
    {
      return;
    }

        // We don't use fa_unresolved, because unit.inheritance is
        // filled in by InheritanceEvaluator, so just clear it out.
        node.fa_unresolved.clear();
    transferDependencies(node.ns_unresolved, unit.namespaces, unit.namespaceHistory);

    // transferDefinitions2(unit.topLevelDefinitions, context);

    unit.typeInfo = node.frame;

        for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).analyze1(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return;
      }
        }
       
        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.ANALYZE1);
        }
  }
 
  public void analyze2(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.ANALYZE2, unit.getSource().getNameForReporting());
        }

        if (unit.hasTypeInfo)
        {
            return;
        }

    TypeTable typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);

    ProgramNode node = (ProgramNode) unit.getSyntaxTree();
    if (node.state != ProgramNode.Else)
    {
      return;
    }

    CompilerContext context = unit.getContext();
    Context cx = context.getAscContext();
    symbolTable.perCompileData.handler = cx.getHandler();

    FlowAnalyzer flower = (FlowAnalyzer) context.getAttribute("FlowAnalyzer");
    context.setAttribute("processed", new HashSet(15));

    inheritSlots(unit, unit.inheritance, symbolTable);
    inheritSlots(unit, unit.namespaces, symbolTable);

    cx.pushScope(node.frame);
    // 2. ProgramNode.state == Else
    node.evaluate(cx, flower);
    cx.popScope();

    if (ThreadLocalToolkit.errorCount() > 0)
    {
      return;
    }

    transferDependencies(node.ce_unresolved, unit.types, unit.typeHistory);
    transferDependencies(node.body_unresolved, unit.types, unit.typeHistory);
    transferDependencies(node.ns_unresolved, unit.namespaces, unit.namespaceHistory);
      transferDependencies(node.rt_unresolved, unit.expressions, unit.expressionHistory);

    // only verify import statements when strict is turned on.
    if (as3Configuration.strict())
    {
      transferImportPackages(node.package_unresolved, unit.importPackageStatements);
      transferImportDefinitions(node.import_def_unresolved, unit.importDefinitionStatements);
    }

    for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).analyze2(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return;
      }
    }

        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.ANALYZE2);
        }
    }

  public void analyze3(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.ANALYZE3, unit.getSource().getNameForReporting());
        }
       
        if (unit.hasTypeInfo)
        {
            return;
        }

    ProgramNode node = (ProgramNode) unit.getSyntaxTree();
    if (node.state == ProgramNode.Inheritance || node.state == ProgramNode.Else)
    {
      return;
    }

    CompilerContext context = unit.getContext();
    Context cx = context.getAscContext();
    symbolTable.perCompileData.handler = cx.getHandler();

    inheritSlots(unit, unit.types, symbolTable);
    inheritSlots(unit, unit.namespaces, symbolTable);

    // C: If --coach is turned on, do inheritSlots for unit.expressions here...
        if (as3Configuration.strict() || as3Configuration.warnings())
        {
        inheritSlots(unit, unit.expressions, symbolTable);
        }

    if (as3Configuration.strict())
    {
      verifyImportPackages(unit.importPackageStatements, context);
      verifyImportDefinitions(unit.importDefinitionStatements, context);
    }

    if (true /*configuration.metadataExport()*/ && ! unit.getSource().isInternal())
        {
            cx.pushScope(node.frame);
          // C: for SWC generation, use debug(). this makes MetaDataEvaluator generate go-to-definition metadata.
          //    it's okay because compc doesn't use PostLink
          //    for debug-mode movies, MetaDataEvaluator will generate go-to-definition metadata.
          //    But PostLink will take them out.
            macromedia.asc.parser.MetaDataEvaluator printer =
                new macromedia.asc.parser.MetaDataEvaluator(as3Configuration.debug(), !as3Configuration.optimize());
            node.evaluate(cx,printer);

          if (as3Configuration.doc() && unit.getSource().isDebuggable())
          {
            StringBuilder out = new StringBuilder();
            out.append("<asdoc>").append("\n");

            ObjectList comments = printer.doccomments;
            int numComments = comments.size();
            for(int x = 0; x < numComments; x++)
            {
              ((DocCommentNode) comments.get(x)).emit(cx,out);
            }
            out.append("\n").append("</asdoc>").append("\n");
          }

          cx.popScope();
        }

        if (ThreadLocalToolkit.errorCount() > 0)
        {
            return;
        }

        // run ConstantEvaluator
    cx.pushScope(node.frame);
    ConstantEvaluator analyzer = new ConstantEvaluator(cx);
    context.setAttribute("ConstantEvaluator", analyzer);
    analyzer.PreprocessDefinitionTypeInfo(cx, node);
    cx.popScope();

    if (ThreadLocalToolkit.errorCount() > 0)
    {
        return;
    }

    TypeTable typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);

    for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).analyze3(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return;
      }
    }
       
        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.ANALYZE3);
        }
  }

  public void analyze4(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.ANALYZE4, unit.getSource().getNameForReporting());
        }
       
    TypeTable typeTable = null;

    if (symbolTable != null)
    {
      typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);
      if (typeTable == null)
      {
        typeTable = new TypeTable(symbolTable);
        symbolTable.getContext().setAttribute(AttrTypeTable, typeTable);
      }
    }

        if (unit.hasTypeInfo)
        {
            for (Map.Entry<String, AbcClass> entry : unit.classTable.entrySet())
            {
                AbcClass c = entry.getValue();
                c.setTypeTable(typeTable);
                symbolTable.registerClass(entry.getKey(), c);
            }

            try
            {
                symbolTable.registerStyles(unit.styles);
            }
            catch (StyleConflictException e)
            {
                // C: assume that StyleConflictException is going to be internationalized...
                ThreadLocalToolkit.logError(unit.getSource().getNameForReporting(), e.getLocalizedMessage());
            }

            evaluateLoaderClassBase(unit, typeTable);
            return;
        }

        ProgramNode node = (ProgramNode) unit.getSyntaxTree();
        if (node.state == ProgramNode.Inheritance || node.state == ProgramNode.Else)
        {
            return;
        }

        CompilerContext context = unit.getContext();
        Context cx = context.getAscContext();
        symbolTable.perCompileData.handler = cx.getHandler();

        // run ConstantEvaluator
        cx.pushScope(node.frame);
        ConstantEvaluator analyzer = (ConstantEvaluator) context.removeAttribute("ConstantEvaluator");
    node.evaluate(cx, analyzer);
    cx.popScope();

    if (ThreadLocalToolkit.errorCount() > 0)
    {
      return;
    }

    // run -strict and -coach
    if (as3Configuration.warnings())
    {
      cx.pushScope(node.frame);

      LintEvaluator lint = new LintEvaluator(cx, unit.getSource().getName(), warnMap);
      node.evaluate(cx, lint);
      cx.popScope();
            lint.simpleLogWarnings(cx, coachWarningsAsErrors);
            // if we want to go back to the verbose style of warnings, uncomment the line below and
            // comment out the line above
            //lint.logWarnings(context.cx);

      lint.clear();
    }

    if (ThreadLocalToolkit.errorCount() > 0)
    {
      return;
    }

    // last step: collect class definitions, add them to the symbol table and the CompilationUnit
        Map classMap = typeTable.createClasses(node.clsdefs, unit.topLevelDefinitions);
        for (Iterator i = classMap.keySet().iterator(); i.hasNext();)
        {
            String className = (String) i.next();
            AbcClass c = (AbcClass) classMap.get(className);
            symbolTable.registerClass(className, c);
            unit.classTable.put(className, c);
        }

        try
        {
            symbolTable.registerStyles(unit.styles);
        }
        catch (StyleConflictException e)
        {
            // C: assume that StyleConflictException is going to be internationalized...
            ThreadLocalToolkit.logError(unit.getSource().getNameForReporting(), e.getLocalizedMessage());
        }

        evaluateLoaderClassBase(unit, typeTable);

    for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).analyze4(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return;
      }
    }

        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.ANALYZE4);
        }
    }


  public void generate(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.GENERATE, unit.getSource().getNameForReporting());
        }
       
        if (unit.hasTypeInfo)
        {
            return;
        }

    TypeTable typeTable = (TypeTable) symbolTable.getContext().getAttribute(AttrTypeTable);

    CompilerContext context = unit.getContext();
    Context cx = context.getAscContext();
    symbolTable.perCompileData.handler = cx.getHandler();

    ProgramNode node = (ProgramNode) unit.getSyntaxTree();

    LineNumberMap map = (LineNumberMap) context.getAttribute("LineNumberMap");

    Emitter emitter = new BytecodeEmitter(cx, unit.getSource(),
                                              as3Configuration.debug() || as3Configuration.verboseStacktraces(),
                                              !as3Configuration.optimize(),
                                              as3Configuration.keepEmbedMetadata(),
                                          as3Configuration.adjustOpDebugLine() ? map : null);

    cx.pushScope(node.frame);
    CodeGenerator generator = new CodeGenerator(emitter);
    if (RuntimeConstants.SWF)
    {
      generator.push_args_right_to_left(true);
    }
    node.evaluate(cx, generator);
    cx.popScope();

    if (ThreadLocalToolkit.errorCount() > 0)
    {
      return;
    }

    emitter.emit(unit.bytes);

    for (int i = 0, length = compilerExtensions.size(); i < length; i++)
    {
      compilerExtensions.get(i).generate(unit, typeTable);

      if (ThreadLocalToolkit.errorCount() > 0)
      {
        return;
      }
    }

    cleanSlots(unit.typeInfo, cx, unit.topLevelDefinitions);
    unit.getContext().removeAscContext();
    cx.setHandler(null);
       
        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.GENERATE);
        }
  }

  public static void cleanSlots(ObjectValue ov, Context cx, QNameList definitions)
  {
        if (ov != null)
        {
            // clear this map because it points to AST nodes.
            ov.getDeferredClassMap().clear();
           
            // clean slots in the ObjectValue
            final Slots ovSlots = ov.slots;
            if (ovSlots != null)
            {
                for (int i = 0, length = ovSlots.size(); i < length; i++)
                {
                    final Slot slot = ovSlots.get(i);
                   
                    // the following block should be relatively in sync with ContextStatics.cleanSlot()
                    if (slot != null)
                    {
                        slot.setImplNode(null);
                    }
                }
            }
        }

        // for each QName definition, clean each slot in TypeValue slot and its prototype
        if (cx != null && definitions != null)
        {
        for (int i = 0, size = definitions.size(); i < size; i++)
        {
          final TypeValue value = cx.userDefined((definitions.get(i)).toString());
          if (value != null)
          {
                    final Slots valueSlots = value.slots;
                    if (valueSlots != null)
                    {
                        for (int j = 0, length = valueSlots.size(); j < length; j++)
                        {
                            ContextStatics.cleanSlot(valueSlots.get(j));
                        }
                    }
                   
                    final ObjectValue proto = value.prototype;
                    if (proto != null)
                    {
                        final Slots protoSlots = proto.slots;
                        if (protoSlots != null)
                        {
                            for (int j = 0, length = protoSlots.size(); j < length; j++)
                            {
                                ContextStatics.cleanSlot(protoSlots.get(j));
                            }
                        }
                    }
          }
            }
    }
  }

  public static void cleanNodeFactory(NodeFactory nodeFactory)
  {
    nodeFactory.pkg_defs.clear();
    nodeFactory.pkg_names.clear();
    nodeFactory.compound_names.clear();
    nodeFactory.current_package = null;
    nodeFactory.dxns = null;
    nodeFactory.use_stmts = null;
  }

  public void postprocess(CompilationUnit unit, SymbolTable symbolTable)
  {
        // This method is never called, because generate() always produces bytecode, which
        // causes CompilerAPI.postprocess() to skip calling the flex2.compiler.mxml.MxmlCompiler
        // postprocess() method.
  }

  private boolean isNotPrivate(AttributeListNode attrs)
  {
        for (int i = 0, size = attrs == null ? 0 : attrs.items.size(); i < size; i++)
        {
            Node n = attrs.items.get(i);
            if (n != null && n.hasAttribute("private"))
            {
              return false;
            }
        }
       
        return true;
  }
 
  private String getPackageDefinition(PackageDefinitionNode pkgdef)
  {
    StringBuilder packageName = new StringBuilder();
   
    if (pkgdef != null)
    {
      List list = pkgdef.name.id.list;
      for (int i = 0, size = list == null ? 0 : list.size(); i < size; i++)
      {
        IdentifierNode node = (IdentifierNode) list.get(i);
        packageName.append(node.name);
        if (i < size - 1)
        {
          packageName.append(".");
        }
      }
    }
   
    return packageName.toString();
  }
 
  private QName getClassDefinition(ClassDefinitionNode def)
  {
    return new QName(getPackageDefinition(def.pkgdef), def.name.name);
  }

  private QName getNamespaceDefinition(NamespaceDefinitionNode def)
  {
    return new QName(getPackageDefinition(def.pkgdef), def.name.name);
  }

  private QName getFunctionDefinition(FunctionDefinitionNode def)
  {
    return new QName(getPackageDefinition(def.pkgdef), def.name.identifier.name);
  }

  private QName getVariableBinding(PackageDefinitionNode pkgdef, VariableBindingNode def)
  {
    return new QName(getPackageDefinition(pkgdef), def.variable.identifier.name);
  }

  private void transferDefinitions(Collection<QName> topLevelDefinitions, List<Node> definitions)
  {
    for (int i = 0, size = definitions.size(); i < size; i++)
    {
      Node n = definitions.get(i);
      if (n instanceof ClassDefinitionNode)
      {
        ClassDefinitionNode def = (ClassDefinitionNode) n;
        if (isNotPrivate(def.attrs))
        {
          topLevelDefinitions.add(getClassDefinition(def));
        }
      }
      else if (n instanceof NamespaceDefinitionNode)
      {
        NamespaceDefinitionNode def = (NamespaceDefinitionNode) n;
               
                // CNDNs are for conditional compilation, and only on the syntax tree for
                // ASC error handling -- they are effectively hidden to us
        if (isNotPrivate(def.attrs) && !(n instanceof ConfigNamespaceDefinitionNode))
        {
          topLevelDefinitions.add(getNamespaceDefinition(def));
        }
      }
      else if (n instanceof FunctionDefinitionNode)
      {
        FunctionDefinitionNode def = (FunctionDefinitionNode) n;
        if (isNotPrivate(def.attrs))
        {
          topLevelDefinitions.add(getFunctionDefinition(def));
        }
      }
      else if (n instanceof VariableDefinitionNode)
      {
        VariableDefinitionNode def = (VariableDefinitionNode) n;
        if (isNotPrivate(def.attrs))
        {
          for (int j = 0, length = def.list == null ? 0 : def.list.size(); j < length; j++)
          {
            VariableBindingNode binding = (VariableBindingNode) def.list.items.get(j);
            topLevelDefinitions.add(getVariableBinding(def.pkgdef, binding));
          }
        }
      }
    }   
  }

//  private void transferDefinitions2(Collection topLevelDefinitions, CompilerContext context)
//  {
//    List definitions = (List) context.removeAttribute("definitions");
//    for (int i = 0, size = definitions.size(); i < size; i++)
//    {
//      Node n = (Node) definitions.get(i);
//      if (n instanceof ClassDefinitionNode)
//      {
//        ClassDefinitionNode def = (ClassDefinitionNode) n;
//        if (def.attrs == null || !def.attrs.hasPrivate)
//        {
//          macromedia.asc.semantics.QName qName = def.cframe.builder.classname;
//          topLevelDefinitions.add(new flex2.compiler.util.QName(qName.ns.name, qName.name));
//        }
//      }
//      else if (n instanceof NamespaceDefinitionNode)
//      {
//        NamespaceDefinitionNode def = (NamespaceDefinitionNode) n;
//        if ((def.attrs == null || !def.attrs.hasPrivate) && !(n instanceof ConfigNamespaceDefinitionNode))
//        {
//          macromedia.asc.semantics.QName qName = def.qualifiedname;
//          topLevelDefinitions.add(new flex2.compiler.util.QName(qName.ns.name, qName.name));
//        }
//      }
//      else if (n instanceof FunctionDefinitionNode)
//      {
//        FunctionDefinitionNode def = (FunctionDefinitionNode) n;
//        if (def.attrs == null || !def.attrs.hasPrivate)
//        {
//          ReferenceValue ref = def.ref;
//          String ns = ref.namespaces.size() == 0 ? "" : ((ObjectValue) ref.namespaces.get(0)).name;
//          topLevelDefinitions.add(new flex2.compiler.util.QName(ns, ref.name));
//        }
//      }
//      else if (n instanceof VariableDefinitionNode)
//      {
//        VariableDefinitionNode def = (VariableDefinitionNode) n;
//        if (def.attrs == null || !def.attrs.hasPrivate)
//        {
//          for (int j = 0, length = def.list == null ? 0 : def.list.size(); j < length; j++)
//          {
//            VariableBindingNode binding = (VariableBindingNode) def.list.items.get(j);
//            ReferenceValue ref = binding.ref;
//            String ns = ref.namespaces.size() == 0 ? "" : ((ObjectValue) ref.namespaces.get(0)).name;
//            topLevelDefinitions.add(new flex2.compiler.util.QName(ns, ref.name));
//          }
//        }
//      }
//      else if (n instanceof ImportDirectiveNode || n instanceof IncludeDirectiveNode || n instanceof UseDirectiveNode)
//      {
//      }
//    }
//  }

  // C: as long as the compiler instance is not shared among multiple concurrent requests, this is okay.
  private final List<String> nsList = new ArrayList<String>();

  private void transferDependencies(Set<ReferenceValue> unresolved, Set<Name> target, MultiNameMap history)
  {
    for (ReferenceValue ref : unresolved)
    {
      nsList.clear();
      for (ObjectValue objectValue : ref.namespaces)
      {
                String ns = null;
                int nsKind = 0;

                if (objectValue instanceof UnresolvedNamespace)
                {
                    UnresolvedNamespace nsValue = (UnresolvedNamespace) objectValue;
                    if( nsValue.resolved )
                    {
                        ns = nsValue.name;
                        nsKind = nsValue.getNamespaceKind();
                    }
                    else
                    {
                        ns = nsValue.ref.name;
                        nsKind = nsValue.getNamespaceKind();
                    }
                }
                else if (objectValue instanceof NamespaceValue)
                {
                    NamespaceValue nsValue = (NamespaceValue) objectValue;
                    ns = nsValue.name;
                    nsKind = nsValue.getNamespaceKind();
                }

                if (ns != null)
                {
                    // C: skip NS_PRIVATE, NS_PROTECTED and NS_STATICPROTECTED. The inheritance relationships should
                    //    take care of PROTECTED...
                    if ((nsKind == Context.NS_PUBLIC || nsKind == Context.NS_INTERNAL) && !nsList.contains(ns))
                    {
                        nsList.add(ns);
                    }
                }
      }
      String[] namespaceURI = new String[nsList.size()];
      nsList.toArray(namespaceURI);

            // Valid references shouldn't have a dot in them, but
            // sometimes ASC creates them.  Filter them out here.
            if ((ref.name.indexOf(".") < 0) && !history.containsKey(namespaceURI, ref.name))
      {
        target.add(new MultiName(namespaceURI, ref.name));
      }
    }

    unresolved.clear();
  }

  private void transferImportPackages(Set<ReferenceValue> unresolved, Set<String> target)
  {
    for (ReferenceValue ref : unresolved)
    {
      target.add(ref.name);
    }

    unresolved.clear();
  }

  private void transferImportDefinitions(Set<ReferenceValue> unresolved, QNameSet target)
  {
    for (ReferenceValue ref : unresolved)
    {
      for (ObjectValue objectValue : ref.namespaces)
      {
                if (objectValue instanceof NamespaceValue)
                {
                    NamespaceValue nsValue = (NamespaceValue) objectValue;
                    String ns = nsValue.name;
                    int nsKind = nsValue.getNamespaceKind();
                    // C: skip NS_PRIVATE, NS_PROTECTED and NS_STATICPROTECTED. The inheritance relationships should
                    //    take care of PROTECTED...
                    if (nsKind == Context.NS_PUBLIC || nsKind == Context.NS_INTERNAL)
                    {
                        target.add(ns, ref.name);
                    }

                    break;
                }
            }
    }

    unresolved.clear();
  }

  private void verifyImportPackages(Set<String> imports, CompilerContext context)
  {
    Context cx = context.getAscContext();

    for (String importName : imports)
    {
      ObjectValue ns = cx.getNamespace(importName);
      if (ns != null)
      {
        ns.setPackage(true);
      }
    }
  }

  private void verifyImportDefinitions(QNameSet imports, CompilerContext context)
  {
    Context cx = context.getAscContext();

    // imports contains only definitions that are available... it doesn't mean that they are linked in.
    for (Iterator i = imports.iterator(); i.hasNext(); )
    {
      QName qName = (QName) i.next();
      // verify import statements
      cx.addValidImport(qName.toString());
    }
  }

    private void inheritSlots(CompilationUnit unit, Set<Name> types, SymbolTable symbolTable)
  {
    CompilerContext context = unit.getContext();
    ProgramNode node = (ProgramNode) unit.getSyntaxTree();
    Context cx = context.getAscContext();
       
    @SuppressWarnings("unchecked")
    Set<String> processed = (Set<String>) context.getAttribute("processed");

    for (Name name : types)
    {
      if (name instanceof flex2.compiler.util.QName)
      {
        flex2.compiler.util.QName qName = (flex2.compiler.util.QName) name;

        Source s = symbolTable.findSourceByQName(qName);
        CompilationUnit u = s.getCompilationUnit();       
        if (unit == u)
        {
          continue;
        }
       
        ObjectValue frame = u.typeInfo;

        if (frame != null && !processed.contains(s.getName()))
        {
          //ThreadLocalToolkit.logDebug("import: " + s.getName() + " --> " + target);
          FlowAnalyzer.inheritContextSlots(frame, node.frame, node.frame.builder, cx);
          processed.add(s.getName());
        }
      }
    }
  }

  public static void evaluateLoaderClassBase(CompilationUnit unit, TypeTable typeTable)
  {
    for (Iterator it = unit.topLevelDefinitions.iterator(); it.hasNext();)
    {
        QName qName = (QName) it.next();

        AbcClass c = typeTable.getClass( qName.toString() );
        if (c == null)
            continue;
        getParentLoader(unit, typeTable, c);
    }
  }

  private static void getParentLoader(CompilationUnit u, TypeTable typeTable, AbcClass c)
  {
        String superTypeName = c.getSuperTypeName();

        if (superTypeName != null)
        {
            AbcClass sc = typeTable.getClass( NameFormatter.toColon(superTypeName) );

            if (sc != null)
            {
                List inherited = sc.getMetaData( "Frame", true );
                String inheritedLoaderClass = null;

                for (Iterator it = inherited.iterator(); it.hasNext();)
                {
                    MetaData md = (MetaData) it.next();

                    String lc = md.getValue( "factoryClass" );
                    if (lc != null)
                    {
                        inheritedLoaderClass = NodeMagic.normalizeClassName( lc );
                        break;
                    }
                }

                u.loaderClassBase = inheritedLoaderClass;
            }
        }
  }

  private void processCoachSettings()
  {
    if (warnMap == null)
    {
      warnMap = LintEvaluator.getWarningDefaults();

      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ArrayToStringChanges), as3Configuration.warn_array_tostring_changes());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_AssignmentWithinConditional), as3Configuration.warn_assignment_within_conditional());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadArrayCast), as3Configuration.warn_bad_array_cast());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadBoolAssignment), as3Configuration.warn_bad_bool_assignment());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadDateCast), as3Configuration.warn_bad_date_cast());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadES3TypeMethod), as3Configuration.warn_bad_es3_type_method());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadES3TypeProp), as3Configuration.warn_bad_es3_type_prop());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadNaNComparision), as3Configuration.warn_bad_nan_comparison());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadNullAssignment), as3Configuration.warn_bad_null_assignment());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadNullComparision), as3Configuration.warn_bad_null_comparison());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BadUndefinedComparision), as3Configuration.warn_bad_undefined_comparison());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_BooleanConstructorWithNoArgs), as3Configuration.warn_boolean_constructor_with_no_args());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ChangesInResolve), as3Configuration.warn_changes_in_resolve());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ClassIsSealed), as3Configuration.warn_class_is_sealed());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ConstNotInitialized), as3Configuration.warn_const_not_initialized());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ConstructorReturnsValue), as3Configuration.warn_constructor_returns_value());

            boolean showDeprecationWarnings = as3Configuration.showDeprecationWarnings();
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_Deprecated), showDeprecationWarnings);
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DeprecatedMessage), showDeprecationWarnings);
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DeprecatedUseReplacement), showDeprecationWarnings);
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DeprecatedSince), showDeprecationWarnings);
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DeprecatedSinceNoReplacement), showDeprecationWarnings);
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DepricatedEventHandlerError), showDeprecationWarnings && as3Configuration.warn_deprecated_event_handler_error());
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DepricatedFunctionError), showDeprecationWarnings && as3Configuration.warn_deprecated_function_error());
            warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DepricatedPropertyError), showDeprecationWarnings && as3Configuration.warn_deprecated_property_error());

      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DuplicateArgumentNames), as3Configuration.warn_duplicate_argument_names());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_DuplicateVariableDef), as3Configuration.warn_duplicate_variable_def());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ForVarInChanges), as3Configuration.warn_for_var_in_changes());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ImportHidesClass), as3Configuration.warn_import_hides_class());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_InstanceOfChanges), as3Configuration.warn_instance_of_changes());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_InternalError), as3Configuration.warn_internal_error());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_LevelNotSupported), as3Configuration.warn_level_not_supported());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_MissingNamespaceDecl), as3Configuration.warn_missing_namespace_decl());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_NegativeUintLiteral), as3Configuration.warn_negative_uint_literal());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_NoConstructor), as3Configuration.warn_no_constructor());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_NoExplicitSuperCallInConstructor), as3Configuration.warn_no_explicit_super_call_in_constructor());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_NoTypeDecl), as3Configuration.warn_no_type_decl());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_NumberFromStringChanges), as3Configuration.warn_number_from_string_changes());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_ScopingChangeInThis), as3Configuration.warn_scoping_change_in_this());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_SlowTextFieldAddition), as3Configuration.warn_slow_text_field_addition());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_UnlikelyFunctionValue), as3Configuration.warn_unlikely_function_value());
      warnMap.put(IntegerPool.getNumber(WarningConstants.kWarning_XML_ClassHasChanged), as3Configuration.warn_xml_class_has_changed());
    }
  }
}
TOP

Related Classes of flex2.compiler.as3.As3Compiler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.