Example #1
0
        void FlattenNestedTypes(JavaPackage package)
        {
            var results = new List <JavaType> ();

            foreach (var t in package.Types)
            {
                Flatten(results, t);
            }
            package.Types = results.ToList();

            void Flatten(List <JavaType> list, JavaType t)
            {
                list.Add(t);
                foreach (var nt in t.Members.OfType <JavaNestedType> ())
                {
                    if (nt.Type == null)
                    {
                        continue;
                    }
                    nt.Type.Name = t.Name + '.' + nt.Type.Name;
                    foreach (var nc in nt.Type.Members.OfType <JavaConstructor> ())
                    {
                        nc.Name = nt.Type.Name;
                    }
                    Flatten(list, nt.Type);
                }
                t.Members = t.Members.Where(_ => !(_ is JavaNestedType)).ToArray();
            }
        }
        public void IntentServiceHack()
        {
            // https://github.com/xamarin/java.interop/issues/717
            var api = JavaApiTestHelper.GetLoadedApi();

            // Create "mono.android.app" package
            var mono_android_app = new JavaPackage(api)
            {
                Name = "mono.android.app", JniName = "mono/android/app"
            };

            api.Packages.Add(mono_android_app.Name, mono_android_app);

            // Remove "android.app.IntentService" type
            var android_app    = api.AllPackages.Single(p => p.Name == "android.app");
            var intent_service = android_app.AllTypes.Single(t => t.Name == "IntentService");

            android_app.RemoveType(intent_service);

            // Create new "mono.android.app.IntentService" type
            var new_intent_service = new JavaClass(mono_android_app)
            {
                Name = intent_service.Name,
            };

            mono_android_app.AddType(new_intent_service);

            api.Resolve();

            // Ensure we can resolve the type by either name
            Assert.AreSame(new_intent_service, api.FindNonGenericType("android.app.IntentService"));
            Assert.AreSame(new_intent_service, api.FindNonGenericType("mono.android.app.IntentService"));
        }
Example #3
0
        void FlattenNestedTypes(JavaPackage package)
        {
            Action <List <JavaType>, JavaType> flatten = null;

            flatten = (list, t) => {
                list.Add(t);
                foreach (var nt in t.Members.OfType <JavaNestedType> ())
                {
                    nt.Type.Name = t.Name + '.' + nt.Type.Name;
                    foreach (var nc in nt.Type.Members.OfType <JavaConstructor> ())
                    {
                        nc.Name = nt.Type.Name;
                    }
                    flatten(list, nt.Type);
                }
                t.Members = t.Members.Where(_ => !(_ is JavaNestedType)).ToArray();
            };
            var results = new List <JavaType> ();

            foreach (var t in package.Types)
            {
                flatten(results, t);
            }
            package.Types = results.ToList();
        }
Example #4
0
        public override bool Execute()
        {
            Log.LogMessage("GenerateParameterNames Task");
            Log.LogMessage("  ApiOutputFile:  {0}", ApiOutputFile);
            Log.LogMessage("  GeneratedFile:  {0}", GeneratedFile);
            Log.LogMessage("  SourceJars:     {0}", string.Join(";", SourceJars.Select(x => x.ItemSpec)));
            Log.LogMessage("  TransformFiles: {0}", string.Join(";", TransformFiles.Select(x => x.ItemSpec)));

            var generatorParameters = new GeneratorParameters
            {
                ReservedPrefix  = ReservedPrefix ?? string.Empty,
                ReservedSuffix  = ReservedSuffix ?? string.Empty,
                ParameterCasing = (TextCasing)Enum.Parse(typeof(TextCasing), ParameterCasing, true),
                ForceMeaningfulParameterNames = ForceMeaningfulParameterNames
            };

            // create the folder
            var dir = Path.GetDirectoryName(GeneratedFile.ItemSpec);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            // read the jar files
            var classPath = new ClassPath()
            {
                ApiSource = "class-parse"
            };

            foreach (var jarFile in SourceJars)
            {
                if (ClassPath.IsJarFile(jarFile.ItemSpec))
                {
                    classPath.Load(jarFile.ItemSpec);
                }
            }

            // build up the object tree
            var metadataElement = classPath.ToXElement();

            // remove any nodes that the user wants
            metadataElement = TransformXml(metadataElement);

            var packages    = JavaPackage.Parse(metadataElement);
            var xParameters = packages.SelectMany(p => p.ToXElement(generatorParameters));

            // create the new xml document
            var xDoc = new XDocument(
                new XElement("metadata",
                             xParameters.ToArray()));

            // make sure we don't have anything not in the api.xml
            RemoveIgnoredApiXmlMembers(xDoc);

            // save
            xDoc.Save(GeneratedFile.ItemSpec);

            return(true);
        }
