Package flex2.compiler.i18n

Source Code of flex2.compiler.i18n.I18nCompiler

/*
*
*  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.i18n;                                                  

import flex2.compiler.AbstractSubCompiler;
import flex2.compiler.CompilationUnit;
import flex2.compiler.CompilerBenchmarkHelper;
import flex2.compiler.CompilerContext;
import flex2.compiler.Source;
import flex2.compiler.SymbolTable;
import flex2.compiler.Transcoder;
import flex2.compiler.as3.As3Configuration;
import flex2.compiler.as3.EmbedExtension;
import flex2.compiler.as3.Extension;
import flex2.compiler.common.CompilerConfiguration;
import flex2.compiler.common.MxmlConfiguration;
import flex2.compiler.io.LocalFile;
import flex2.compiler.io.TextFile;
import flex2.compiler.io.VirtualFile;
import flex2.compiler.mxml.lang.StandardDefs;
import flex2.compiler.mxml.rep.AtEmbed;
import flex2.compiler.util.MimeMappings;
import flex2.compiler.util.ThreadLocalToolkit;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
import java.io.File;
import java.io.IOException;

import macromedia.asc.embedding.ConfigVar;
import macromedia.asc.util.ObjectList;

import flash.util.FileUtils;
import flash.util.StringJoiner;
import flash.util.StringUtils;

/**
* Transforms translation files (usually .properties files) into
* classes that extend ResourceBundle.
*
* @author Clement Wong
* @author Brian Deitte
*/
public class I18nCompiler extends AbstractSubCompiler implements flex2.compiler.SubCompiler
{
    private static final String COMPILER_NAME = "i18n";

    public I18nCompiler(final CompilerConfiguration compilerConfig, Transcoder[] transcoders)
    {
      configuration = compilerConfig;
        asc = new flex2.compiler.as3.As3Compiler(new As3Configuration()
        {
            public boolean optimize() { return true; }
            public boolean verboseStacktraces() { return false; }
            public boolean debug() { return false; }
            public boolean strict() { return true; }
          public int dialect() { return compilerConfig.dialect(); }
          public boolean adjustOpDebugLine() { return compilerConfig.adjustOpDebugLine(); }
            public boolean warnings() { return false; }
            public boolean doc() { return false; }
            public boolean getGenerateAbstractSyntaxTree() { return false; }
          public String getEncoding() { return null; }
            public boolean metadataExport() { return false; }
            public boolean showDeprecationWarnings() { return false; }
          public boolean warn_array_tostring_changes() { return false; }
          public boolean warn_assignment_within_conditional() { return false; }
          public boolean warn_bad_array_cast() { return false; }
          public boolean warn_bad_bool_assignment() { return false; }
          public boolean warn_bad_date_cast() { return false; }
          public boolean warn_bad_es3_type_method() { return false; }
          public boolean warn_bad_es3_type_prop() { return false; }
          public boolean warn_bad_nan_comparison() { return false; }
          public boolean warn_bad_null_assignment() { return false; }
          public boolean warn_bad_null_comparison() { return false; }
          public boolean warn_bad_undefined_comparison() { return false; }
          public boolean warn_boolean_constructor_with_no_args() { return false; }
          public boolean warn_changes_in_resolve() { return false; }
          public boolean warn_class_is_sealed() { return false; }
          public boolean warn_const_not_initialized() { return false; }
          public boolean warn_constructor_returns_value() { return false; }
          public boolean warn_deprecated_event_handler_error() { return false; }
          public boolean warn_deprecated_function_error() { return false; }
          public boolean warn_deprecated_property_error() { return false; }
          public boolean warn_duplicate_argument_names() { return false; }
          public boolean warn_duplicate_variable_def() { return false; }
          public boolean warn_for_var_in_changes() { return false; }
          public boolean warn_import_hides_class() { return false; }
          public boolean warn_instance_of_changes() { return false; }
          public boolean warn_internal_error() { return false; }
          public boolean warn_level_not_supported() { return false; }
          public boolean warn_missing_namespace_decl() { return false; }
          public boolean warn_negative_uint_literal() { return false; }
          public boolean warn_no_constructor() { return false; }
          public boolean warn_no_explicit_super_call_in_constructor() { return false; }
          public boolean warn_no_type_decl() { return false; }
          public boolean warn_number_from_string_changes() { return false; }
          public boolean warn_scoping_change_in_this() { return false; }
          public boolean warn_slow_text_field_addition() { return false; }
          public boolean warn_unlikely_function_value() { return false; }
          public boolean warn_xml_class_has_changed() { return false; }
            public ObjectList<ConfigVar> getDefine() { return null; }
            public boolean keepEmbedMetadata() { return false; }
        });

        generatedDir = (compilerConfig.keepGeneratedActionScript() ? compilerConfig.getGeneratedDirectory() : null);
        addCompilerExtension(new EmbedExtension(transcoders, generatedDir, compilerConfig.showDeprecationWarnings()));
        format = I18nUtils.getTranslationFormat(compilerConfig);
        locales = compilerConfig.getLocales();
    }

