Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZOOKEEPER-4880: Generate comments from zookeeper.jute into code. #2206

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions zookeeper-jute/src/main/java/org/apache/jute/compiler/JField.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,31 @@

package org.apache.jute.compiler;

import org.apache.jute.compiler.generated.RccConstants;
import org.apache.jute.compiler.generated.Token;

/**
*
*/
public class JField {
private JType mType;
private String mName;

/**
* {@link #mType} of token.
*/
private Token mTypeToken;

private Token previousToken;

/**
* Since we can only get the comments before the token through the {@link Token#specialToken},
* we need to save the next token to get the end-of-line comment.
*
* <p>It may be the type of the next field, or it may be {@link RccConstants#RBRACE_TKN} of the class.
*/
private Token nextToken;

/**
* Creates a new instance of JField.
*/
Expand All @@ -33,6 +51,30 @@ public JField(JType type, String name) {
mName = name;
}

public Token getTypeToken() {
return mTypeToken;
}

public void setTypeToken(Token typeToken) {
this.mTypeToken = typeToken;
}

public Token getNextToken() {
return nextToken;
}

public void setNextToken(Token nextToken) {
this.nextToken = nextToken;
}

public Token getPreviousToken() {
return previousToken;
}

public void setPreviousToken(Token previousToken) {
this.previousToken = previousToken;
}

public String getSignature() {
return mType.getSignature();
}
Expand Down
146 changes: 145 additions & 1 deletion zookeeper-jute/src/main/java/org/apache/jute/compiler/JRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.jute.compiler.generated.RccConstants;
import org.apache.jute.compiler.generated.Token;

/**
*
Expand All @@ -36,24 +39,30 @@ public class JRecord extends JCompType {
private String mName;
private String mModule;
private List<JField> mFields;
private Token mRecordToken;

/**
* Creates a new instance of JRecord.
*/
public JRecord(String name, ArrayList<JField> flist) {
public JRecord(String name, ArrayList<JField> flist, Token recordToken) {
super("struct " + name.substring(name.lastIndexOf('.') + 1),
name.replaceAll("\\.", "::"), getCsharpFQName(name), name, "Record", name, getCsharpFQName("IRecord"));
mFQName = name;
int idx = name.lastIndexOf('.');
mName = name.substring(idx + 1);
mModule = name.substring(0, idx);
mFields = flist;
mRecordToken = recordToken;
}

public String getName() {
return mName;
}

public Token getRecordToken() {
return mRecordToken;
}

public String getCsharpName() {
return "Id".equals(mName) ? "ZKId" : mName;
}
Expand Down Expand Up @@ -208,8 +217,17 @@ public void genCCode(FileWriter h, FileWriter c) throws IOException {
}
}
String recName = getName();

String recordComments = getRecordComments();
if (recordComments != null && !recordComments.isEmpty()) {
h.write(recordComments);
}
h.write("struct " + recName + " {\n");
for (JField f : mFields) {
String fieldComments = getCFieldComments(f);
if (fieldComments != null && !fieldComments.isEmpty()) {
h.write(fieldComments);
}
h.write(f.genCDecl());
}
h.write("};\n");
Expand Down Expand Up @@ -436,10 +454,18 @@ public void genJavaCode(File outputDirectory) throws IOException {
jj.write("import org.apache.jute.*;\n");
jj.write("import org.apache.jute.Record; // JDK14 needs explicit import due to clash with java.lang.Record\n");
jj.write("import org.apache.yetus.audience.InterfaceAudience;\n");
String recordComments = getRecordComments();
if (recordComments != null && !recordComments.isEmpty()) {
jj.write(recordComments);
}
jj.write("@InterfaceAudience.Public\n");
jj.write("public class " + getName() + " implements Record {\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); ) {
JField jf = i.next();
String fieldComments = getJavaFieldComments(jf);
if (fieldComments != null && !fieldComments.isEmpty()) {
jj.write(fieldComments);
}
jj.write(jf.genJavaDecl());
}
jj.write(" public " + getName() + "() {\n");
Expand Down Expand Up @@ -767,4 +793,122 @@ public static String getCsharpFQName(String name) {
}
return fQName.toString();
}

public String getJavaFieldComments(JField jField) {
return getFieldComments(jField, " ");
}

public String getCFieldComments(JField jField) {
return getFieldComments(jField, " ");
}

private String getFieldComments(JField jField, String indent) {
if (jField == null || jField.getTypeToken() == null || jField.getNextToken() == null) {
return "";
}

// get the comment before the line
Token beforeTheLineCommentToken = getCommentToken(jField.getTypeToken(), jField.getPreviousToken());
List<String> comments = extractComments(beforeTheLineCommentToken, Integer.MAX_VALUE);

Token endOfLineCommentToken = getCommentToken(jField.getNextToken(), null);
if (endOfLineCommentToken != null && jField.getTypeToken().beginLine == endOfLineCommentToken.beginLine) {

comments.addAll(extractComments(endOfLineCommentToken, endOfLineCommentToken.beginLine));
}

return formatComments(indent, comments);
}

private Token getCommentToken(Token token, Token previousToken) {
if (token == null || token.specialToken == null) {
return null;
}

Token commentToken = token.specialToken;
while (commentToken.specialToken != null) {
commentToken = commentToken.specialToken;
}
// Skip end of line comment belong to previous token.
while (previousToken != null && commentToken != null && commentToken.beginLine == previousToken.endLine) {
commentToken = commentToken.next;
}
return commentToken;
}

public String getRecordComments() {
if (getRecordToken() == null || getRecordToken().specialToken == null) {
return "";
}

// get the comments before the class
Token commentToken = getCommentToken(getRecordToken(), null);
return formatComments("", extractComments(commentToken, Integer.MAX_VALUE));
}

private static String formatComments(String indent, List<String> commentLines) {
if (commentLines == null || commentLines.isEmpty()) {
return "";
}

StringBuilder builder = new StringBuilder();
for (String line : commentLines) {
if (!line.isEmpty()) {
builder.append(indent).append(line);
}
builder.append(System.lineSeparator());
}

return builder.toString();
}

/**
* Extracts comments with indentation and line separator trimmed.
*
* <p>Empty line is represented as empty string.
*/
private static List<String> extractComments(Token token, int endLine) {
List<String> comments = new ArrayList<>();

if (token == null) {
return comments;
}

int nextLine = token.beginLine;
while (token != null && token.beginLine <= endLine) {
while (nextLine < token.beginLine) {
comments.add("");
nextLine++;
}
nextLine = token.endLine + 1;
switch (token.kind) {
case RccConstants.ONE_LINE_COMMENT:
comments.add(token.image);
break;
case RccConstants.MULTI_LINE_COMMENT: {
List<String> lines = Arrays.asList(token.image.split("\r|\n|\r\n"));
// First line captures no indentation.
comments.add(lines.get(0));
int indentSpaces = token.beginColumn - 1;
for (int i = 1; i < lines.size(); i++) {
String line = lines.get(i);
int j = 0;
while (j < indentSpaces && j < line.length()) {
if (line.charAt(j) != ' ') {
break;
}
j++;
}
comments.add(line.substring(j));
}
}
break;
default:
throw new IllegalStateException("expect comment token, but get token kind " + token.kind);
}
token = token.next;
}

return comments;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,32 +111,8 @@ SKIP :

SPECIAL_TOKEN :
{
"//" : WithinOneLineComment
}

<WithinOneLineComment> SPECIAL_TOKEN :
{
<("\n" | "\r" | "\r\n" )> : DEFAULT
}

<WithinOneLineComment> MORE :
{
<~[]>
}

SPECIAL_TOKEN :
{
"/*" : WithinMultiLineComment
}

<WithinMultiLineComment> SPECIAL_TOKEN :
{
"*/" : DEFAULT
}

<WithinMultiLineComment> MORE :
{
<~[]>
<ONE_LINE_COMMENT: "//" (~["\n","\r"])*>
| <MULTI_LINE_COMMENT: "/*" (~["*"])* "*" (~["*","/"] (~["*"])* "*" | "*")* "/">
}

TOKEN :
Expand Down Expand Up @@ -274,21 +250,32 @@ JRecord Record() :
ArrayList<JField> flist = new ArrayList<JField>();
Token t;
JField f;
// Get the comments on the class token
Token recordTkn;
Token typeTkn;
Token previousToken = null;
}
{
<RECORD_TKN>
recordTkn = <RECORD_TKN>
t = <IDENT_TKN>
{ rname = t.image; }
<LBRACE_TKN>
previousToken = <LBRACE_TKN>
(
{typeTkn = getToken(1);}
f = Field()
kezhuw marked this conversation as resolved.
Show resolved Hide resolved
{ flist.add(f); }
<SEMICOLON_TKN>
{
f.setTypeToken(typeTkn);
f.setPreviousToken(previousToken);
f.setNextToken(getToken(1));
previousToken = typeTkn;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal. But I think the previousToken should be <SEMICOLON_TKN>.

}
)+
<RBRACE_TKN>
{
String fqn = curModuleName + "." + rname;
JRecord r = new JRecord(fqn, flist);
JRecord r = new JRecord(fqn, flist, recordTkn);
recTab.put(fqn, r);
return r;
}
Expand Down
Loading
Loading