Example #5
0
        public void GenericDerivation()
        {
            var dic = api.FindType("java.util.Dictionary") as JavaClassModel;

            Assert.IsNotNull(dic, "Dictionary not found");
            Assert.AreEqual(0, dic.GenericInheritanceMapping.Count, "Dictionary should have no mapping.");

            var hashtable = api.FindType("java.util.Hashtable") as JavaClassModel;

            Assert.IsNotNull(hashtable, "Hashtable not found");
            Assert.AreEqual(0, hashtable.GenericInheritanceMapping.Count, "Hashtable should have no mapping.");

            var pkg       = new JavaPackage("com.example", "com/example", null);
            var dummyType = JavaApiTestHelper.CreateClass(pkg, "Dummy");
            var tps       = new JavaTypeParameters(dummyType);

            var props = api.FindType("java.util.Properties") as JavaClassModel;

            Assert.IsNotNull(props, "Properties not found");
            Assert.AreEqual(2, props.GenericInheritanceMapping.Count, "Properties should have no mapping.");

            var k = new JavaTypeReference(new JavaTypeParameter("K", tps), null);
            var v = new JavaTypeReference(new JavaTypeParameter("V", tps), null);

            Assert.IsNotNull(props.GenericInheritanceMapping [k], "Properties: mapping for K not found.");
            Assert.AreEqual("java.lang.Object", props.GenericInheritanceMapping [k].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object.");
            Assert.AreEqual("java.lang.Object", props.GenericInheritanceMapping [v].ReferencedType.FullName, "Properties: mapping for K is not to java.lang.Object.");
        }
        public void TypeReferenceEquals()
        {
            var int_ref = JavaTypeReference.Int;

            Assert.AreEqual(JavaTypeReference.Int, int_ref, "primitive types 2");

            var pkg       = new JavaPackage("com.example", "com/example", null);
            var dummyType = JavaApiTestHelper.CreateClass(pkg, "Dummy");
            var tps       = new JavaTypeParameters(dummyType);
            var gt        = new JavaTypeParameter("T", tps);

            Assert.AreEqual(new JavaTypeReference(gt, null), new JavaTypeReference(new JavaTypeParameter("T", tps), null), "type parameters");
            Assert.AreNotEqual(new JavaTypeReference(gt, null), new JavaTypeReference(new JavaTypeParameter("U", tps), null), "type parameters 2");
            Assert.AreNotEqual(new JavaTypeReference(gt, null), new JavaTypeReference(gt, "[]"), "type parameters: array vs. non-array");
            Assert.AreEqual(new JavaTypeReference(gt, "[]"), new JavaTypeReference(gt, "[]"), "type parameters: array vs. array");

            var type = JavaApiTestHelper.CreateClass(pkg, "T");

            Assert.AreEqual(new JavaTypeReference(type, null, null), new JavaTypeReference(type, null, null), "type vs. type");
            Assert.AreNotEqual(new JavaTypeReference(type, null, "[]"), new JavaTypeReference(type, null, null), "type: array vs. non array");
            Assert.AreNotEqual(new JavaTypeReference(type, null, "[]"), new JavaTypeReference(type, null, "[][]"), "type: array vs. array of array");
            Assert.AreNotEqual(new JavaTypeReference(type, null, null), new JavaTypeReference(new JavaTypeParameter("T", tps), null), "type vs. type parameters");

            Assert.AreNotEqual(new JavaTypeReference(gt, "[]"), new JavaTypeReference(type, null, null), "type: array vs. non array");
            Assert.AreNotEqual(new JavaTypeReference(type, null, "[]"), new JavaTypeReference(type, null, "[][]"), "type: array vs. array of array");
        }
Example #7
0
        public void GenericInheritanceMappings()
        {
            var obj = api.FindType("java.lang.Object") as JavaClassModel;

            Assert.IsNotNull(obj.GenericInheritanceMapping, "java.lang.Object mapping not found");
            Assert.AreEqual(0, obj.GenericInheritanceMapping.Count, "ContentObservable mapping not found");

            var kls = api.FindType("android.database.ContentObservable") as JavaClassModel;
            var map = kls.GenericInheritanceMapping;

            Assert.IsNotNull(map, "ContentObservable mapping not found");
            Assert.AreEqual(1, map.Count, "ContentObservable mapping count unexpected");

            Assert.IsNotNull(map.Keys.First().ReferencedTypeParameter, "key is not GenericTypeParameter");
            Assert.IsNotNull("T", map.Keys.First().ReferencedTypeParameter.Name, "key GenericTypeParameter has unexpected name");
            Assert.IsNotNull(map.Values.First().ReferencedType, "value is not to JavaType");
            Assert.IsNotNull("android.database.ContentObserver", map.Values.First().ReferencedType.FullName, "value JavaType has unexpected name");

            var pkg       = new JavaPackage("com.example", "com/example", null);
            var dummyType = JavaApiTestHelper.CreateClass(pkg, "Dummy");
            var tps       = new JavaTypeParameters(dummyType);
            var gt        = new JavaTypeParameter("T", tps);

            Assert.IsTrue(map.TryGetValue(new JavaTypeReference(gt, null), out var mapped),
                          "Mapped type for generic parameter 'T' not found, or dictionary lookup failed.");

            Assert.AreEqual("android.database.ContentObserver", mapped.ReferencedType.FullName, "unexpected resolved type");
        }
Example #8
0
 void LoadDll(string file, string sourceIdentifier = null)
 {
     foreach (var ta in AssemblyDefinition.ReadAssembly(file).Modules.SelectMany(m => m.Types.SelectMany(t => FlattenTypeHierarchy(t)))
              .Where(ta => !ta.Name.EndsWith("Invoker", StringComparison.Ordinal) && !ta.Name.EndsWith("Implementor", StringComparison.Ordinal))
              .Select(t => new Tuple <TypeDefinition, CustomAttribute> (t, GetRegisteredAttribute(t)))
              .Where(p => p.Item2 != null))
     {
         var td   = ta.Item1;
         var tatt = PopulateRegisterAttributeInfo(ta.Item2, true);
         var pkg  = Api.Packages.FirstOrDefault(p => p.Name == tatt.Package);
         if (pkg == null)
         {
             Api.Packages.Add(pkg = new JavaPackage(Api)
             {
                 Name = tatt.Package
             });
         }
         var type = td.IsInterface ? (JavaType) new JavaInterface(pkg) : new JavaClass(pkg);
         type.Name = tatt.Name;
         type.SetExtension(td);
         pkg.Types.Add(type);
         foreach (var fa in td.Fields
                  .Select(f => new Tuple <FieldDefinition, CustomAttribute> (f, GetRegisteredAttribute(f)))
                  .Where(p => p.Item2 != null))
         {
             var matt = PopulateRegisterAttributeInfo(fa.Item2);
             var f    = new JavaField(type)
             {
                 Name = matt.Name, Static = fa.Item1.IsStatic, Final = fa.Item1.HasConstant
             };
             f.SetExtension(fa.Item1);
             type.Members.Add(f);
         }
         foreach (var ma in GetAllMethods(td)
                  .Where(m => m != null)
                  .Select(m => new Tuple <MethodDefinition, CustomAttribute> (m, GetRegisteredAttribute(m)))
                  .Where(p => p.Item2 != null))
         {
             var matt = PopulateRegisterAttributeInfo(ma.Item2);
             var m    = new JavaMethod(type)
             {
                 Name = matt.Name, Abstract = ma.Item1.IsAbstract, Static = ma.Item1.IsStatic
             };
             var jniParameters = matt.JniSignature.Substring(0, matt.JniSignature.IndexOf(')')).Substring(1);
             m.Return     = ParseJniParameters(matt.JniSignature.Substring(matt.JniSignature.IndexOf(')') + 1)).First();
             m.Parameters = ParseJniParameters(jniParameters)
                            .Zip(ma.Item1.Parameters, (s, mp) => new { Type = s, ManagedParameter = mp })
                            .Select(_ => new JavaParameter(m)
             {
                 Name = _.ManagedParameter.Name, Type = _.Type
             })
                            .ToArray();
             m.SetExtension(ma.Item1);
             type.Members.Add(m);
         }
     }
     FillSourceIdentifier(Api, sourceIdentifier ?? file);
 }
        public static JavaClassModel ParseClass(JavaPackage package, XElement element)
        {
            var model = new JavaClassModel(
                javaPackage: package,
                javaNestedName: element.XGetAttribute("name"),
                javaVisibility: element.XGetAttribute("visibility"),
                javaAbstract: element.XGetAttributeAsBool("abstract"),
                javaFinal: element.XGetAttributeAsBool("final"),
                javaBaseType: element.XGetAttribute("extends"),
                javaBaseTypeGeneric: element.XGetAttribute("extends-generic-aware"),
                javaDeprecated: element.XGetAttribute("deprecated"),
                javaStatic: element.XGetAttributeAsBool("static"),
                jniSignature: element.XGetAttribute("jni-signature"),
                baseTypeJni: element.XGetAttribute("jni-extends")
                );

            if (element.XGetAttribute("merge.SourceFile") is string source && source.HasValue())
            {
                model.PropertyBag.Add("merge.SourceFile", source);
            }
            if (element.XGetAttribute("deprecated-since") is string dep && dep.HasValue())
            {
                model.PropertyBag.Add("deprecated-since", dep);
            }

            if (element.Element("typeParameters") is XElement tp)
            {
                ParseTypeParameters(model.TypeParameters, tp);
            }

            foreach (var child in element.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "constructor":
                    model.Constructors.Add(ParseConstructor(model, child));
                    break;

                case "field":
                    model.Fields.Add(ParseField(model, child));
                    break;

                case "implements":
                    model.Implements.Add(ParseImplements(child));
                    break;

                case "method":
                    model.Methods.Add(ParseMethod(model, child));
                    break;
                }
            }

            return(model);
        }
        public static JavaInterfaceModel ParseInterface(JavaPackage package, XElement element)
        {
            var nested_name   = element.XGetAttribute("name");
            var visibility    = element.XGetAttribute("visibility");
            var deprecated    = element.XGetAttribute("deprecated");
            var is_static     = element.XGetAttribute("static") == "true";
            var jni_signature = element.XGetAttribute("jni-signature");

            var model = new JavaInterfaceModel(package, nested_name, visibility, deprecated, is_static, jni_signature);

            if (element.XGetAttribute("merge.SourceFile") is string source && source.HasValue())
            {
                model.PropertyBag.Add("merge.SourceFile", source);
            }
            if (element.XGetAttribute("deprecated-since") is string dep && dep.HasValue())
            {
                model.PropertyBag.Add("deprecated-since", dep);
            }

            if (element.Element("typeParameters") is XElement tp)
            {
                ParseTypeParameters(model.TypeParameters, tp);
            }

            foreach (var child in element.Elements())
            {
                switch (child.Name.LocalName)
                {
                case "field":
                    model.Fields.Add(ParseField(model, child));
                    break;

                case "implements":
                    model.Implements.Add(ParseImplements(child));
                    break;

                case "method":
                    if (child.XGetAttribute("synthetic") != "true")
                    {
                        model.Methods.Add(ParseMethod(model, child));
                    }
                    break;
                }
            }

            return(model);
        }