    private flex2.compiler.as3.As3Compiler asc;
    private TranslationFormat format;
    public String generatedDir;
    private String[] locales;
    private CompilerConfiguration configuration;
   
  public void addCompilerExtension(Extension ext)
  {
    asc.addCompilerExtension(ext);
  }

    /**
     * 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 format.isSupported(mimeType);
    }

    public String[] getSupportedMimeTypes()
    {
        return format.getSupportedMimeTypes();
    }

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

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

        //System.out.println("parse1: " + source.getNameForReporting());
        TranslationInfo[] translations = new TranslationInfo[locales == null ? 0 : locales.length];
        StandardDefs standardDefs = ThreadLocalToolkit.getStandardDefs();
       
        for (int i = 0, len = translations.length; i < len; i++)
        {
            try
            {
                translations[i] = format.getTranslationSet(configuration, symbolTable, source, locales[i], standardDefs);
            }
            catch(TranslationException te)
            {
                ThreadLocalToolkit.logError(te.getMessage());
            }
        }
       
        if (ThreadLocalToolkit.errorCount() > 0)
        {
          return null;
        }

        Source transSource = transform(source, translations);

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

        CompilationUnit ascUnit = asc.parse1(transSource, symbolTable);

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

        flex2.compiler.CompilerContext context = new flex2.compiler.CompilerContext();
        context.setAttribute("ascUnit", ascUnit);
        context.setAttribute(CompilerContext.L10N_ARCHIVE_FILES, new HashMap());

        CompilationUnit unit = source.newCompilationUnit(null, context);

        // when building a SWC, we want to locate all the asset sources and ask compc to put them in the SWC.
        for (int i = 0, len = translations.length; i < len; i++)
        {
          if (translations[i] != null)
          {
            TranslationInfo info = translations[i];
            Set atEmbeds = info.getEmeds();
                if (atEmbeds != null && configuration.archiveClassesAndAssets())
                {
                    @SuppressWarnings("unchecked")
                  Map<String, VirtualFile> archiveFiles = (Map<String, VirtualFile>)context.getAttribute(CompilerContext.L10N_ARCHIVE_FILES);
                   
                  for (Iterator j = atEmbeds.iterator(); j.hasNext(); )
                  {
                    AtEmbed e = (AtEmbed) j.next();
                    String src = (String) e.getAttributes().get(Transcoder.SOURCE);
                    String original = (String) e.getAttributes().get(Transcoder.ORIGINAL);
                    if (src != null)
                    {
                      if (source.getRelativePath().length() == 0)
                      {
                        archiveFiles.put("locale/" + locales[i] + "/" + original, new LocalFile(new File(src)));
                      }
                      else
                      {
                        archiveFiles.put("locale/" + locales[i] + "/" + source.getRelativePath() + "/" + original, new LocalFile(new File(src)));
                      }
                    }
                  }
                }
          }
        }

      Source.transferMetaData(ascUnit, unit);
      Source.transferGeneratedSources(ascUnit, unit);
      Source.transferDefinitions(ascUnit, unit);
      Source.transferInheritance(ascUnit, unit);

        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());
        }

      CompilationUnit ascUnit = (CompilationUnit) unit.getContext().getAttribute("ascUnit");
      Source.transferInheritance(unit, ascUnit);

      asc.parse2(ascUnit, symbolTable);     

    Source.transferAssets(ascUnit, unit);
      Source.transferGeneratedSources(ascUnit, unit);

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

    /**
     * Transforms foo.properties into a Source text file
   * with the following autogenerated code
   * for a resource bundle class:
     *
   * package
   * {
   * import mx.resources.ResourceBundle;
   *
   * [ExcludeClass]
   *
   * public class foo_properties extends ResourceBundle
   * {
   *     public function foo_properties()
   *     {
   *         super("en_US", "foo");
   *     }
   *
   *     override protected function getContent():Object
   *     {
   *         var content:Object =
   *         {
   *             "key1": "value1",
   *             "key2": "value2"
   *         };
    *         return content;
   *     }
    * }
    *
   * }
     */
    private String transform(Source source, TranslationInfo translations,
                 String packageName, String className, String locale)
    {
        String lineSep = System.getProperty("line.separator");
      String bundleName = I18nUtils.bundleNameFromClassName(className);

        String[] codePieces =
        {
          codegenImports(translations.getClassReferences()),
          "[ExcludeClass]", lineSep, lineSep,
          "public class ", className, " extends ResourceBundle", lineSep,
      "{", lineSep,
      codegenAtEmbeds(translations.getEmeds()),
      "    public function ", className, "()",  lineSep,
            "    {", lineSep,
      codegenSuper(locale, bundleName), lineSep,
      "    }", lineSep, lineSep,
      "    override protected function getContent():Object", lineSep,
        "    {", lineSep,
      "        var content:Object =", lineSep,
      "        {", lineSep,
      codegenContent(translations.getTranslationSet()),
      "        };", lineSep,
      "        return content;",  lineSep,
            "    }", lineSep,
            "}", lineSep, lineSep,
        };
       
        return StringJoiner.join(codePieces, null);
    }

