Skip to content

Commit 1ad9e10

Browse files
committed
[generator] Add --with-javadoc-xml=FILE support.
Commit 69e1b80 added `tools/java-source-utils`, which can parse Java source code and extract Javadoc comments into an XML file: $ java -jar "java-source-utils.jar" -v \ $HOME/android-toolchain/sdk/platforms/android-29/android-stubs-src.jar \ --output-javadoc android-javadoc.xml What can we *do* with the generated `android-javadoc.xml`? `android-javadoc.xml` contains parameter names, and thus can be used with `class-parse --docspath`; see commit 806082f. What we *really* want to do is make the Javadoc information *useful* to consumers of the binding assembly. This means that we want a C# XML Documentation file for the binding assembly. The most straightforward way to get a C# XML Documentation File is to emit [C# XML Documentation Comments][0] into the binding source code! Add a new `generator --with-javadoc-xml=FILE` option. When specified, `FILE` will be treated as an XML file containing the output from `java-source-utils.jar --output-javadoc` (see 69e1b80)`, and all `<javadoc/>` elements within the XML file will be associated with C# types and members to emit, based on the `//@jni-signature` and `//@name` attributes, as appropriate. When the bindings are written to disk, the Javadoc comments will be translated to C# XML Documentation comments, in a "best effort" basis. (THIS WILL BE INCOMPLETE.) To perform the Javadoc-to-C# XML Documentation comments conversion, add a new Irony-based grammar to `Java.Interop.Tools.JavaSource.dll`, in the new `Java.Interop.Tools.JavaSource.SourceJavadocToXmldocParser` type, which parses the Javadoc content and translates to XML. TODO: * Properties? [0]: https://docs.microsoft.com/en-us/dotnet/csharp/codedoc
1 parent b588ef5 commit 1ad9e10

32 files changed

+1485
-0
lines changed

