Skip to content

Commit b7f5020

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 da74abd commit b7f5020

31 files changed

+1363
-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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 MakeStarRule (this NonTerminal star, Grammar grammar, BnfTerm delimiter, BnfTerm of)
14+
{
15+
star.Rule = grammar.MakeStarRule (star, delimiter, of);
16+
}
17+
18+
public static void MakeStarRule (this NonTerminal star, Grammar grammar, BnfTerm of)
19+
{
20+
star.Rule = grammar.MakeStarRule (star, of);
21+
}
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
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+
39+
AuthorDeclaration.Rule = "@author" + BlockValue;
40+
AuthorDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
41+
// Ignore; not sure how best to convert to Xmldoc
42+
FinishParse (context, parseNode);
43+
};
44+
45+
ApiSinceDeclaration.Rule = "@apiSince" + BlockValue;
46+
ApiSinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
47+
var p = new XElement ("para", "Added in API level " + parseNode.ChildNodes [1].AstNode?.ToString ().Trim () + ".");
48+
FinishParse (context, parseNode).Remarks.Add (p);
49+
parseNode.AstNode = p;
50+
};
51+
52+
DeprecatedDeclaration.Rule = "@deprecated" + BlockValue;
53+
DeprecatedDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
54+
var p = new XElement ("para", "This member is deprecated. " + AstNodeToXmlContent (parseNode.ChildNodes [1]));
55+
FinishParse (context, parseNode).Remarks.Add (p);
56+
parseNode.AstNode = p;
57+
};
58+
59+
DeprecatedSinceDeclaration.Rule = "@deprecatedSince" + BlockValue;
60+
DeprecatedSinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
61+
var p = new XElement ("para", "This member was deprecated in API level " + AstNodeToXmlContent (parseNode.ChildNodes [1]) + ".");
62+
FinishParse (context, parseNode).Remarks.Add (p);
63+
parseNode.AstNode = p;
64+
};
65+
66+
var nonSpaceTerm = new RegexBasedTerminal ("[^ ]", "[^ ]+") {
67+
AstConfig = new AstNodeConfig {
68+
NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value,
69+
},
70+
};
71+
72+
ExceptionDeclaration.Rule = "@exception" + nonSpaceTerm + BlockValue;
73+
ExceptionDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
74+
// TODO: convert `nonSpaceTerm` into a proper CREF
75+
var e = new XElement ("exception",
76+
new XAttribute ("cref", AstNodeToXmlContent (parseNode.ChildNodes [1])),
77+
AstNodeToXmlContent (parseNode.ChildNodes [2]));
78+
FinishParse (context, parseNode).Exceptions.Add (e);
79+
parseNode.AstNode = e;
80+
};
81+
82+
ParamDeclaration.Rule = "@param" + nonSpaceTerm + BlockValue;
83+
ParamDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
84+
var p = new XElement ("param",
85+
new XAttribute ("name", parseNode.ChildNodes [1].AstNode?.ToString ()),
86+
parseNode.ChildNodes [2].AstNode.ToString ().Trim ());
87+
FinishParse (context, parseNode).Parameters.Add (p);
88+
parseNode.AstNode = p;
89+
};
90+
91+
ReturnDeclaration.Rule = "@return" + BlockValue;
92+
ReturnDeclaration.Flags = TermFlags.IsMultiline;
93+
ReturnDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
94+
var r = new XElement ("returns", parseNode.ChildNodes [1].AstNode.ToString ());
95+
FinishParse (context, parseNode).Returns.Add (r);
96+
parseNode.AstNode = r;
97+
};
98+
99+
SeeDeclaration.Rule = "@see" + BlockValue;
100+
SeeDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
101+
// TODO: @see supports multiple forms; see: https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#see
102+
var e = new XElement ("altmember",
103+
new XAttribute ("cref", parseNode.ChildNodes [1].AstNode?.ToString ().Trim ()));
104+
FinishParse (context, parseNode).Extra.Add (e);
105+
parseNode.AstNode = e;
106+
};
107+
108+
SinceDeclaration.Rule = "@since" + BlockValue;
109+
SinceDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
110+
var p = new XElement ("para", "Added in " + parseNode.ChildNodes [1].AstNode?.ToString () + ".");
111+
FinishParse (context, parseNode).Remarks.Add (p);
112+
parseNode.AstNode = p;
113+
};
114+
115+
ThrowsDeclaration.Rule = "@throws" + nonSpaceTerm + BlockValue;
116+
ThrowsDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
117+
// TODO: convert `nonSpaceTerm` into a proper CREF
118+
var e = new XElement ("exception",
119+
new XAttribute ("cref", parseNode.ChildNodes [1].AstNode?.ToString ()),
120+
parseNode.ChildNodes [2].AstNode);
121+
FinishParse (context, parseNode).Exceptions.Add (e);
122+
parseNode.AstNode = e;
123+
};
124+
125+
// Ignore serialization informatino
126+
SerialDeclaration.Rule = "@serial" + BlockValue;
127+
SerialDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
128+
FinishParse (context, parseNode);
129+
};
130+
131+
SerialDataDeclaration.Rule = "@serialData" + BlockValue;
132+
SerialDataDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
133+
FinishParse (context, parseNode);
134+
};
135+
136+
SerialFieldDeclaration.Rule = "@serialField" + BlockValue;
137+
SerialFieldDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
138+
FinishParse (context, parseNode);
139+
};
140+
141+
// Ignore Version
142+
VersionDeclaration.Rule = "@version" + BlockValue;
143+
VersionDeclaration.AstConfig.NodeCreator = (context, parseNode) => {
144+
FinishParse (context, parseNode);
145+
};
146+
}
147+
148+
public readonly NonTerminal AllBlockTerms = new NonTerminal (nameof (AllBlockTerms), ConcatChildNodes);
149+
150+
public readonly Terminal Cdata = new CharacterDataTerminal ("#CDATA", preserveLeadingWhitespace: false);
151+
/*
152+
public readonly Terminal Cdata = new RegexBasedTerminal (nameof (BlockValue), "[^<]*") {
153+
AstConfig = new AstNodeConfig {
154+
NodeCreator = (context, parseNode) => parseNode.AstNode = parseNode.Token.Value.ToString (),
155+
},
156+
};
157+
*/
158+
159+
public readonly NonTerminal BlockValue = new NonTerminal (nameof (BlockValue), ConcatChildNodes);
160+
public readonly NonTerminal AuthorDeclaration = new NonTerminal (nameof (AuthorDeclaration));
161+
public readonly NonTerminal ApiSinceDeclaration = new NonTerminal (nameof (ApiSinceDeclaration));
162+
public readonly NonTerminal DeprecatedDeclaration = new NonTerminal (nameof (DeprecatedDeclaration));
163+
public readonly NonTerminal DeprecatedSinceDeclaration = new NonTerminal (nameof (DeprecatedSinceDeclaration));
164+
public readonly NonTerminal ExceptionDeclaration = new NonTerminal (nameof (ExceptionDeclaration));
165+
public readonly NonTerminal ParamDeclaration = new NonTerminal (nameof (ParamDeclaration));
166+
public readonly NonTerminal ReturnDeclaration = new NonTerminal (nameof (ReturnDeclaration));
167+
public readonly NonTerminal SeeDeclaration = new NonTerminal (nameof (SeeDeclaration));
168+
public readonly NonTerminal SerialDeclaration = new NonTerminal (nameof (SerialDeclaration));
169+
public readonly NonTerminal SerialDataDeclaration = new NonTerminal (nameof (SerialDataDeclaration));
170+
public readonly NonTerminal SerialFieldDeclaration = new NonTerminal (nameof (SerialFieldDeclaration));
171+
public readonly NonTerminal SinceDeclaration = new NonTerminal (nameof (SinceDeclaration));
172+
public readonly NonTerminal ThrowsDeclaration = new NonTerminal (nameof (ThrowsDeclaration));
173+
public readonly NonTerminal VersionDeclaration = new NonTerminal (nameof (VersionDeclaration));
174+
}
175+
}
176+
}

0 commit comments

Comments
 (0)