Example #11
0
        JavaPackage EnsurePackage(string path)
        {
            JavaPackage cp = this;

            foreach (var token in path.Split('/'))
            {
                var cp1 = cp.Packages.GetByName(token);
                if (cp1 == null)
                {
                    cp1 = new JavaPackage(token, cp);
                    cp.Packages.Add(cp1);
                }

                cp = cp1;
            }

            return(cp);
        }
Example #12
0
        public void JavaCloneTest()
        {
            var parentPackage = new JavaPackage("parent");
            var childPackage  = new JavaPackage("child");
            var classType1    = new JavaClass("class1");
            var classType2    = new JavaClass("class2");

            childPackage.AddNestedChild(classType1);
            childPackage.AddNestedChild(classType2);
            parentPackage.AddNestedChild(childPackage);

            var otherParent = parentPackage.Clone(true);
            var otherChild  = (JavaPackage)parentPackage.NestedChilds.First();

            otherParent.NestedChilds.Count().ShouldBe(1);
            otherParent.Name.ShouldBe(parentPackage.Name);
            otherChild.NestedChilds.Count().ShouldBe(2);
            otherChild.Name.ShouldBe(childPackage.Name);
            otherChild.NestedChilds.First().Name.ShouldBe(classType1.Name);
            otherChild.NestedChilds.Last().Name.ShouldBe(classType2.Name);
        }
        public static JavaClassModel CreateClass(JavaPackage javaPackage, string javaNestedName, string javaVisibility = "public", bool javaAbstract = false, bool javaFinal = false, string javaBaseType = "java.lang.Object", string javaBaseTypeGeneric = "java.lang.Object", string javaDeprecated = "not deprecated", bool javaStatic = false, string jniSignature = "", string baseTypeJni = "java/lang/Object")
        {
            if (string.IsNullOrWhiteSpace(jniSignature))
            {
                jniSignature = $"{(!string.IsNullOrWhiteSpace (javaPackage.Name) ? javaPackage.Name + "." : "")}{javaNestedName}".Replace('.', '/');
            }

            var klass = new JavaClassModel(
                javaPackage: javaPackage,
                javaNestedName: javaNestedName,
                javaVisibility: javaVisibility,
                javaAbstract: javaAbstract,
                javaFinal: javaFinal,
                javaBaseType: javaBaseType,
                javaBaseTypeGeneric: javaBaseTypeGeneric,
                javaDeprecated: javaDeprecated,
                javaStatic: javaStatic,
                jniSignature: jniSignature,
                baseTypeJni: baseTypeJni
                );

            return(klass);
        }
Example #14
0
        /*
         *
         * The DroidDoc format from API Level 16 to 23, the format is:
         *
         * - All pages have ToC links and body (unlike standard JavaDoc which is based on HTML frames).
         * - The actual doc section is a div element whose id is "doc-col".
         * - The "doc-col" div element has a section div element whose id is "jd-header" and another one with id "jd-content".
         * - "jd-header" div element contains the type signature (modifiers, name, and inheritance).
         * - Here we care only about type name and kind (whether it is a class or interface).
         *  - Generic arguments are insignificant.
         * - In the following terms I explain the "correct" (or "expected") document structure, but in fact
         * Google completely broke it and it is impossible to retrieve the document tree like this.
         * We workaround this issue by changing the strategy "iterate children of 'jd-content'"
         * with "iterate descendants of 'jd-content'"... It occurs only in API Level 15 or later.
         * - "jd-content" div element contains a collection of sections. Each section consists of:
         *  - an "h2" element whose value text indicates the section name ("Public Constructors", "Protected Methods" etc.)
         *    - There was an issue in javax/xml/validation/SchemaFactory.html in API Level 15 that the method details contain
         *      "h2" and confuses the parser. To workaround this, we accept only limited kind of values.
         *  - the content, which follows the h2 element.
         * - The section content is a collection of members. Each member consists of:
         *  - an anchor ("A") element with "name" attribute, and
         *  - a div element which contains an h4 child element whose class contains "jd-details-title".
         * - The h4 element contains the member signature. We parse it and retrieve the method name and list of parameters.
         *  - Parameters are tokenized by ", ".
         *  - Note that the splitter contains a white space which disambiguates any use of generic arguments (we don't want to split "Foo<K,V> bar" as "Foo<K" and "V> bar")
         *
         * API Level 10 to 15 has slightly different format:
         *
         * - There is no "doc-col" element. But "jd-header" and "jd-content" are still alive.
         *
         */
        public void Import(ImporterOptions options)
        {
            options.DiagnosticWriter.WriteLine(options.DocumentDirectory);

            string referenceDocsTopDir = Path.Combine(options.DocumentDirectory, "reference");
            var    htmlFiles           = Directory.GetDirectories(referenceDocsTopDir).SelectMany(d => Directory.GetFiles(d, "*.html", SearchOption.AllDirectories));

            var api = new JavaApi();

            foreach (var htmlFile in htmlFiles)
            {
                // skip irrelevant files.
                if (excludes.Any(x => htmlFile.EndsWith(x, StringComparison.OrdinalIgnoreCase)))
                {
                    continue;
                }
                var packageName = Path.GetDirectoryName(htmlFile).Substring(referenceDocsTopDir.Length + 1).Replace('/', '.');
                if (options.FrameworkOnly && non_frameworks.Any(n => packageName.StartsWith(n, StringComparison.Ordinal)))
                {
                    continue;
                }

                options.DiagnosticWriter.WriteLine("-- " + htmlFile);

                var doc = new HtmlLoader().GetJavaDocFile(htmlFile);

                var header  = doc.Descendants().FirstOrDefault(e => e.Attribute("id")?.Value == "jd-header");
                var content = doc.Descendants().FirstOrDefault(e => e.Attribute("id")?.Value == "jd-content");

                if (header == null || content == null)
                {
                    continue;
                }

                var apiSignatureTokens = header.Value.Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ').Trim();
                if (apiSignatureTokens.Contains("extends "))
                {
                    apiSignatureTokens = apiSignatureTokens.Substring(0, apiSignatureTokens.IndexOf("extends ", StringComparison.Ordinal)).Trim();
                }
                if (apiSignatureTokens.Contains("implements "))
                {
                    apiSignatureTokens = apiSignatureTokens.Substring(0, apiSignatureTokens.IndexOf("implements ", StringComparison.Ordinal)).Trim();
                }
                bool isClass = apiSignatureTokens.Contains("class");
                options.DiagnosticWriter.WriteLine(apiSignatureTokens);

                var javaPackage = api.Packages.FirstOrDefault(p => p.Name == packageName);
                if (javaPackage == null)
                {
                    javaPackage = new JavaPackage(api)
                    {
                        Name = packageName
                    };
                    api.Packages.Add(javaPackage);
                }

                var javaType = isClass ? (JavaType) new JavaClass(javaPackage) : new JavaInterface(javaPackage);
                javaType.Name = apiSignatureTokens.Substring(apiSignatureTokens.LastIndexOf(' ') + 1);
                javaPackage.Types.Add(javaType);

                string sectionType = null;
                var    sep         = new string [] { ", " };
                var    ssep        = new char [] { ' ' };
                foreach (var child in content.Descendants())
                {
                    if (child.Name == "h2")
                    {
                        var value = child.Value;
                        switch (value)
                        {
                        case "Public Constructors":
                        case "Protected Constructors":
                        case "Public Methods":
                        case "Protected Methods":
                            sectionType = value;
                            break;
                        }
                        continue;
                    }

                    if (sectionType == null)
                    {
                        continue;
                    }

                    if (child.Name != "a" || child.Attribute("name") == null)
                    {
                        continue;
                    }

                    var h4 = child.XPathSelectElement("following-sibling::div/h4[contains(@class, 'jd-details-title')]");
                    if (h4 == null)
                    {
                        continue;
                    }

                    string sigTypeOnly    = child.Attribute("name").Value;
                    string sigTypeAndName = h4.Value.Replace('\n', ' ').Replace('\r', ' ').Trim();
                    if (!sigTypeAndName.Contains('('))
                    {
                        continue;
                    }
                    JavaMethodBase javaMethod = null;
                    string         name       = sigTypeAndName.Substring(0, sigTypeAndName.IndexOf('(')).Split(ssep, StringSplitOptions.RemoveEmptyEntries).Last();
                    switch (sectionType)
                    {
                    case "Public Constructors":
                    case "Protected Constructors":
                        javaMethod = new JavaConstructor(javaType)
                        {
                            Name = name
                        };
                        break;

                    case "Public Methods":
                    case "Protected Methods":
                        string mname = sigTypeAndName.Substring(0, sigTypeAndName.IndexOf('('));
                        javaMethod = new JavaMethod(javaType)
                        {
                            Name = name
                        };
                        break;
                    }
                    javaType.Members.Add(javaMethod);

                    var paramTypes = SplitTypes(sigTypeOnly.Substring(sigTypeOnly.IndexOf('(') + 1).TrimEnd(')'), 0).ToArray();
                    var parameters = sigTypeAndName.Substring(sigTypeAndName.IndexOf('(') + 1).TrimEnd(')')
                                     .Split(sep, StringSplitOptions.RemoveEmptyEntries)
                                     .Select(s => s.Trim())
                                     .ToArray();
                    foreach (var p in paramTypes.Zip(parameters, (to, tn) => new { Type = to, TypeAndName = tn })
                             .Select(pp => new { Type = pp.Type, Name = pp.TypeAndName.Split(' ') [1] }))
                    {
                        javaMethod.Parameters.Add(new JavaParameter(javaMethod)
                        {
                            Name = p.Name, Type = p.Type
                        });
                    }
                }
                javaType.Members = javaType.Members.OfType <JavaMethodBase> ()
                                   .OrderBy(m => m.Name + "(" + string.Join(",", m.Parameters.Select(p => p.Type)) + ")")
                                   .ToArray();
            }
            foreach (var pkg in api.Packages)
            {
                pkg.Types = pkg.Types.OrderBy(t => t.Name).ToArray();
            }
            api.Packages = api.Packages.OrderBy(p => p.Name).ToArray();

            if (options.OutputTextFile != null)
            {
                api.WriteParameterNamesText(options.OutputTextFile);
            }
            if (options.OutputXmlFile != null)
            {
                api.WriteParameterNamesXml(options.OutputXmlFile);
            }
        }