    private Source transform(Source source, TranslationInfo[] translations)
    {
        String name = source.getName();
        String relativePath = source.getRelativePath();
        String shortName = source.getShortName();
        String lineSep = System.getProperty("line.separator");
        String packageName = relativePath.replace('/', '.');     

      StringBuilder code = new StringBuilder();     
     
      code.append("package ");
      code.append(packageName);
      code.append(lineSep);
      code.append("{");
      code.append(lineSep);
      code.append(lineSep);
     
      for (int i = 0, len = translations == null ? 0 : translations.length; i < len; i++)
      {
            // A Source instance for a .properties file knows which locale it is for
            // and produces a class name like "en_US$core_properties".
            String className = locales[i] + "$" + shortName + I18nUtils.CLASS_SUFFIX;
        code.append(transform(source, translations[i], packageName, className, locales[i]));
       
        code.append(lineSep);
        code.append(lineSep);
      }
   
      code.append("}");
      code.append(lineSep);

      if (generatedDir != null)
      {
        try
        {
          FileUtils.writeClassToFile(generatedDir, packageName, shortName + I18nUtils.CLASS_SUFFIX + ".as", code.toString());
        }
        catch(IOException ioe)
        {
          ThreadLocalToolkit.logError(ioe.toString());
        }
      }
     
      return new Source(new TextFile(code.toString(), name, source.getParent(),
                       MimeMappings.AS, source.getLastModified()), source);
    }

    private String codegenImports(Set imports)
    {
    String lineSep = System.getProperty("line.separator");
    StringJoiner.ItemStringer itemStringer = new StringJoiner.ItemStringer()
      {
        public String itemToString(Object obj)
        {
          return "import " + (String)obj + ";";
        }
      };
      return StringJoiner.join(imports, lineSep, itemStringer) + lineSep + lineSep;
    }
   
    private String codegenAtEmbeds(Set atEmbeds)
    {
      if (configuration.archiveClassesAndAssets()) return "";
     
    String lineSep = System.getProperty("line.separator");
    StringJoiner.ItemStringer itemStringer = new StringJoiner.ItemStringer()
      {
        public String itemToString(Object obj)
        {
          AtEmbed atEmbed = (AtEmbed)obj;
          return atEmbed.codegenEmbedVar();
        }
      };
    return StringJoiner.join(atEmbeds, lineSep, itemStringer) + lineSep;
    }
   
