2023-08-20 12:13:40 +08:00
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import org.antlr.v4.runtime.*;
|
|
|
|
|
import org.antlr.v4.runtime.tree.*;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The generic walker for collecting multiple enums.
|
|
|
|
|
*/
|
|
|
|
|
public class EnumsWalker extends CKEnumsParserBaseListener {
|
|
|
|
|
public EnumsWalker(BufferedTokenStream tokenStream) {
|
|
|
|
|
mTokenStream = tokenStream;
|
|
|
|
|
mCommentsFinder = new CommentsFinder(tokenStream);
|
|
|
|
|
mResult = null;
|
|
|
|
|
|
|
|
|
|
mCurrentProg = null;
|
|
|
|
|
mCurrentEnum = null;
|
|
|
|
|
mCurrentEntry = null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-26 11:11:58 +08:00
|
|
|
public EnumsHelper.BEnumCollection getEnums() {
|
2023-08-20 12:13:40 +08:00
|
|
|
return mResult;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getEnumComment(Token enumHead) {
|
|
|
|
|
return CommonHelper
|
2026-01-28 16:35:42 +08:00
|
|
|
.cutComments(CommonHelper.getPreChannelTokens(mTokenStream, enumHead, CKGenericLexer.COMMENTS));
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BufferedTokenStream mTokenStream;
|
|
|
|
|
private CommentsFinder mCommentsFinder;
|
2026-01-26 11:11:58 +08:00
|
|
|
private EnumsHelper.BEnumCollection mResult;
|
2023-08-20 12:13:40 +08:00
|
|
|
|
2026-01-26 11:11:58 +08:00
|
|
|
private EnumsHelper.BEnumCollection mCurrentProg;
|
|
|
|
|
private EnumsHelper.BEnum mCurrentEnum;
|
|
|
|
|
private EnumsHelper.BEnumEntry mCurrentEntry;
|
2023-08-20 12:13:40 +08:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void enterProg(CKEnumsParser.ProgContext ctx) {
|
2026-01-26 11:11:58 +08:00
|
|
|
mCurrentProg = new EnumsHelper.BEnumCollection();
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void exitProg(CKEnumsParser.ProgContext ctx) {
|
|
|
|
|
mResult = mCurrentProg;
|
|
|
|
|
mCurrentProg = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void enterEnumBody(CKEnumsParser.EnumBodyContext ctx) {
|
2026-01-26 11:11:58 +08:00
|
|
|
mCurrentEnum = new EnumsHelper.BEnum();
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void exitEnumBody(CKEnumsParser.EnumBodyContext ctx) {
|
|
|
|
|
// get enum comment
|
|
|
|
|
mCurrentEnum.mEnumComment = getEnumComment(ctx.getStart());
|
|
|
|
|
// get the last name (for typedef case)
|
2026-01-28 16:35:42 +08:00
|
|
|
List<TerminalNode> allNames = ctx.CKGENERIC_ID();
|
2023-08-20 12:13:40 +08:00
|
|
|
mCurrentEnum.mEnumName = allNames.get(allNames.size() - 1).getText();
|
|
|
|
|
|
2026-02-11 22:49:54 +08:00
|
|
|
// update self and add into list
|
|
|
|
|
mCurrentEnum.updateByEntries();
|
2023-08-20 12:13:40 +08:00
|
|
|
mCurrentProg.mEnums.add(mCurrentEnum);
|
|
|
|
|
mCurrentEnum = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void enterEntryPair(CKEnumsParser.EntryPairContext ctx) {
|
2026-01-26 11:11:58 +08:00
|
|
|
mCurrentEntry = new EnumsHelper.BEnumEntry();
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void exitEntryPair(CKEnumsParser.EntryPairContext ctx) {
|
|
|
|
|
// get entry comment
|
|
|
|
|
mCurrentEntry.mEntryComment = mCommentsFinder.getComment(ctx.getStart(), ctx.getStop());
|
|
|
|
|
// get entry name
|
2026-01-28 16:35:42 +08:00
|
|
|
mCurrentEntry.mEntryName = ctx.CKGENERIC_ID().getText();
|
2023-08-20 12:13:40 +08:00
|
|
|
|
2026-02-11 22:49:54 +08:00
|
|
|
// if its value is null, we manually fill 2 kinds
|
|
|
|
|
if (mCurrentEntry.mEntryValue == null) {
|
|
|
|
|
// the sign kind is unknown because it relys on other value (+1)
|
|
|
|
|
mCurrentEntry.mEntrySignKind = EnumsHelper.BEnumEntrySignKind.Unknown;
|
|
|
|
|
// because it just adds one from previous member, it should not belong to a flag enum
|
|
|
|
|
mCurrentEntry.mEntryFlagKind = EnumsHelper.BEnumEntryFlagKind.NotFlag;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-20 12:13:40 +08:00
|
|
|
mCurrentEnum.mEntries.add(mCurrentEntry);
|
|
|
|
|
mCurrentEntry = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void exitEntryDirectValue(CKEnumsParser.EntryDirectValueContext ctx) {
|
|
|
|
|
// get all numbers
|
2026-01-28 16:35:42 +08:00
|
|
|
List<TerminalNode> nums = ctx.CKGENERIC_NUM();
|
2023-08-20 12:13:40 +08:00
|
|
|
|
|
|
|
|
switch (nums.size()) {
|
2026-02-11 22:49:54 +08:00
|
|
|
case 1: {
|
|
|
|
|
// value is immediate number
|
|
|
|
|
TerminalNode node = nums.get(0);
|
|
|
|
|
String num = node.getText();
|
|
|
|
|
mCurrentEntry.mEntryValue = num;
|
|
|
|
|
|
|
|
|
|
// check whether this enum can be unsigned
|
|
|
|
|
if (CommonHelper.isNegativeNumber(num)) {
|
|
|
|
|
mCurrentEntry.mEntrySignKind = EnumsHelper.BEnumEntrySignKind.Negative;
|
|
|
|
|
} else {
|
|
|
|
|
mCurrentEntry.mEntrySignKind = EnumsHelper.BEnumEntrySignKind.Positive;
|
|
|
|
|
}
|
|
|
|
|
// if the number is in hex form, this entry may belong to flag enum
|
|
|
|
|
if (CommonHelper.isHexNumber(num)) {
|
|
|
|
|
mCurrentEntry.mEntryFlagKind = EnumsHelper.BEnumEntryFlagKind.MayFlag;
|
|
|
|
|
} else {
|
|
|
|
|
mCurrentEntry.mEntryFlagKind = EnumsHelper.BEnumEntryFlagKind.NotFlag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
2026-02-11 22:49:54 +08:00
|
|
|
case 2: {
|
|
|
|
|
// value is bitwise operation
|
|
|
|
|
TerminalNode num = nums.get(0), offset = nums.get(1);
|
|
|
|
|
mCurrentEntry.mEntryValue = String.format("%s << %s", num.getText(), offset.getText());
|
|
|
|
|
|
|
|
|
|
// << operator appears.
|
|
|
|
|
// it shoud be unsigned.
|
|
|
|
|
mCurrentEntry.mEntrySignKind = EnumsHelper.BEnumEntrySignKind.Positive;
|
|
|
|
|
// and it must belong to flag enum
|
|
|
|
|
mCurrentEntry.mEntryFlagKind = EnumsHelper.BEnumEntryFlagKind.MustFlag;
|
|
|
|
|
|
|
|
|
|
break;
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
2026-02-11 22:49:54 +08:00
|
|
|
default:
|
|
|
|
|
throw new IllegalArgumentException("Unexpected value: " + nums.size());
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void exitEntryRelativeValue(CKEnumsParser.EntryRelativeValueContext ctx) {
|
|
|
|
|
// get all identifiers and join them
|
2026-01-28 16:35:42 +08:00
|
|
|
mCurrentEntry.mEntryValue = ctx.CKGENERIC_ID().stream().map(value -> value.getText())
|
2023-08-20 12:13:40 +08:00
|
|
|
.collect(Collectors.joining(" | "));
|
|
|
|
|
|
2026-02-11 22:49:54 +08:00
|
|
|
if (ctx.CKGENERIC_ID().size() > 1) {
|
|
|
|
|
// If there is more than one ID, it means | operator appears.
|
|
|
|
|
// It should be unsigned.
|
|
|
|
|
mCurrentEntry.mEntrySignKind = EnumsHelper.BEnumEntrySignKind.Positive;
|
|
|
|
|
// And it must belong to flag enum.
|
|
|
|
|
mCurrentEntry.mEntryFlagKind = EnumsHelper.BEnumEntryFlagKind.MustFlag;
|
|
|
|
|
} else {
|
|
|
|
|
// Otherwise it just refer other member.
|
|
|
|
|
// The sign of its value is unclear.
|
|
|
|
|
mCurrentEntry.mEntrySignKind = EnumsHelper.BEnumEntrySignKind.Unknown;
|
|
|
|
|
// And it may belong to flag enum because it refers other memeber.
|
|
|
|
|
mCurrentEntry.mEntryFlagKind = EnumsHelper.BEnumEntryFlagKind.MayFlag;
|
|
|
|
|
}
|
2023-08-20 12:13:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|