Example #15
0
        /// <summary>
        /// Parse .class files using BigEndianBinaryReader.
        /// </summary>
        /// <param name="name">Class name</param>
        /// <param name="parent">The package that contains this class</param>
        /// <param name="reader">The reader to get binary data</param>
        public ClassFile(string name, JavaPackage parent, BigEndianBinaryReader reader) : base(parent, name, JavaPackageElementTypes.Class)
        {
            if (reader.ReadUInt32() != Magic)
            {
                throw new FormatException();
            }

            MinorVersion = reader.ReadUInt16();
            MajorVersion = reader.ReadUInt16();

            ConstantPoolCount = reader.ReadUInt16();
            Constants         = new ConstantInfoBase[ConstantPoolCount];

            for (int i = 1; i < ConstantPoolCount; i++)
            {
                ConstantType tagByte = (ConstantType)reader.ReadByte();
                switch (tagByte)
                {
                case ConstantType.Class:
                    Constants[i] = new ConstantClassInfo(this, reader);
                    break;

                case ConstantType.Fieldref:
                    Constants[i] = new ConstantFieldrefInfo(this, reader);
                    break;

                case ConstantType.Methodref:
                    Constants[i] = new ConstantMethodrefInfo(this, reader);
                    break;

                case ConstantType.InterfaceMethodref:
                    Constants[i] = new ConstantInterfaceMethodrefInfo(this, reader);
                    break;

                case ConstantType.String:
                    Constants[i] = new ConstantStringInfo(this, reader);
                    break;

                case ConstantType.Integer:
                    Constants[i] = new ConstantIntegerInfo(this, reader);
                    break;

                case ConstantType.Float:
                    Constants[i] = new ConstantFloatInfo(this, reader);
                    break;

                case ConstantType.Long:
                    Constants[i++] = new ConstantLongInfo(this, reader);
                    break;

                case ConstantType.Double:
                    Constants[i++] = new ConstantDoubleInfo(this, reader);
                    break;

                case ConstantType.NameAndType:
                    Constants[i] = new ConstantNameAndTypeInfo(this, reader);
                    break;

                case ConstantType.MethodHandle:
                    Constants[i] = new ConstantMethodHandleInfo(this, reader);
                    break;

                case ConstantType.MethodType:
                    Constants[i] = new ConstantMethodType(this, reader);
                    break;

                case ConstantType.InvokeDynamic:
                    Constants[i] = new ConstantInvokeDynamicInfo(this, reader);
                    break;

                case ConstantType.Utf8:
                    Constants[i] = new ConstantUtf8Info(this, reader);
                    break;

                default:
                    throw new InvalidOperationException("Unknown Constant Pool Type");
                }
            }

            ClassAccessFlag = (ClassAccessFlags)reader.ReadUInt16();

            ThisClassIndex  = reader.ReadUInt16();
            SuperClassIndex = reader.ReadUInt16();

            InterfacesCount   = reader.ReadUInt16();
            InterfacesIndexes = new ushort[InterfacesCount];
            for (int i = 0; i < InterfacesCount; i++)
            {
                InterfacesIndexes[i] = reader.ReadUInt16();
            }
            Interfaces = new ConstantsArray <ConstantClassInfo>(this, InterfacesIndexes);

            FieldsInfoCount = reader.ReadUInt16();
            Fields          = new FieldInfo[FieldsInfoCount];
            for (int i = 0; i < FieldsInfoCount; i++)
            {
                Fields[i] = new FieldInfo(this, reader);
            }

            MethodsInfoCount = reader.ReadUInt16();
            Methods          = new MethodInfo[MethodsInfoCount];
            for (int i = 0; i < MethodsInfoCount; i++)
            {
                Methods[i] = new MethodInfo(this, reader);
            }

            AttributesCount = reader.ReadUInt16();
            Attributes      = new AttributeInfo[AttributesCount];
            for (int i = 0; i < AttributesCount; i++)
            {
                Attributes[i] = AttributeInfo.GetAttributeInfo(AttributeTarget.ClassFile, this, reader);
            }
        }