  private String codegenSuper(String locale, String bundleName)
  {
    // -resource-hack=true is only for compiler performance testing.
    // It allows the Flex 3 compiler to compile the Flex 2 framework
    // and Flex 2 apps.
    // The problem is that the ResourceBundle constructor changed
    // between Flex 2 (where it took no arguments) and Flex 3
    // (where it takes an optional locale and bundleName).
    // Setting -resource-hack=true makes the constructors of the
    // autogenerated bundle classes call super() like they used to,
    // rather than calling super(locale, bundleName).

    return configuration.getResourceHack() ?
         "     super();" :
         "     super(\"" + locale + "\", \"" + bundleName + "\");";
  }
   
  private String codegenContent(Set resources)
  {
    String lineSep = System.getProperty("line.separator");
   
    int version = configuration.getCompatibilityVersion();
    final boolean flex2Compatible = version < MxmlConfiguration.VERSION_3_0;
      
    StringJoiner.ItemStringer itemStringer = new StringJoiner.ItemStringer()
      {
        public String itemToString(Object obj)
        {
            Map.Entry entry = (Map.Entry)obj;
           
            String key = (String)entry.getKey();
             if (!flex2Compatible)
             {
               key = escape(key);
             }
            
            Object value = entry.getValue();
            if (value instanceof ClassReference)
          {
            value = value.toString();
          }
            else if (value instanceof AtEmbed)
            {
              value = (configuration.archiveClassesAndAssets()) ? "\"\"" : ((AtEmbed)value).getPropName();
            }
          else
          {
                 if (!flex2Compatible)
                 {
                   value = escape((String)value);
                 }
            value = "\"" + value + "\"";
          }
            return "            \"" + key + "\": " + value;
        }
      };
      return StringJoiner.join(resources, "," + lineSep, itemStringer) + lineSep;
  }
 
  /*
   * s may contain chars like double-quote, carriage-return, and newline
   * which need to be written out as \", \r, and \n inside an AS String literal.
   */
  private String escape(String s)
  {
    s = StringUtils.formatString(s);
    int n = s.length();
    return s.substring(1, n - 1);
  }

  public void analyze1(CompilationUnit unit, SymbolTable symbolTable)
  {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.ANALYZE1, unit.getSource().getNameForReporting());
        }
       
      CompilationUnit ascUnit = (CompilationUnit) unit.getContext().getAttribute("ascUnit");
      asc.analyze1(ascUnit, symbolTable);

      Source.transferTypeInfo(ascUnit, unit);
      Source.transferNamespaces(ascUnit, unit);

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

    public void analyze2(CompilationUnit unit, SymbolTable symbolTable)
    {
        if (benchmarkHelper != null)
        {
            benchmarkHelper.startPhase(CompilerBenchmarkHelper.ANALYZE2, unit.getSource().getNameForReporting());
        }

        CompilationUnit ascUnit = (CompilationUnit) unit.getContext().getAttribute("ascUnit");
        Source.transferDependencies(unit, ascUnit);
        asc.analyze2(ascUnit, symbolTable);
        Source.transferDependencies(ascUnit, unit);

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

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

        CompilationUnit ascUnit = (CompilationUnit) unit.getContext().getAttribute("ascUnit");
        Source.transferDependencies(unit, ascUnit);
        asc.analyze3(ascUnit, symbolTable);

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

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

        CompilationUnit ascUnit = (CompilationUnit) unit.getContext().getAttribute("ascUnit");
        asc.analyze4(ascUnit, symbolTable);
        Source.transferExpressions(ascUnit, unit);
      // Source.transferLoaderClassBase(ascUnit, unit);
      // Source.transferGeneratedSources(ascUnit, unit);
      // Source.transferClassTable(ascUnit, unit);
      // Source.transferStyles(ascUnit, unit);
        if (benchmarkHelper != null)
        {
            benchmarkHelper.endPhase(CompilerBenchmarkHelper.ANALYZE4);
        }
    }

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

        CompilationUnit ascUnit = (CompilationUnit) unit.getContext().getAttribute("ascUnit");
        asc.generate(ascUnit, symbolTable);

        unit.bytes.clear();
        unit.bytes.addAll(ascUnit.bytes);

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

    public void postprocess(CompilationUnit unit, SymbolTable symbolTable)
    {
    }
}
TOP

Related Classes of flex2.compiler.i18n.I18nCompiler

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.