src/Java.Interop.Tools.JavaSource/Java.Interop.Tools.JavaSource.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<Project Sdk="Microsoft.NET.Sdk">
33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
5+
<LangVersion>8.0</LangVersion>
56
<ProjectGuid>{5C0B3562-8DA0-4726-9762-75B9709ED6B7}</ProjectGuid>
67
<AssemblyTitle>Java.Interop.Tools.JavaSource</AssemblyTitle>
78
<Company>Microsoft Corporation</Company>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using Irony.Ast;
7+
using Irony.Parsing;
8+
9+
namespace Java.Interop.Tools.JavaSource {
10+
11+
static class IronyExtensions {
12+
13+
public static void MakePlusRule (this NonTerminal star, Grammar grammar, BnfTerm delimiter)
14+
{
15+
star.Rule = grammar.MakePlusRule (star, delimiter);
16+
}
17+
18+
public static void MakeStarRule (this NonTerminal star, Grammar grammar, BnfTerm delimiter, BnfTerm of)
19+
{
20+
star.Rule = grammar.MakeStarRule (star, delimiter, of);
21+
}
22+
23+
public static void MakeStarRule (this NonTerminal star, Grammar grammar, BnfTerm of)
24+
{
25+
star.Rule = grammar.MakeStarRule (star, of);
26+
}
27+
}
28+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Xml.Linq;
7+
8+
using Irony.Ast;
9+
using Irony.Parsing;
10+
11+
namespace Java.Interop.Tools.JavaSource {
12+
13+
sealed class JavadocInfo {
14+
public readonly ICollection<XNode> Exceptions = new Collection<XNode> ();
15+
public readonly ICollection<XNode> Extra = new Collection<XNode> ();
16+
public readonly ICollection<XNode> Remarks = new Collection<XNode> ();
17+
public readonly ICollection<XNode> Parameters = new Collection<XNode> ();
18+
public readonly ICollection<XNode> Returns = new Collection<XNode> ();
19+
20+
public override string ToString ()
21+
{
22+
return new XElement ("Javadoc",
23+
new XElement (nameof (Parameters), Parameters),
24+
new XElement (nameof (Remarks), Remarks),
25+
new XElement (nameof (Returns), Returns),
26+
new XElement (nameof (Exceptions), Exceptions),
27+
new XElement (nameof (Extra), Extra))
28+
.ToString ();
29+
}
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Xml.Linq;
6+
7+
using Irony.Ast;
8+
using Irony.Parsing;
9+
10+
namespace Java.Interop.Tools.JavaSource {
11+
12+
public partial class SourceJavadocToXmldocGrammar {
13+
14+
// https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags
15+
public class BlockTagsBnfTerms {
16+
17+
internal BlockTagsBnfTerms ()
18+
{
19+
}
20+
21+
internal void CreateRules (SourceJavadocToXmldocGrammar grammar)
22+
{
23+
AllBlockTerms.Rule = AuthorDeclaration
24+
| ApiSinceDeclaration
25+
| DeprecatedDeclaration
26+
| DeprecatedSinceDeclaration
27+
| ExceptionDeclaration
28+
| ParamDeclaration
29+
| ReturnDeclaration
30+
| SeeDeclaration
31+
| SerialDataDeclaration
32+
| SerialFieldDeclaration
33+
| SinceDeclaration
34+
| ThrowsDeclaration
35+
| VersionDeclaration
36+
;
37+
BlockValue.Rule = Cdata | grammar.InlineTagsTerms.AllInlineTerms;
38+
BlockValues.MakePlusRule (grammar, BlockValue);
39+
40+
AuthorDeclaration.Rule = "@author" + BlockValue;
41+
AuthorDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
42+
// Ignore; not sure how best to convert to Xmldoc
43+
FinishParse (context, parseNode);
44+
};
45+
46+
ApiSinceDeclaration.Rule = "@apiSince" + BlockValue;
47+
ApiSinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
48+
var p = new XElement ("para", "Added in API level ", AstNodeToXmlContent (parseNode.ChildNodes [1]), ".");
49+
FinishParse (context, parseNode).Remarks.Add (p);
50+
parseNode.AstNode = p;
51+
};
52+
53+
DeprecatedDeclaration.Rule = "@deprecated" + BlockValue;
54+
DeprecatedDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
55+
var p = new XElement ("para", "This member is deprecated. ", AstNodeToXmlContent (parseNode.ChildNodes [1]));
56+
FinishParse (context, parseNode).Remarks.Add (p);
57+
parseNode.AstNode = p;
58+
};
59+
60+
DeprecatedSinceDeclaration.Rule = "@deprecatedSince" + BlockValue;
61+
DeprecatedSinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
62+
var p = new XElement ("para", "This member was deprecated in API level ", AstNodeToXmlContent (parseNode.ChildNodes [1]), ".");
63+
FinishParse (context, parseNode).Remarks.Add (p);
64+
parseNode.AstNode = p;
65+
};
66+
67+
var nonSpaceTerm = new RegexBasedTerminal ("[^ ]", "[^ ]+") {
68+
AstConfig = new AstNodeConfig {
69+
NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value,
70+
},
71+
};
72+
73+
ExceptionDeclaration.Rule = "@exception" + nonSpaceTerm + BlockValue;
74+
ExceptionDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
75+
// TODO: convert `nonSpaceTerm` into a proper CREF
76+
var e = new XElement ("exception",
77+
new XAttribute ("cref", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))),
78+
AstNodeToXmlContent (parseNode.ChildNodes [2]));
79+
FinishParse (context, parseNode).Exceptions.Add (e);
80+
parseNode.AstNode = e;
81+
};
82+
83+
ParamDeclaration.Rule = "@param" + nonSpaceTerm + BlockValue;
84+
ParamDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
85+
var p = new XElement ("param",
86+
new XAttribute ("name", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))),
87+
AstNodeToXmlContent (parseNode.ChildNodes [2]));
88+
FinishParse (context, parseNode).Parameters.Add (p);
89+
parseNode.AstNode = p;
90+
};
91+
92+
ReturnDeclaration.Rule = "@return" + BlockValues;
93+
// ReturnDeclaration.Flags = TermFlags.IsMultiline;
94+
ReturnDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
95+
var r = new XElement ("returns", parseNode.ChildNodes.Skip (1).Select (c => AstNodeToXmlContent (c)));
96+
FinishParse (context, parseNode).Returns.Add (r);
97+
parseNode.AstNode = r;
98+
};
99+
100+
SeeDeclaration.Rule = "@see" + BlockValue;
101+
SeeDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
102+
// TODO: @see supports multiple forms; see: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#see
103+
var e = new XElement ("altmember",
104+
new XAttribute ("cref", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))));
105+
FinishParse (context, parseNode).Extra.Add (e);
106+
parseNode.AstNode = e;
107+
};
108+
109+
SinceDeclaration.Rule = "@since" + BlockValue;
110+
SinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
111+
var p = new XElement ("para", "Added in ", AstNodeToXmlContent (parseNode.ChildNodes [1]), ".");
112+
FinishParse (context, parseNode).Remarks.Add (p);
113+
parseNode.AstNode = p;
114+
};
115+
116+
ThrowsDeclaration.Rule = "@throws" + nonSpaceTerm + BlockValue;
117+
ThrowsDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
118+
// TODO: convert `nonSpaceTerm` into a proper CREF
119+
var e = new XElement ("exception",
120+
new XAttribute ("cref", string.Join ("", AstNodeToXmlContent (parseNode.ChildNodes [1]))),
121+
parseNode.ChildNodes [2].AstNode);
122+
FinishParse (context, parseNode).Exceptions.Add (e);
123+
parseNode.AstNode = e;
124+
};
125+
126+
// Ignore serialization informatino
127+
SerialDeclaration.Rule = "@serial" + BlockValue;
128+
SerialDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
129+
FinishParse (context, parseNode);
130+
};
131+
132+
SerialDataDeclaration.Rule = "@serialData" + BlockValue;
133+
SerialDataDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
134+
FinishParse (context, parseNode);
135+
};
136+
137+
SerialFieldDeclaration.Rule = "@serialField" + BlockValue;
138+
SerialFieldDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
139+
FinishParse (context, parseNode);
140+
};
141+
142+
// Ignore Version
143+
VersionDeclaration.Rule = "@version" + BlockValue;
144+
VersionDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
145+
FinishParse (context, parseNode);
146+
};
147+
}
148+
149+
public readonly NonTerminal AllBlockTerms = new NonTerminal (nameof (AllBlockTerms), ConcatChildNodes);
150+
151+
public readonly Terminal Cdata = new CharacterDataTerminal ("#CDATA", preserveLeadingWhitespace: true);
152+
/*
153+
public readonly Terminal Cdata = new RegexBasedTerminal (nameof (BlockValue), "[^<]*") {
154+
AstConfig = new AstNodeConfig {
155+
NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value.ToString (),
156+
},
157+
};
158+
*/
159+
160+
public readonly NonTerminal BlockValue = new NonTerminal (nameof (BlockValue), ConcatChildNodes);
161+
public readonly NonTerminal BlockValues = new NonTerminal (nameof (BlockValues), ConcatChildNodes);
162+
public readonly NonTerminal AuthorDeclaration = new NonTerminal (nameof (AuthorDeclaration));
163+
public readonly NonTerminal ApiSinceDeclaration = new NonTerminal (nameof (ApiSinceDeclaration));
164+
public readonly NonTerminal DeprecatedDeclaration = new NonTerminal (nameof (DeprecatedDeclaration));
165+
public readonly NonTerminal DeprecatedSinceDeclaration = new NonTerminal (nameof (DeprecatedSinceDeclaration));
166+
public readonly NonTerminal ExceptionDeclaration = new NonTerminal (nameof (ExceptionDeclaration));
167+
public readonly NonTerminal ParamDeclaration = new NonTerminal (nameof (ParamDeclaration));
168+
public readonly NonTerminal ReturnDeclaration = new NonTerminal (nameof (ReturnDeclaration));
169+
public readonly NonTerminal SeeDeclaration = new NonTerminal (nameof (SeeDeclaration));
170+
public readonly NonTerminal SerialDeclaration = new NonTerminal (nameof (SerialDeclaration));
171+
public readonly NonTerminal SerialDataDeclaration = new NonTerminal (nameof (SerialDataDeclaration));
172+
public readonly NonTerminal SerialFieldDeclaration = new NonTerminal (nameof (SerialFieldDeclaration));
173+
public readonly NonTerminal SinceDeclaration = new NonTerminal (nameof (SinceDeclaration));
174+
public readonly NonTerminal ThrowsDeclaration = new NonTerminal (nameof (ThrowsDeclaration));
175+
public readonly NonTerminal VersionDeclaration = new NonTerminal (nameof (VersionDeclaration));
176+
}
177+
}
178+
}

0 commit comments

Comments
 (0)