Example #16
0
        public JavaStubGrammar()
        {
            CommentTerminal single_line_comment = new CommentTerminal("SingleLineComment", "//", "\r", "\n");
            CommentTerminal delimited_comment   = new CommentTerminal("DelimitedComment", "/*", "*/");

            NonGrammarTerminals.Add(single_line_comment);
            NonGrammarTerminals.Add(delimited_comment);

            IdentifierTerminal identifier = new IdentifierTerminal("identifier");

            KeyTerm keyword_package      = Keyword("package");
            KeyTerm keyword_import       = Keyword("import");
            KeyTerm keyword_public       = Keyword("public");
            KeyTerm keyword_protected    = Keyword("protected");
            KeyTerm keyword_static       = Keyword("static");
            KeyTerm keyword_final        = Keyword("final");
            KeyTerm keyword_abstract     = Keyword("abstract");
            KeyTerm keyword_synchronized = Keyword("synchronized");
            KeyTerm keyword_default      = Keyword("default");
            KeyTerm keyword_native       = Keyword("native");
            KeyTerm keyword_volatile     = Keyword("volatile");
            KeyTerm keyword_transient    = Keyword("transient");
            KeyTerm keyword_enum         = Keyword("enum");
            KeyTerm keyword_class        = Keyword("class");
            KeyTerm keyword_interface    = Keyword("interface");
            KeyTerm keyword_at_interface = Keyword("@interface");
            KeyTerm keyword_extends      = Keyword("extends");
            KeyTerm keyword_implements   = Keyword("implements");
            KeyTerm keyword_throw        = Keyword("throw");
            KeyTerm keyword_throws       = Keyword("throws");
            KeyTerm keyword_null         = Keyword("null");
            KeyTerm keyword_super        = Keyword("super");
            KeyTerm keyword_true         = Keyword("true");
            KeyTerm keyword_false        = Keyword("false");
            KeyTerm keyword_new          = Keyword("new");

            var compile_unit                         = DefaultNonTerminal("compile_unit");
            var opt_package_decl                     = DefaultNonTerminal("opt_package_declaration");
            var package_decl                         = DefaultNonTerminal("package_declaration");
            var imports                              = DefaultNonTerminal("imports");
            var import                               = DefaultNonTerminal("import");
            var type_decls                           = DefaultNonTerminal("type_decls");
            var type_decl                            = DefaultNonTerminal("type_decl");
            var enum_decl                            = DefaultNonTerminal("enum_decl");
            var enum_body                            = DefaultNonTerminal("enum_body");
            var class_decl                           = DefaultNonTerminal("class_decl");
            var opt_generic_arg_decl                 = DefaultNonTerminal("opt_generic_arg_decl");
            var opt_extends_decl                     = DefaultNonTerminal("opt_extends_decl");
            var opt_implements_decl                  = DefaultNonTerminal("opt_implements_decl");
            var implements_decl                      = DefaultNonTerminal("implements_decl");
            var interface_decl                       = DefaultNonTerminal("interface_decl");
            var iface_or_at_iface                    = DefaultNonTerminal("iface_or_at_iface");
            var type_body                            = DefaultNonTerminal("type_body");
            var type_members                         = DefaultNonTerminal("type_members");
            var type_member                          = DefaultNonTerminal("type_member");
            var nested_type_decl                     = DefaultNonTerminal("nested_type_decl");
            var ctor_decl                            = DefaultNonTerminal("ctor_decl");
            var method_decl                          = DefaultNonTerminal("method_decl");
            var field_decl                           = DefaultNonTerminal("field_decl");
            var opt_field_assignment                 = DefaultNonTerminal("opt_field_assignment");
            var static_ctor_decl                     = DefaultNonTerminal("static_ctor_decl");
            var enum_members_decl                    = DefaultNonTerminal("enum_members_decl");
            var enum_member_initializers             = DefaultNonTerminal("enum_member_initializers");
            var enum_member_initializer              = DefaultNonTerminal("enum_member_initializer");
            var opt_enum_braces                      = DefaultNonTerminal("opt_enum_braces");
            var opt_final_field_assign               = DefaultNonTerminal("opt_final_field_assign");
            var final_field_assign                   = DefaultNonTerminal("final_field_assign");
            var terminate_decl_or_body               = DefaultNonTerminal("terminate_decl_or_body");
            var assignments                          = DefaultNonTerminal("assignments");
            var assignment                           = DefaultNonTerminal("assignment");
            var assign_expr                          = DefaultNonTerminal("assign_expr");
            var rvalue_expressions                   = DefaultNonTerminal("rvalue_expressions");
            var rvalue_expression                    = DefaultNonTerminal("rvalue_expression");
            var array_literal                        = DefaultNonTerminal("array_literal");
            var annotations                          = DefaultNonTerminal("annotations");
            var annotation                           = DefaultNonTerminal("annotation");
            var opt_annotation_args                  = DefaultNonTerminal("opt_annotation_args");
            var annotation_value_assignments         = DefaultNonTerminal("annotation_value_assignments");
            var annot_assign_expr                    = DefaultNonTerminal("annot_assign_expr");
            var modifiers_then_opt_generic_arg       = DefaultNonTerminal("modifiers_then_opt_generic_arg");
            var modifier_or_generic_arg              = DefaultNonTerminal("modifier_or_generic_arg");
            var modifiers                            = DefaultNonTerminal("modifiers");
            var modifier                             = DefaultNonTerminal("modifier");
            var argument_decls                       = DefaultNonTerminal("argument_decls");
            var argument_decl                        = DefaultNonTerminal("argument_decl");
            var comma_separated_types                = DefaultNonTerminal("comma_separated_types");
            var throws_decl                          = DefaultNonTerminal("throws_decl");
            var opt_throws_decl                      = DefaultNonTerminal("opt_throws_decl");
            var type_name                            = DefaultNonTerminal("type_name");
            var dotted_identifier                    = DefaultNonTerminal("dotted_identifier");
            var array_type                           = DefaultNonTerminal("array_type");
            var vararg_type                          = DefaultNonTerminal("vararg_type");
            var generic_type                         = DefaultNonTerminal("generic_type");
            var generic_definition_arguments         = DefaultNonTerminal("generic_definition_arguments");
            var generic_definition_argument          = DefaultNonTerminal("generic_definition_argument");
            var generic_definition_constraints       = DefaultNonTerminal("generic_definition_constraints");
            var generic_definition_arguments_spec    = DefaultNonTerminal("generic_definition_arguments_spec");
            var generic_instance_arguments_spec      = DefaultNonTerminal("generic_instance_arguments_spec");
            var generic_instance_arguments           = DefaultNonTerminal("generic_instance_arguments");
            var generic_instance_argument            = DefaultNonTerminal("generic_instance_argument");
            var generic_instance_identifier_or_q     = DefaultNonTerminal("generic_instance_identifier_or_q");
            var generic_instance_constraints         = DefaultNonTerminal("generic_instance_constraints");
            var generic_instance_constraints_extends = DefaultNonTerminal("generic_instance_constraints_extends");
            var generic_instance_constraints_super   = DefaultNonTerminal("generic_instance_constraints_super");
            var generic_instance_constraint_types    = DefaultNonTerminal("generic_instance_constraint_types");
            var impl_expressions                     = DefaultNonTerminal("impl_expressions");
            var impl_expression                      = DefaultNonTerminal("impl_expression");
            var call_super                           = DefaultNonTerminal("call_super");
            var super_args                           = DefaultNonTerminal("super_args");
            var default_value_expr                   = DefaultNonTerminal("default_value_expr");
            var default_value_casted                 = DefaultNonTerminal("default_value_casted");
            var default_value_literal                = DefaultNonTerminal("default_value_literal");
            var new_array                            = DefaultNonTerminal("new_array");
            var runtime_exception                    = DefaultNonTerminal("runtime_exception");
            var numeric_terminal                     = TerminalFactory.CreateCSharpNumber("numeric_value_literal");

            numeric_terminal.AddPrefix("-", NumberOptions.AllowSign);
            numeric_terminal.AddPrefix("+", NumberOptions.AllowSign);
            //numeric_terminal.AddSuffix ("f");
            numeric_terminal.AddSuffix("L");
            var numeric_literal = DefaultNonTerminal("numeric_literal");
            var string_literal  = TerminalFactory.CreateCSharpString("string_literal");
            var value_literal   = DefaultNonTerminal("value_literal");
            var identifier_wild = DefaultNonTerminal("identifier_wild");

            // <construction_rules>

            compile_unit.Rule     = opt_package_decl + imports + type_decls;
            opt_package_decl.Rule = package_decl | Empty;
            package_decl.Rule     = keyword_package + dotted_identifier + ";";
            imports.Rule          = MakeStarRule(imports, import);
            import.Rule           = keyword_import + dotted_identifier + ";";
            type_decls.Rule       = MakeStarRule(type_decls, type_decl);

            type_decl.Rule = class_decl | interface_decl | enum_decl;
            // FIXME: those modifiers_then_opt_generic_arg should be actually just modifiers... see modifiers_then_opt_generic_arg.Rule below.
            enum_decl.Rule         = annotations + modifiers_then_opt_generic_arg + keyword_enum + identifier + opt_implements_decl + "{" + enum_body + "}";
            enum_body.Rule         = Empty | enum_members_decl + type_members;
            class_decl.Rule        = annotations + modifiers_then_opt_generic_arg + keyword_class + identifier + opt_generic_arg_decl + opt_extends_decl + opt_implements_decl + type_body;
            interface_decl.Rule    = annotations + modifiers_then_opt_generic_arg + iface_or_at_iface + identifier + opt_generic_arg_decl + opt_extends_decl + opt_implements_decl + type_body;
            iface_or_at_iface.Rule = keyword_interface | keyword_at_interface;

            opt_generic_arg_decl.Rule         = Empty | "<" + generic_definition_arguments + ">";
            opt_extends_decl.Rule             = Empty | keyword_extends + implements_decl; // when it is used with an interface, it can be more than one...
            opt_implements_decl.Rule          = Empty | keyword_implements + implements_decl;
            implements_decl.Rule              = MakePlusRule(implements_decl, ToTerm(","), type_name);
            type_body.Rule                    = T("{") + type_members + T("}");
            annotations.Rule                  = MakeStarRule(annotations, annotation);
            annotation.Rule                   = T("@") + dotted_identifier + opt_annotation_args;
            opt_annotation_args.Rule          = Empty | T("(") + annotation_value_assignments + T(")");
            annotation_value_assignments.Rule = rvalue_expression | MakeStarRule(annotation_value_assignments, ToTerm(","), annot_assign_expr);
            annot_assign_expr.Rule            = assign_expr | T("{") + rvalue_expressions + T("}");

            // HACK: I believe this is an Irony bug that adding opt_generic_arg_decl here results in shift-reduce conflict, but it's too complicated to investigate the actual issue.
            // As a workaround I add generic arguments as part of this "modifier" so that it can be safely added to a generic method declaration.
            modifiers_then_opt_generic_arg.Rule = MakeStarRule(modifiers_then_opt_generic_arg, modifier_or_generic_arg);
            modifiers.Rule = MakeStarRule(modifiers, modifier);
            modifier_or_generic_arg.Rule = modifier | generic_definition_arguments_spec;
            modifier.Rule = keyword_public | keyword_protected | keyword_final | keyword_abstract | keyword_synchronized | keyword_default | keyword_native | keyword_volatile | keyword_transient | keyword_static;

            type_members.Rule             = MakeStarRule(type_members, type_member);
            type_member.Rule              = nested_type_decl | ctor_decl | method_decl | field_decl | static_ctor_decl;
            nested_type_decl.Rule         = type_decl;
            enum_members_decl.Rule        = enum_member_initializers + ";";
            enum_member_initializers.Rule = MakeStarRule(enum_member_initializers, ToTerm(","), enum_member_initializer);
            enum_member_initializer.Rule  = annotations + identifier + opt_enum_braces;
            opt_enum_braces.Rule          = Empty | "(" + ")";
            static_ctor_decl.Rule         = annotations + keyword_static + "{" + assignments + "}";
            assignments.Rule              = MakeStarRule(assignments, assignment);
            assignment.Rule         = assign_expr + ";";
            assign_expr.Rule        = identifier + "=" + rvalue_expression;
            rvalue_expressions.Rule = MakeStarRule(rvalue_expressions, ToTerm(","), rvalue_expression);
            rvalue_expression.Rule  = value_literal | new_array | type_name | identifier | array_literal | annotation;
            array_literal.Rule      = "{" + rvalue_expressions + "}";

            field_decl.Rule             = annotations + modifiers_then_opt_generic_arg + type_name + identifier + opt_field_assignment + ";" + opt_final_field_assign;
            opt_field_assignment.Rule   = Empty | "=" + rvalue_expression;
            opt_final_field_assign.Rule = Empty | "{" + assign_expr + ";" + "}";
            terminate_decl_or_body.Rule = ";" | ("{" + impl_expressions + "}") | (keyword_default + default_value_literal + ";");

            ctor_decl.Rule = annotations + modifiers_then_opt_generic_arg + identifier + "(" + argument_decls + ")" + opt_throws_decl + terminate_decl_or_body;             // these Empties can make the structure common to method_decl.

            method_decl.Rule = annotations + modifiers_then_opt_generic_arg + /*opt_generic_arg_decl*/ type_name + identifier + "(" + argument_decls + ")" + opt_throws_decl + terminate_decl_or_body;

            impl_expressions.Rule      = MakeStarRule(impl_expressions, impl_expression);
            impl_expression.Rule       = call_super | runtime_exception | assign_expr;
            call_super.Rule            = keyword_super + "(" + super_args + ")" + ";";
            super_args.Rule            = MakeStarRule(super_args, ToTerm(","), default_value_expr);
            default_value_expr.Rule    = keyword_null | default_value_casted | default_value_literal;
            default_value_casted.Rule  = "(" + type_name + ")" + default_value_expr;
            default_value_literal.Rule = numeric_terminal | "\"\"" | "{" + "}" | keyword_true | keyword_false;
            runtime_exception.Rule     = keyword_throw + keyword_new + identifier + "(\"Stub!\"" + ")" + ";";
            new_array.Rule             = keyword_new + dotted_identifier + "[" + numeric_literal + "]";

            argument_decls.Rule = annotations | MakeStarRule(argument_decls, ToTerm(","), argument_decl);

            argument_decl.Rule = annotations + type_name + identifier;

            throws_decl.Rule           = keyword_throws + comma_separated_types;
            comma_separated_types.Rule = MakeStarRule(comma_separated_types, ToTerm(","), type_name);
            opt_throws_decl.Rule       = Empty | throws_decl;

            type_name.Rule = dotted_identifier | array_type | vararg_type | generic_type;

            vararg_type.Rule = type_name + T("...");
            array_type.Rule  = type_name + ("[") + T("]");

            generic_definition_arguments_spec.Rule = "<" + generic_definition_arguments + ">";
            generic_type.Rule = dotted_identifier + generic_instance_arguments_spec;
            generic_instance_arguments_spec.Rule      = "<" + generic_instance_arguments + ">";
            generic_definition_arguments.Rule         = MakePlusRule(generic_definition_arguments, ToTerm(","), generic_definition_argument);
            generic_definition_argument.Rule          = identifier + generic_definition_constraints;
            generic_definition_constraints.Rule       = Empty | generic_instance_constraints_extends | generic_instance_constraints_super;
            generic_instance_arguments.Rule           = MakePlusRule(generic_instance_arguments, ToTerm(","), generic_instance_argument);
            generic_instance_argument.Rule            = generic_instance_identifier_or_q + generic_instance_constraints;
            generic_instance_identifier_or_q.Rule     = type_name | T("?");
            generic_instance_constraints.Rule         = Empty | generic_instance_constraints_extends | generic_instance_constraints_super;
            generic_instance_constraints_extends.Rule = keyword_extends + generic_instance_constraint_types;
            generic_instance_constraints_super.Rule   = keyword_super + generic_instance_constraint_types;
            generic_instance_constraint_types.Rule    = MakePlusRule(generic_instance_constraint_types, ToTerm("&"), type_name);

            dotted_identifier.Rule = MakePlusRule(dotted_identifier, ToTerm("."), identifier_wild);

            numeric_literal.Rule  = numeric_terminal;
            numeric_literal.Rule |= "(" + numeric_literal + "/" + numeric_literal + ")";
            value_literal.Rule    = string_literal | numeric_literal | keyword_null;
            identifier_wild.Rule  = identifier | "*";

            // Define AST node creators

            Func <string, string> stripGenerics = s => s.IndexOf('<') > 0 ? s.Substring(0, s.IndexOf('<')) : s;

            single_line_comment.AstConfig.NodeCreator = DoNothing;
            delimited_comment.AstConfig.NodeCreator   = DoNothing;
            identifier.AstConfig.NodeCreator          = (ctx, node) => node.AstNode = node.Token.ValueString;
            compile_unit.AstConfig.NodeCreator        = (ctx, node) => {
                ProcessChildren(ctx, node);
                var pkg = new JavaPackage(null)
                {
                    Name = (string)node.ChildNodes [0].AstNode
                };

                foreach (var t in (IEnumerable <JavaType>)node.ChildNodes [2].AstNode)
                {
                    pkg.AddType(t);
                }

                node.AstNode = pkg;
            };
            opt_package_decl.AstConfig.NodeCreator     = SelectSingleChild;
            package_decl.AstConfig.NodeCreator         = SelectChildValueAt(1);
            imports.AstConfig.NodeCreator              = CreateArrayCreator <object> ();
            import.AstConfig.NodeCreator               = SelectChildValueAt(1);
            type_decls.AstConfig.NodeCreator           = CreateArrayCreator <JavaType> ();
            type_decl.AstConfig.NodeCreator            = SelectSingleChild;
            opt_generic_arg_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = node.ChildNodes.Count == 0 ? null : node.ChildNodes [1].AstNode;
            };
            opt_extends_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = node.ChildNodes.Count == 0 ? null : node.ChildNodes [1].AstNode;
            };
            opt_implements_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = node.ChildNodes.Count == 0 ? null : node.ChildNodes [1].AstNode;
            };
            implements_decl.AstConfig.NodeCreator = CreateArrayCreator <string> ();
            Action <ParseTreeNode, JavaType> fillType = (node, type) => {
                var  modsOrTps = (IEnumerable <object>)node.ChildNodes [1].AstNode;
                var  mods      = modsOrTps.OfType <string> ();
                bool isEnum    = node.ChildNodes [2].AstNode as string == "enum";
                type.Abstract      |= mods.Contains("abstract");
                type.Static        |= mods.Contains("static");
                type.Final         |= mods.Contains("final");
                type.Visibility     = mods.FirstOrDefault(s => s == "public" || s == "protected") ?? "";
                type.Name           = (string)node.ChildNodes [3].AstNode;
                type.Deprecated     = ((IEnumerable <string>)node.ChildNodes [0].AstNode).Any(v => v == "java.lang.Deprecated" || v == "Deprecated") ? "deprecated" : "not deprecated";
                type.TypeParameters = isEnum ? null : (JavaTypeParameters)node.ChildNodes [4].AstNode;
                type.Members        = (IList <JavaMember>)node.ChildNodes [isEnum ? 6 : 7].AstNode;
            };

            enum_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                var type = new JavaClass(null)
                {
                    Extends = "java.lang.Enum", Final = true
                };
                var methods = new JavaMember [] {
                    new JavaMethod(null)
                    {
                        Deprecated = "not deprecated",
                        Name       = "valueOf",
                        // Return needs to be filled later, with full package name.
                        Static     = true,
                        Visibility = "public",
                        Parameters = new JavaParameter [] { new JavaParameter(null)
                                                            {
                                                                Name = "name", Type = "java.lang.String"
                                                            } },
                    },
                    new JavaMethod(null)
                    {
                        Deprecated = "not deprecated",
                        Name       = "values",
                        // Return needs to be filled later, with full package name.
                        Static     = true,
                        Visibility = "public",
                        Parameters = new JavaParameter [0],
                    }
                };
                fillType(node, type);
                node.AstNode = type;
            };
            class_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                var exts  = ((IEnumerable <string>)node.ChildNodes [5].AstNode) ?? Enumerable.Empty <string> ();
                var impls = ((IEnumerable <string>)node.ChildNodes [6].AstNode) ?? Enumerable.Empty <string> ();
                var ext   = exts.FirstOrDefault() ?? "java.lang.Object";
                var type  = new JavaClass(null)
                {
                    Extends        = stripGenerics(ext),
                    ExtendsGeneric = ext,
                    Implements     = impls.Select(s => new JavaImplements {
                        Name = stripGenerics(s), NameGeneric = s
                    }).ToArray(),
                };
                fillType(node, type);
                node.AstNode = type;
            };
            interface_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                bool annot = node.ChildNodes [2].AstNode as string == "@interface";
                var  exts  = ((IEnumerable <string>)node.ChildNodes [5].AstNode) ?? Enumerable.Empty <string> ();
                var  impls = ((IEnumerable <string>)node.ChildNodes [6].AstNode) ?? Enumerable.Empty <string> ();
                var  type  = new JavaInterface(null)
                {
                    Implements = exts.Concat(impls).Select(s => new JavaImplements {
                        Name = stripGenerics(s), NameGeneric = s
                    }).ToList(),
                };
                if (annot)
                {
                    type.Implements.Add(new JavaImplements {
                        Name = "java.lang.annotation.Annotation", NameGeneric = "java.lang.annotation.Annotation"
                    });
                }
                fillType(node, type);
                node.AstNode = type;
            };
            iface_or_at_iface.AstConfig.NodeCreator = SelectSingleChild;
            type_body.AstConfig.NodeCreator         = SelectChildValueAt(1);
            type_members.AstConfig.NodeCreator      = CreateArrayCreator <JavaMember> ();
            type_member.AstConfig.NodeCreator       = SelectSingleChild;
            nested_type_decl.AstConfig.NodeCreator  = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = new JavaNestedType(null)
                {
                    Type = (JavaType)node.ChildNodes [0].AstNode
                };
            };
            Action <ParseTreeNode, JavaMethodBase> fillMethodBase = (node, method) => {
                bool ctor      = node.ChildNodes.Count == 8;
                var  modsOrTps = (IEnumerable <object>)node.ChildNodes [1].AstNode;
                var  mods      = modsOrTps.OfType <string> ();
                method.Static            = mods.Contains("static");
                method.Visibility        = mods.FirstOrDefault(s => s == "public" || s == "protected") ?? "";
                method.Name              = (string)node.ChildNodes [ctor ? 2 : 3].AstNode;
                method.Parameters        = ((IEnumerable <JavaParameter>)node.ChildNodes [ctor ? 4 : 5].AstNode).ToArray();
                method.ExtendedSynthetic = mods.Contains("synthetic");
                // HACK: Exception "name" can be inconsistent for nested types, and this nested type detection is hacky.
                Func <string, string> stripPackage = s => {
                    var packageTokens = s.Split('.').TakeWhile(t => !t.Any(c => Char.IsUpper(c)));
                    return(s.Substring(Enumerable.Sum(packageTokens.Select(t => t.Length)) + packageTokens.Count()));
                };
                method.Exceptions = ((IEnumerable <string>)node.ChildNodes [ctor ? 6 : 7].AstNode)
                                    ?.Select(s => new JavaException {
                    Type = s, Name = stripPackage(s)
                })
                                    ?.ToArray();
                method.Deprecated     = ((IEnumerable <string>)node.ChildNodes [0].AstNode).Any(v => v == "java.lang.Deprecated" || v == "Deprecated") ? "deprecated" : "not deprecated";
                method.Final          = mods.Contains("final");
                method.TypeParameters = modsOrTps.OfType <JavaTypeParameters> ().FirstOrDefault();
            };

            ctor_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                var annots    = node.ChildNodes [0].AstNode;
                var modsOrTps = (IEnumerable <object>)node.ChildNodes [1].AstNode;
                var mods      = modsOrTps.OfType <string> ();
                var ctor      = new JavaConstructor(null);
                fillMethodBase(node, ctor);
                node.AstNode = ctor;
            };
            method_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                var annots    = node.ChildNodes [0].AstNode;
                var modsOrTps = (IEnumerable <object>)node.ChildNodes [1].AstNode;
                var mods      = modsOrTps.OfType <string> ();
                var method    = new JavaMethod(null)
                {
                    Return            = (string)node.ChildNodes [2].AstNode,
                    Abstract          = mods.Contains("abstract"),
                    Native            = mods.Contains("native"),
                    Synchronized      = mods.Contains("synchronized"),
                    ExtendedSynthetic = mods.Contains("synthetic"),
                };
                fillMethodBase(node, method);
                node.AstNode = method;
            };
            field_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                var annots    = node.ChildNodes [0].AstNode;
                var modsOrTps = (IEnumerable <object>)node.ChildNodes [1].AstNode;
                var mods      = modsOrTps.OfType <string> ();
                var value     = node.ChildNodes [4].AstNode?.ToString();
                var type      = (string)node.ChildNodes [2].AstNode;
                node.AstNode = new JavaField(null)
                {
                    Static      = mods.Contains("static"),
                    Visibility  = mods.FirstOrDefault(s => s == "public" || s == "protected") ?? "",
                    Type        = stripGenerics(type),
                    TypeGeneric = type,
                    Name        = (string)node.ChildNodes [3].AstNode,
                    Deprecated  = ((IEnumerable <string>)node.ChildNodes [0].AstNode).Any(v => v == "java.lang.Deprecated" || v == "Deprecated") ? "deprecated" : "not deprecated",
                    Value       = value == "null" ? null : value,               // null will not be explicitly written.
                    Volatile    = mods.Contains("volatile"),
                    Final       = mods.Contains("final"),
                    Transient   = mods.Contains("transient"),
                };
            };
            opt_field_assignment.AstConfig.NodeCreator   = (ctx, node) => node.AstNode = node.ChildNodes.Count > 0 ? node.ChildNodes [1].AstNode : null;
            opt_final_field_assign.AstConfig.NodeCreator = (ctx, node) => node.AstNode = node.ChildNodes.Count > 0 ? node.ChildNodes [1].AstNode : null;
            static_ctor_decl.AstConfig.NodeCreator       = DoNothing;       // static constructors are ignorable.
            enum_body.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                var ml = new List <JavaMember> ();
                foreach (var c in node.ChildNodes)
                {
                    ml.AddRange((IEnumerable <JavaMember>)c.AstNode);
                }
                node.AstNode = ml;
            };
            enum_members_decl.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                if (node.ChildNodes.Count > 0)
                {
                    node.AstNode = ((IEnumerable <string>)node.ChildNodes [0].AstNode)
                                   .Select(s => new JavaField(null)
                    {
                        Name       = s,
                        Final      = true,
                        Deprecated = "not deprecated",
                        Static     = true,
                        // Type needs to be filled later, with full package name.
                        Visibility = "public"
                    });
                }
            };
            enum_member_initializers.AstConfig.NodeCreator = CreateArrayCreator <string> ();
            enum_member_initializer.AstConfig.NodeCreator  = SelectChildValueAt(1);
            opt_enum_braces.AstConfig.NodeCreator          = DoNothing;
            terminate_decl_or_body.AstConfig.NodeCreator   = DoNothing;           // method/ctor body doesn't matter.
            assignments.AstConfig.NodeCreator = CreateArrayCreator <object> ();
            assignment.AstConfig.NodeCreator  = SelectChildValueAt(0);
            assign_expr.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = new KeyValuePair <string, string?> ((string)node.ChildNodes [0].AstNode, node.ChildNodes [2].AstNode?.ToString());
            };
            rvalue_expressions.AstConfig.NodeCreator = CreateArrayCreator <object> ();
            rvalue_expression.AstConfig.NodeCreator  = SelectSingleChild;
            array_literal.AstConfig.NodeCreator      = CreateStringFlattener();
            annotations.AstConfig.NodeCreator        = CreateArrayCreator <string> ();
            annotation.AstConfig.NodeCreator         = (ctx, node) => {
                ProcessChildren(ctx, node.ChildNodes [1]);                  // we only care about name.
                node.AstNode = node.ChildNodes [1].AstNode;
            };
            opt_annotation_args.AstConfig.NodeCreator            = DoNothing;
            annotation_value_assignments.AstConfig.NodeCreator   = DoNothing;
            annot_assign_expr.AstConfig.NodeCreator              = DoNothing;
            modifiers_then_opt_generic_arg.AstConfig.NodeCreator = CreateArrayCreator <object> ();
            modifier_or_generic_arg.AstConfig.NodeCreator        = SelectSingleChild;
            modifiers.AstConfig.NodeCreator      = CreateArrayCreator <string> ();
            modifier.AstConfig.NodeCreator       = CreateStringFlattener();
            argument_decls.AstConfig.NodeCreator = CreateArrayCreator <JavaParameter> ();
            argument_decl.AstConfig.NodeCreator  = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = new JavaParameter(null)
                {
                    Type = (string)node.ChildNodes [1].AstNode, Name = (string)node.ChildNodes [2].AstNode
                };
            };
            opt_throws_decl.AstConfig.NodeCreator       = SelectSingleChild;
            throws_decl.AstConfig.NodeCreator           = SelectChildValueAt(1);
            comma_separated_types.AstConfig.NodeCreator = CreateArrayCreator <string> ();
            type_name.AstConfig.NodeCreator             = SelectSingleChild;
            dotted_identifier.AstConfig.NodeCreator     = CreateStringFlattener(".");
            array_type.AstConfig.NodeCreator            = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = node.ChildNodes [0].AstNode + "[]";
            };
            vararg_type.AstConfig.NodeCreator  = CreateStringFlattener();
            generic_type.AstConfig.NodeCreator = CreateStringFlattener();
            generic_definition_arguments_spec.AstConfig.NodeCreator = SelectChildValueAt(1);
            generic_instance_arguments_spec.AstConfig.NodeCreator   = (ctx, node) => {
                // It is distinct from generic type parameters definition.
                ProcessChildren(ctx, node);
                node.AstNode = "<" + string.Join(", ", (IEnumerable <string>)node.ChildNodes [1].AstNode) + ">";
            };
            generic_definition_arguments.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = new JavaTypeParameters((JavaMethod?)null)
                {
                    TypeParameters = node.ChildNodes.Select(c => c.AstNode).Cast <JavaTypeParameter> ().ToList()
                };
            };
            generic_definition_argument.AstConfig.NodeCreator = (ctx, node) => {
                ProcessChildren(ctx, node);
                node.AstNode = new JavaTypeParameter(null)
                {
                    Name = (string)node.ChildNodes [0].AstNode,
                    GenericConstraints = (JavaGenericConstraints)node.ChildNodes [1].AstNode
                };
            };
            generic_definition_constraints.AstConfig.NodeCreator   = SelectSingleChild;
            generic_instance_arguments.AstConfig.NodeCreator       = CreateArrayCreator <string> ();
            generic_instance_argument.AstConfig.NodeCreator        = CreateStringFlattener();
            generic_instance_identifier_or_q.AstConfig.NodeCreator = SelectSingleChild;
            generic_instance_constraints.AstConfig.NodeCreator     = (ctx, node) => {
                ProcessChildren(ctx, node);
                var c = (JavaGenericConstraints?)node.ChildNodes.FirstOrDefault()?.AstNode;
                if (c != null)
                {
                    node.AstNode = " " + c.BoundsType + " " + string.Join(" & ", c.GenericConstraints.Select(cc => cc.Type));
                }
            };
            AstNodeCreator createGenericConstaints = (ctx, node) => {
                ProcessChildren(ctx, node);
                var cl = ((IEnumerable <string>)node.ChildNodes [1].AstNode).Select(s => new JavaGenericConstraint {
                    Type = s
                });
                node.AstNode = new JavaGenericConstraints()
                {
                    BoundsType         = (string)node.ChildNodes [0].AstNode,
                    GenericConstraints = cl.Any() ? cl.ToArray() : null,
                };
            };

            generic_instance_constraints_extends.AstConfig.NodeCreator = createGenericConstaints;
            generic_instance_constraints_super.AstConfig.NodeCreator   = createGenericConstaints;
            generic_instance_constraint_types.AstConfig.NodeCreator    = CreateArrayCreator <string> ();
            impl_expressions.AstConfig.NodeCreator = CreateArrayCreator <object> ();
            impl_expression.AstConfig.NodeCreator  = SelectSingleChild;
            // each expression item is not seriously processed.
            // They are insignificant except for consts, and for consts they are just string values.
            call_super.AstConfig.NodeCreator            = CreateStringFlattener();
            super_args.AstConfig.NodeCreator            = CreateStringFlattener();
            default_value_expr.AstConfig.NodeCreator    = CreateStringFlattener();
            default_value_casted.AstConfig.NodeCreator  = CreateStringFlattener();
            default_value_literal.AstConfig.NodeCreator = CreateStringFlattener();
            new_array.AstConfig.NodeCreator             = DoNothing;
            runtime_exception.AstConfig.NodeCreator     = CreateStringFlattener();
            Func <string, string, string> stripTail = (s, t) => s.EndsWith(t, StringComparison.Ordinal) ? s.Substring(0, s.Length - t.Length) : s;

            numeric_terminal.AstConfig.NodeCreator = (ctx, node) => node.AstNode = stripTail(stripTail(node.Token.Text, "L"), "f");
            numeric_literal.AstConfig.NodeCreator  = CreateStringFlattener();
            string_literal.AstConfig.NodeCreator   = (ctx, node) => node.AstNode = '"' + node.Token.ValueString + '"';
            value_literal.AstConfig.NodeCreator    = SelectSingleChild;
            identifier_wild.AstConfig.NodeCreator  = SelectSingleChild;

            this.Root = compile_unit;
        }