refactor: refactor EnumsMigration but not finished
This commit is contained in:
126
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/.gitignore
vendored
Normal file
126
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/.gitignore
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
## ======== Personal ========
|
||||
# Additional remove for JetBrains IDEA
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
## ======== ANTLR Output ========
|
||||
*.interp
|
||||
*.tokens
|
||||
|
||||
CKGeneralLexer*.java
|
||||
CKEnumsParser*.java
|
||||
CKDefinesParser*.java
|
||||
|
||||
## ======== Java ========
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
## ======== JetBrains ========
|
||||
# Covers JetBrains IDEs: IntelliJ, GoLand, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
.idea/sonarlint.xml # see https://community.sonarsource.com/t/is-the-file-idea-idea-idea-sonarlint-xml-intended-to-be-under-source-control/121119
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based HTTP Client
|
||||
.idea/httpRequests
|
||||
http-client.private.env.json
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Apifox Helper cache
|
||||
.idea/.cache/.Apifox_Helper
|
||||
.idea/ApifoxUploaderProjectSetting.xml
|
||||
|
||||
# Github Copilot persisted session migrations, see: https://github.com/microsoft/copilot-intellij-feedback/issues/712#issuecomment-3322062215
|
||||
.idea/**/copilot.data.migration.*.xml
|
||||
@@ -0,0 +1,6 @@
|
||||
parser grammar CKDefinesParser;
|
||||
options { tokenVocab = CKGeneralLexer; }
|
||||
|
||||
prog: definePair+ ;
|
||||
|
||||
definePair: CKGENERAL_DEFINE CKGENERAL_ID (CKGENERAL_NUM | CKGENERAL_ID) ;
|
||||
14
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CKEnumsParser.g4
Normal file
14
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CKEnumsParser.g4
Normal file
@@ -0,0 +1,14 @@
|
||||
parser grammar CKEnumsParser;
|
||||
options { tokenVocab = CKGeneralLexer; }
|
||||
|
||||
prog: enumBody* ;
|
||||
|
||||
enumBody: CKGENERAL_TYPEDEF? CKGENERAL_ENUM CKGENERAL_ID CKGENERAL_LBRACKET
|
||||
entryPair+
|
||||
CKGENERAL_RBRACKET CKGENERAL_ID? CKGENERAL_SEMICOLON ;
|
||||
|
||||
entryPair: CKGENERAL_ID (CKGENERAL_EQUAL entryValue)? CKGENERAL_COMMA? ;
|
||||
|
||||
entryValue: CKGENERAL_NUM (CKGENERAL_LSHIFT CKGENERAL_NUM)? # entryDirectValue
|
||||
| CKGENERAL_ID (CKGENERAL_OR CKGENERAL_ID)* # entryRelativeValue
|
||||
;
|
||||
@@ -0,0 +1,26 @@
|
||||
lexer grammar CKGeneralLexer;
|
||||
|
||||
channels { COMMENTS, WHITESPACE }
|
||||
|
||||
// keywords
|
||||
CKGENERAL_TYPEDEF: 'typedef' ;
|
||||
CKGENERAL_DEFINE: '#define' ;
|
||||
CKGENERAL_ENUM: 'enum' ;
|
||||
// symbols
|
||||
CKGENERAL_LBRACKET: '{' ;
|
||||
CKGENERAL_RBRACKET: '}' ;
|
||||
CKGENERAL_EQUAL: '=';
|
||||
CKGENERAL_SEMICOLON: ';' ;
|
||||
CKGENERAL_LSHIFT: '<<' ;
|
||||
CKGENERAL_OR: '|' ;
|
||||
CKGENERAL_COMMA: ',' ;
|
||||
|
||||
// identifider and number
|
||||
CKGENERAL_ID: [_a-zA-Z][_a-zA-Z0-9]* ;
|
||||
CKGENERAL_NUM: (('0'[xX]) | '-')? [0-9a-fA-F]+ [uUlL]* ;
|
||||
|
||||
// comments
|
||||
CKGENERAL_LINE_COMMENT: '//' ~[\r\n]* -> channel(COMMENTS);
|
||||
CKGENERAL_BLOCK_COMMENT: '/*' .*? '*/' -> channel(COMMENTS);
|
||||
// whitespace
|
||||
CKGENERAL_WS: [ \t\r\n]+ -> channel(WHITESPACE);
|
||||
168
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CSharpWriter.java
Normal file
168
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CSharpWriter.java
Normal file
@@ -0,0 +1,168 @@
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* Write enum declarations and accessible value into CSharp format.
|
||||
*/
|
||||
public class CSharpWriter {
|
||||
|
||||
// =========== C# Enum Declaration Writer ===========
|
||||
|
||||
/**
|
||||
* Get corredponding C# underlying type of given enum.
|
||||
* <p>
|
||||
* This is C# specific function.
|
||||
*
|
||||
* @param canUnsigned The parameter stored in Enum_t that indicate whether this
|
||||
* enum can use unsigned int as its underlying type.
|
||||
* @return The string form of its underlying type.
|
||||
*/
|
||||
private static String getEnumUnderlyingType(boolean canUnsigned) {
|
||||
return canUnsigned ? "uint" : "int";
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal real enum declaration writer.
|
||||
*
|
||||
* @param writer {@linkplain java.io.OutputStreamWriter} instance for writing.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void internalWriteEnums(OutputStreamWriter writer, EnumsHelper.BEnumCollection prog)
|
||||
throws Exception {
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.CSharp);
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
// write enum comment
|
||||
indent.briefComment(benum.mEnumComment);
|
||||
|
||||
// write enum start
|
||||
// write flasg attribute if it is
|
||||
if (benum.mUseFlags) {
|
||||
indent.puts("[Flags]");
|
||||
}
|
||||
indent.printf("public enum %s : %s {", benum.mEnumName, getEnumUnderlyingType(benum.mCanUnsigned));
|
||||
indent.inc();
|
||||
|
||||
// write enum entries
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
// write entry self
|
||||
if (enumEntry.mEntryValue == null) {
|
||||
indent.printf("%s,", enumEntry.mEntryName);
|
||||
} else {
|
||||
indent.printf("%s = %s,", enumEntry.mEntryName, enumEntry.mEntryValue);
|
||||
}
|
||||
|
||||
// write entry comment after member
|
||||
indent.afterMemberComment(enumEntry.mEntryComment);
|
||||
}
|
||||
|
||||
// write enum tail
|
||||
indent.dec();
|
||||
indent.puts("}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum declaration collection into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum declaration collection writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for
|
||||
* writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeEnums(String filename, EnumsHelper.BEnumCollection prog) throws Exception {
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteEnums(fs, prog);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single enum declaration into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum declaration collection writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param _enum {@linkplain EnumsHelper.BEnum} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeEnum(String filename, EnumsHelper.BEnum _enum) throws Exception {
|
||||
// create collection from single enum
|
||||
EnumsHelper.BEnumCollection col = new EnumsHelper.BEnumCollection();
|
||||
col.mEnums.add(_enum);
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteEnums(fs, col);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
// =========== C# Enum Accessible Value Writer ===========
|
||||
|
||||
/**
|
||||
* Internal real enum accessible value writer.
|
||||
*
|
||||
* @param writer {@linkplain java.io.OutputStreamWriter} instance for writing.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void internalWriteAccVals(OutputStreamWriter writer, EnumsHelper.BEnumCollection prog)
|
||||
throws Exception {
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.CSharp);
|
||||
// write enum collections
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
// write enum desc header
|
||||
indent.printf(
|
||||
"public static readonly System.Collections.Generic.Dictionary<%s, string> %s = new System.Collections.Generic.Dictionary<%s, string>() {",
|
||||
benum.mEnumName, benum.mEnumName, benum.mEnumName);
|
||||
indent.inc();
|
||||
|
||||
// write enum desc entries
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
indent.printf("{ %s.%s, \"%s\" },", benum.mEnumName, enumEntry.mEntryName, enumEntry.mEntryName);
|
||||
}
|
||||
|
||||
// write enum tail
|
||||
indent.dec();
|
||||
indent.puts("};");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum accessible value collection into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum accessible value collection
|
||||
* writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for
|
||||
* writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeAccVals(String filename, EnumsHelper.BEnumCollection prog) throws Exception {
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteAccVals(fs, prog);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single enum accessible value into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum accessible value collection
|
||||
* writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param _enum {@linkplain EnumsHelper.BEnum} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeAccVal(String filename, EnumsHelper.BEnum _enum) throws Exception {
|
||||
// create a collection with single enum.
|
||||
EnumsHelper.BEnumCollection col = new EnumsHelper.BEnumCollection();
|
||||
col.mEnums.add(_enum);
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteAccVals(fs, col);
|
||||
fs.close();
|
||||
}
|
||||
}
|
||||
119
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/ClassidWalker.java
Normal file
119
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/ClassidWalker.java
Normal file
@@ -0,0 +1,119 @@
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
/**
|
||||
* The specialized walker for collecting CK_CLASSID and its inherit
|
||||
* relationship.
|
||||
*/
|
||||
public class ClassidWalker extends CKDefinesParserBaseListener {
|
||||
|
||||
public ClassidWalker(BufferedTokenStream tokenStream) {
|
||||
mTokenStream = tokenStream;
|
||||
mResult = null;
|
||||
|
||||
mLevelStack = null;
|
||||
mCurrentEnum = null;
|
||||
mCurrentEntry = null;
|
||||
}
|
||||
|
||||
public EnumsHelper.BEnum getEnum() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private int getClassidLevel(Token defineHead) {
|
||||
Token ws = CommonHelper.getPreChannelToken(mTokenStream, defineHead, CKGeneralLexer.WHITESPACE);
|
||||
if (ws == null)
|
||||
return 0;
|
||||
|
||||
// reverse finding how many tab used.
|
||||
int counter = 0;
|
||||
char[] wstxt = ws.getText().toCharArray();
|
||||
for (int i = wstxt.length - 1; i >= 0; i--) {
|
||||
if (wstxt[i] == '\t') {
|
||||
counter++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
private void safePop() {
|
||||
if (mLevelStack.size() != 0)
|
||||
mLevelStack.pop();
|
||||
}
|
||||
|
||||
private void safePopTimes(int times) {
|
||||
for (int i = 0; i < times; i++) {
|
||||
if (mLevelStack.size() != 0)
|
||||
mLevelStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedTokenStream mTokenStream;
|
||||
private EnumsHelper.BEnum mResult;
|
||||
|
||||
private int mLevel;
|
||||
private Stack<EnumsHelper.BHierarchyEnumEntry> mLevelStack;
|
||||
private EnumsHelper.BEnum mCurrentEnum;
|
||||
private EnumsHelper.BHierarchyEnumEntry mCurrentEntry;
|
||||
|
||||
@Override
|
||||
public void enterProg(CKDefinesParser.ProgContext ctx) {
|
||||
mLevel = 0;
|
||||
mLevelStack = new Stack<EnumsHelper.BHierarchyEnumEntry>();
|
||||
mCurrentEnum = new EnumsHelper.BEnum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitProg(CKDefinesParser.ProgContext ctx) {
|
||||
mLevel = 0;
|
||||
mLevelStack = null;
|
||||
|
||||
// classid is signed int and do not have flags feature.
|
||||
mCurrentEnum.mCanUnsigned = false;
|
||||
mCurrentEnum.mUseFlags = false;
|
||||
mResult = mCurrentEnum;
|
||||
mCurrentEnum = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterDefinePair(CKDefinesParser.DefinePairContext ctx) {
|
||||
mCurrentEntry = new EnumsHelper.BHierarchyEnumEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitDefinePair(CKDefinesParser.DefinePairContext ctx) {
|
||||
// fill entry info
|
||||
mCurrentEntry.mEntryName = ctx.CKGENERAL_ID(0).getText();
|
||||
mCurrentEntry.mEntryValue = ctx.CKGENERAL_NUM().getText();
|
||||
|
||||
// fill entry level info
|
||||
int this_level = getClassidLevel(ctx.getStart());
|
||||
if (this_level > mLevel) {
|
||||
// level up
|
||||
mLevel++;
|
||||
|
||||
mLevelStack.push(mCurrentEntry);
|
||||
mCurrentEntry.mHierarchy.addAll(mLevelStack);
|
||||
} else if (this_level == mLevel) {
|
||||
safePop();
|
||||
mLevelStack.push(mCurrentEntry);
|
||||
mCurrentEntry.mHierarchy.addAll(mLevelStack);
|
||||
} else if (this_level < mLevel) {
|
||||
// level down
|
||||
safePopTimes(mLevel - this_level + 1);
|
||||
mLevel = this_level;
|
||||
|
||||
mLevelStack.push(mCurrentEntry);
|
||||
mCurrentEntry.mHierarchy.addAll(mLevelStack);
|
||||
}
|
||||
|
||||
// move to list
|
||||
mCurrentEnum.mEntries.add(mCurrentEntry);
|
||||
mCurrentEntry = null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
public class CommentsFinder {
|
||||
|
||||
enum CommentsPosition {
|
||||
Unknown, Precomment, Postcomment
|
||||
}
|
||||
|
||||
public CommentsFinder(BufferedTokenStream tokenStream) {
|
||||
mTokenStream = tokenStream;
|
||||
mCommentsPos = CommentsPosition.Unknown;
|
||||
}
|
||||
|
||||
private BufferedTokenStream mTokenStream;
|
||||
private CommentsPosition mCommentsPos;
|
||||
|
||||
public String getComment(Token preToken, Token postToken) {
|
||||
switch (mCommentsPos) {
|
||||
case Unknown: {
|
||||
// if we don't know where is our token,
|
||||
// we should assume it is from precomment to postcomment
|
||||
// and check it.
|
||||
List<Token> precomment = CommonHelper.getPreChannelTokens(mTokenStream, preToken, CKGeneralLexer.COMMENTS);
|
||||
if (precomment != null) {
|
||||
mCommentsPos = CommentsPosition.Precomment;
|
||||
return CommonHelper.cutComments(precomment);
|
||||
}
|
||||
|
||||
List<Token> postcomment = CommonHelper.getPostChannelTokens(mTokenStream, postToken, CKGeneralLexer.COMMENTS);
|
||||
if (postcomment != null) {
|
||||
mCommentsPos = CommentsPosition.Postcomment;
|
||||
return CommonHelper.cutComments(postcomment);
|
||||
}
|
||||
|
||||
// really do not have comment, return empty and keep comment pos
|
||||
return null;
|
||||
}
|
||||
case Precomment: {
|
||||
return CommonHelper.cutComments(CommonHelper.getPreChannelTokens(mTokenStream, preToken, CKGeneralLexer.COMMENTS));
|
||||
}
|
||||
case Postcomment: {
|
||||
return CommonHelper.cutComments(CommonHelper.getPostChannelTokens(mTokenStream, postToken, CKGeneralLexer.COMMENTS));
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
257
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CommonHelper.java
Normal file
257
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CommonHelper.java
Normal file
@@ -0,0 +1,257 @@
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
public class CommonHelper {
|
||||
|
||||
// =========== Token Finder & Comments Processing ===========
|
||||
|
||||
public static Token getPreChannelToken(BufferedTokenStream stream, Token token, int channel) {
|
||||
List<Token> tokens = stream.getHiddenTokensToLeft(token.getTokenIndex(), channel);
|
||||
if (tokens == null)
|
||||
return null;
|
||||
return tokens.get(0);
|
||||
}
|
||||
|
||||
public static Token getPostChannelToken(BufferedTokenStream stream, Token token, int channel) {
|
||||
List<Token> tokens = stream.getHiddenTokensToRight(token.getTokenIndex(), channel);
|
||||
if (tokens == null)
|
||||
return null;
|
||||
return tokens.get(0);
|
||||
}
|
||||
|
||||
public static List<Token> getPreChannelTokens(BufferedTokenStream stream, Token token, int channel) {
|
||||
return stream.getHiddenTokensToLeft(token.getTokenIndex(), channel);
|
||||
}
|
||||
|
||||
public static List<Token> getPostChannelTokens(BufferedTokenStream stream, Token token, int channel) {
|
||||
return stream.getHiddenTokensToRight(token.getTokenIndex(), channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut the head and tail of comment
|
||||
*
|
||||
* @param comment The comment need to be cut.
|
||||
* @return The cut comment.
|
||||
*/
|
||||
public static String cutComment(Token comment) {
|
||||
if (comment == null)
|
||||
return null;
|
||||
|
||||
switch (comment.getType()) {
|
||||
case CKGeneralLexer.CKGENERAL_LINE_COMMENT: {
|
||||
return removeStars(comment.getText().substring(2));
|
||||
}
|
||||
case CKGeneralLexer.CKGENERAL_BLOCK_COMMENT: {
|
||||
String cache = comment.getText();
|
||||
return removeStars(cache.substring(2, cache.length() - 4));
|
||||
}
|
||||
default:
|
||||
return comment.getText();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cut multiple comments.
|
||||
* <p>
|
||||
* Each comment will be cut the head and tail first. And strip all whitespace.
|
||||
* Then join together.
|
||||
*
|
||||
* @param tokens Multiple comments.
|
||||
* @return The joined comment.
|
||||
*/
|
||||
public static String cutComments(List<Token> tokens) {
|
||||
if (tokens == null)
|
||||
return null;
|
||||
|
||||
return tokens.stream().map(value -> {
|
||||
String text = cutComment(value).strip();
|
||||
return text + " ";
|
||||
}).collect(Collectors.joining(""));
|
||||
}
|
||||
|
||||
// =========== Number Operations ===========
|
||||
|
||||
/**
|
||||
* Check whether Antlr captured CKGENERAL_NUM is a negative number.
|
||||
*
|
||||
* @param numstr The captured number.
|
||||
* @return true if it is negative number.
|
||||
*/
|
||||
public static boolean isNegativeNumber(String numstr) {
|
||||
return numstr.startsWith("-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether Altlr captured CKGENERAL_NUM is a hex number.
|
||||
*
|
||||
* @param numstr The captured number.
|
||||
* @return true if it is hex number.
|
||||
*/
|
||||
public static boolean isHexNumber(String numstr) {
|
||||
return numstr.startsWith("0x") || numstr.startsWith("0X");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert accepted string into Python cupported format.
|
||||
*
|
||||
* It actually just remove trail "UL".
|
||||
*
|
||||
* @param numstr The captured number.
|
||||
* @return The Python style number string.
|
||||
*/
|
||||
public static String convertToPythonNumber(String numstr) {
|
||||
return numstr.replaceFirst("[ulUL]+$", "");
|
||||
}
|
||||
|
||||
// =========== Parts ===========
|
||||
|
||||
enum CKParts {
|
||||
CK2, VxMath
|
||||
}
|
||||
|
||||
enum LangType {
|
||||
Cpp, Python, CSharp
|
||||
}
|
||||
|
||||
public static String getCKPartsNamespace(CKParts parts) {
|
||||
switch (parts) {
|
||||
case CK2:
|
||||
return "CK2";
|
||||
case VxMath:
|
||||
return "VxMath";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + parts);
|
||||
}
|
||||
}
|
||||
|
||||
// =========== File Operations ===========
|
||||
|
||||
private static Path getRootDirectoryPath() throws Exception {
|
||||
String rootDir = System.getenv("ENUMS_MIGRATION_ROOT");
|
||||
return Paths.get(rootDir);
|
||||
}
|
||||
|
||||
public static class InputFilePair {
|
||||
public CharStream mAntlrStream;
|
||||
public FileInputStream mUnderlyingStream;
|
||||
}
|
||||
|
||||
public static InputFilePair openInputFile(String filename) throws Exception {
|
||||
InputFilePair pair = new InputFilePair();
|
||||
pair.mUnderlyingStream = new FileInputStream(filename);
|
||||
pair.mAntlrStream = CharStreams.fromStream(pair.mUnderlyingStream, StandardCharsets.UTF_8);
|
||||
return pair;
|
||||
}
|
||||
|
||||
public static String getInputFilePath(String filename) throws Exception {
|
||||
Path rootDir = getRootDirectoryPath();
|
||||
Path filePath = rootDir.resolve("Input").resolve(filename);
|
||||
return filePath.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output file for writing.
|
||||
*
|
||||
* @param filename The name of file opening.
|
||||
* @return An OutputStreamWriter.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static OutputStreamWriter openOutputFile(String filename) throws Exception {
|
||||
FileOutputStream fs = new FileOutputStream(filename);
|
||||
return new OutputStreamWriter(fs, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String getOutputFilePath(String filename) throws Exception {
|
||||
Path rootDir = getRootDirectoryPath();
|
||||
Path filePath = rootDir.resolve("Intermediate").resolve(filename);
|
||||
return filePath.toString();
|
||||
}
|
||||
|
||||
// =========== String Process ===========
|
||||
|
||||
/**
|
||||
* Escape String
|
||||
*
|
||||
* Escape all characters which are invalid in string quote.
|
||||
*
|
||||
* @param strl The string need to be escaped.
|
||||
* @return The escaped string.
|
||||
* @see removeEol
|
||||
*/
|
||||
public static String escapeString(String strl) {
|
||||
return strl.replace("\\", "\\\\").replace("\t", "\\t").replace("\b", "\\b").replace("\n", "\\n")
|
||||
.replace("\r", "\\r").replace("\f", "\\f").replace("\"", "\\\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all EOL (End of Line) characters.
|
||||
*
|
||||
* @param strl The string need to be processed.
|
||||
* @return The string eliminated all EOL.
|
||||
* @see escapeString
|
||||
*/
|
||||
public static String removeEol(String strl) {
|
||||
return strl.replace("\n", "").replace("\r", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove redundent star '*' (at least 5 continuous star chars)
|
||||
*
|
||||
* @param cmt The string provided.
|
||||
* @return The string processed.
|
||||
*/
|
||||
public static String removeStars(String cmt) {
|
||||
// only remove at least 5 continuous star chars.
|
||||
return cmt.replaceAll("\\*{5,}", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get indent char by style
|
||||
*
|
||||
* @param use_tab Whether indent use Tab, not Space.
|
||||
* @return The indent chars
|
||||
*/
|
||||
public static String getIndentString(boolean use_tab) {
|
||||
if (use_tab)
|
||||
return "\t";
|
||||
else
|
||||
return " ";
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-indent a block of string
|
||||
*
|
||||
* This function will first split block string by line. Then remove all indent
|
||||
* (strip Tab and Space). At last, re-indent and join each line
|
||||
*
|
||||
* @param block_str The string provided.
|
||||
* @param use_tab Use Tab, not Space as indent chars.
|
||||
* @param indent_level The level of indent, started by 0.
|
||||
* @return The re-indent string
|
||||
*/
|
||||
public static String reindentBlockString(String block_str, boolean use_tab, int indent_level) {
|
||||
// pre-create indent string
|
||||
String indentChars = getIndentString(use_tab);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < indent_level; ++i) {
|
||||
sb.append(indentChars);
|
||||
}
|
||||
String indents = sb.toString();
|
||||
|
||||
// split line
|
||||
return block_str.lines().map((String line) -> {
|
||||
// strip space and tab, then re-indent it.
|
||||
return indents + line.trim();
|
||||
}).collect(Collectors.joining(System.lineSeparator())); // then join with new line breaker and return.
|
||||
}
|
||||
|
||||
}
|
||||
273
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CppWriter.java
Normal file
273
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/CppWriter.java
Normal file
@@ -0,0 +1,273 @@
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Write enum declarations and accessible value into C++ format.
|
||||
*/
|
||||
public class CppWriter {
|
||||
|
||||
// =========== C++ Enum Declaration Writer ===========
|
||||
|
||||
/**
|
||||
* Get corredponding C++ underlying type of given enum.
|
||||
* <p>
|
||||
* This is C++ specific function.
|
||||
*
|
||||
* @param canUnsigned The parameter stored in Enum_t that indicate whether this
|
||||
* enum can use unsigned int as its underlying type.
|
||||
* @return The string form of its underlying type.
|
||||
*/
|
||||
private static String getEnumUnderlyingType(boolean canUnsigned) {
|
||||
return canUnsigned ? "CKDWORD" : "CKINT";
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal real enum declarations writer.
|
||||
*
|
||||
* @param writer {@linkplain java.io.OutputStreamWriter} instance for writing.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void internalWriteEnums(OutputStreamWriter writer, EnumsHelper.BEnumCollection prog)
|
||||
throws Exception {
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.Cpp);
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
// write enum comment
|
||||
indent.briefComment(benum.mEnumComment);
|
||||
|
||||
// write enum start
|
||||
indent.printf("enum class %s : %s {", benum.mEnumName, getEnumUnderlyingType(benum.mCanUnsigned));
|
||||
indent.inc();
|
||||
|
||||
// write enum entries
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
// write entry self
|
||||
if (enumEntry.mEntryValue == null) {
|
||||
indent.printf("%s,", enumEntry.mEntryName);
|
||||
} else {
|
||||
indent.printf("%s = %s,", enumEntry.mEntryName, enumEntry.mEntryValue);
|
||||
}
|
||||
|
||||
// write entry comment after member
|
||||
indent.afterMemberComment(enumEntry.mEntryComment);
|
||||
}
|
||||
|
||||
// write enum tail
|
||||
indent.dec();
|
||||
indent.puts("};");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum collection into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum collection writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for
|
||||
* writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeEnums(String filename, EnumsHelper.BEnumCollection prog) throws Exception {
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteEnums(fs, prog);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single enum into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum collection writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param _enum {@linkplain EnumsHelper.BEnum} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeEnum(String filename, EnumsHelper.BEnum _enum) throws Exception {
|
||||
// create an collection from single enum declaration
|
||||
// for suit the argument requirement of real writer.
|
||||
EnumsHelper.BEnumCollection col = new EnumsHelper.BEnumCollection();
|
||||
col.mEnums.add(_enum);
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteEnums(fs, col);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
// =========== C++ Enum Accessible Value Writer ===========
|
||||
|
||||
/**
|
||||
* Internal real enum collection accessible value writer.
|
||||
*
|
||||
* @param writer {@linkplain java.io.OutputStreamWriter} instance for writing.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for writing.
|
||||
* @param parts The part of these enum declarations. It will indicate the
|
||||
* namespace where find given enum collection.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void internalWriteAccVals(OutputStreamWriter writer, EnumsHelper.BEnumCollection prog,
|
||||
CommonHelper.CKParts parts) throws Exception {
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.Cpp);
|
||||
|
||||
// write type defination (just to let user know what the type is)
|
||||
indent.puts("// struct GeneralReflection { const char8_t* mName; };");
|
||||
indent.puts("// template<typename _Ty, std::enable_if_t<std::is_enum_v<_Ty>, int> = 0>");
|
||||
indent.puts("// using GeneralReflectionArray = std::vector<std::pair<_Ty, GeneralReflection>>;");
|
||||
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
|
||||
// write declarations
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
indent.printf("extern const GeneralReflectionArray<LibCmo::%s::%s> %s;",
|
||||
CommonHelper.getCKPartsNamespace(parts), benum.mEnumName, benum.mEnumName);
|
||||
}
|
||||
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
|
||||
// write implements
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
// write enum desc header
|
||||
indent.printf("const GeneralReflectionArray<LibCmo::%s::%s> %s {", CommonHelper.getCKPartsNamespace(parts),
|
||||
benum.mEnumName, benum.mEnumName);
|
||||
indent.inc();
|
||||
|
||||
// write enum desc entries
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
indent.printf("{ LibCmo::%s::%s::%s, { u8\"%s\" } },", CommonHelper.getCKPartsNamespace(parts),
|
||||
benum.mEnumName, enumEntry.mEntryName, enumEntry.mEntryName);
|
||||
}
|
||||
|
||||
// write enum tail
|
||||
indent.dec();
|
||||
indent.puts("};");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum collection accessible value into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum collection accessible value
|
||||
* writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for
|
||||
* writing.
|
||||
* @param parts The part of these enum declarations.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeAccVals(String filename, EnumsHelper.BEnumCollection prog, CommonHelper.CKParts parts)
|
||||
throws Exception {
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteAccVals(fs, prog, parts);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single enum accessible value into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum collection accessible value
|
||||
* writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param _enum {@linkplain EnumsHelper.BEnum} instance for writing.
|
||||
* @param parts The part of these enum declarations.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeAccVal(String filename, EnumsHelper.BEnum _enum, CommonHelper.CKParts parts)
|
||||
throws Exception {
|
||||
// create a enum collection to fulfill the requirement of internal writer.
|
||||
EnumsHelper.BEnumCollection col = new EnumsHelper.BEnumCollection();
|
||||
col.mEnums.add(_enum);
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteAccVals(fs, col, parts);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
// =========== Specialized C++ Enum Accessible Value Writer ===========
|
||||
// Only accessible value part of CERROR and CK_CLASSID need to be specialized.
|
||||
// The enum self do not need special treat. Just write them normally.
|
||||
|
||||
/**
|
||||
* Specialized CKERROR accessible value writer.
|
||||
* <p>
|
||||
* The declaration of CKERROR do not need special treat. It is okey to use
|
||||
* common writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param errors The {@linkplain EnumsHelper.BEnum} instance storing CKERROR.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeCkErrorAccVal(String filename, EnumsHelper.BEnum errors) throws Exception {
|
||||
OutputStreamWriter writer = CommonHelper.openOutputFile(filename);
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.Cpp);
|
||||
|
||||
// write type defination (just to let user know what the type is)
|
||||
indent.puts("// struct CkErrorReflection { const char8_t* mName; const char8_t* mDescription; };");
|
||||
indent.puts("// using CkErrorReflectionArray = std::vector<std::pair<LibCmo::CK2::CKERROR, CkErrorReflection>>;");
|
||||
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
|
||||
// write implementation
|
||||
indent.puts("const CkErrorReflectionArray CKERROR {");
|
||||
indent.inc();
|
||||
for (EnumsHelper.BEnumEntry entry : errors.mEntries) {
|
||||
String comment = CommonHelper.escapeString(entry.mEntryComment);
|
||||
if (comment == null)
|
||||
comment = "";
|
||||
|
||||
indent.printf("{ LibCmo::CK2::CKERROR::%s, { u8\"%s\", u8\"%s\" } },", entry.mEntryName, entry.mEntryName,
|
||||
comment);
|
||||
}
|
||||
indent.dec();
|
||||
indent.puts("};");
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized CK_CLASSID accessible value writer.
|
||||
* <p>
|
||||
* The declaration of CK_CLASSID do not need special treat. It is okey to use
|
||||
* common writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param classids The {@linkplain EnumsHelper.BEnum} instance storing
|
||||
* CK_CLASSID.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeCkClassidAccVal(String filename, EnumsHelper.BEnum classids) throws Exception {
|
||||
OutputStreamWriter writer = CommonHelper.openOutputFile(filename);
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.Cpp);
|
||||
|
||||
// write type defination (just to let user know what the type is)
|
||||
indent.puts("// struct CkClassidReflection { std::vector<const char8_t*> mHierarchy; };");
|
||||
indent.puts("// using CkClassidReflectionArray = std::vector<std::pair<LibCmo::CK2::CK_CLASSID, CkClassidReflection>>;");
|
||||
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
indent.puts("");
|
||||
|
||||
indent.puts("const CkClassidReflectionArray CK_CLASSID {");
|
||||
indent.inc();
|
||||
for (EnumsHelper.BEnumEntry entry : classids.mEntries) {
|
||||
EnumsHelper.BHierarchyEnumEntry specialized = (EnumsHelper.BHierarchyEnumEntry) entry;
|
||||
|
||||
String hierarchy = specialized.mHierarchy.stream().map(value -> value.mEntryName)
|
||||
.collect(Collectors.joining("\", u8\""));
|
||||
indent.printf("{ LibCmo::CK2::CK_CLASSID::%s, { { u8\"%s\" } } },", entry.mEntryName, hierarchy);
|
||||
}
|
||||
indent.dec();
|
||||
indent.puts("};");
|
||||
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
|
||||
/**
|
||||
* The generic walker for collecting defines as a enum.
|
||||
*/
|
||||
public class DefinesWalker extends CKDefinesParserBaseListener {
|
||||
public DefinesWalker(BufferedTokenStream tokenStream) {
|
||||
mCommentsFinder = new CommentsFinder(tokenStream);
|
||||
mResult = null;
|
||||
|
||||
mCurrentEnum = null;
|
||||
mCurrentEntry = null;
|
||||
}
|
||||
|
||||
public EnumsHelper.BEnum getEnum() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private CommentsFinder mCommentsFinder;
|
||||
private EnumsHelper.BEnum mResult;
|
||||
|
||||
private EnumsHelper.BEnum mCurrentEnum;
|
||||
private EnumsHelper.BEnumEntry mCurrentEntry;
|
||||
|
||||
@Override
|
||||
public void enterProg(CKDefinesParser.ProgContext ctx) {
|
||||
mCurrentEnum = new EnumsHelper.BEnum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitProg(CKDefinesParser.ProgContext ctx) {
|
||||
mResult = mCurrentEnum;
|
||||
mCurrentEnum = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterDefinePair(CKDefinesParser.DefinePairContext ctx) {
|
||||
mCurrentEntry = new EnumsHelper.BEnumEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitDefinePair(CKDefinesParser.DefinePairContext ctx) {
|
||||
// set values
|
||||
mCurrentEntry.mEntryName = ctx.CKGENERAL_ID(0).getText();
|
||||
mCurrentEntry.mEntryComment = mCommentsFinder.getComment(ctx.getStart(), ctx.getStop());
|
||||
|
||||
if (ctx.CKGENERAL_NUM() == null) {
|
||||
// define with id
|
||||
mCurrentEntry.mEntryValue = ctx.CKGENERAL_ID(1).getText();
|
||||
|
||||
} else {
|
||||
// define with number
|
||||
String num = ctx.CKGENERAL_NUM().getText();
|
||||
mCurrentEntry.mEntryValue = num;
|
||||
|
||||
// check whether this enum can be unsigned
|
||||
if (CommonHelper.isNegativeNumber(num)) {
|
||||
mCurrentEnum.mCanUnsigned = false;
|
||||
}
|
||||
// if the number is in hex form, this enum MIGHT have flags feature
|
||||
if (CommonHelper.isHexNumber(num)) {
|
||||
mCurrentEnum.mUseFlags = true;
|
||||
}
|
||||
|
||||
}
|
||||
// add entry
|
||||
mCurrentEnum.mEntries.add(mCurrentEntry);
|
||||
mCurrentEntry = null;
|
||||
}
|
||||
|
||||
}
|
||||
72
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/EnumsHelper.java
Normal file
72
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/EnumsHelper.java
Normal file
@@ -0,0 +1,72 @@
|
||||
import java.util.Vector;
|
||||
|
||||
public class EnumsHelper {
|
||||
/**
|
||||
* The struct to describe the entry of an enum.
|
||||
*/
|
||||
public static class BEnumEntry {
|
||||
public BEnumEntry() {
|
||||
mEntryName = null;
|
||||
mEntryValue = null;
|
||||
mEntryComment = null;
|
||||
}
|
||||
|
||||
/** The name of this entry. Can not be null. */
|
||||
public String mEntryName;
|
||||
/** The value of this entry. null if this entry do not have explicit value. */
|
||||
public String mEntryValue;
|
||||
/** The comment of this entry. null if no comment. */
|
||||
public String mEntryComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* The specialized EnumEntry type which can store extra hierarchy info.
|
||||
* Used in CK_CLASSID parsing.
|
||||
*/
|
||||
public static class BHierarchyEnumEntry extends BEnumEntry {
|
||||
public BHierarchyEnumEntry() {
|
||||
super();
|
||||
mHierarchy = new Vector<BHierarchyEnumEntry>();
|
||||
}
|
||||
|
||||
/** The list to store this CK_CLASSID inheritance relationship. */
|
||||
public Vector<BHierarchyEnumEntry> mHierarchy;
|
||||
}
|
||||
|
||||
/**
|
||||
* The struct to describe an enum.
|
||||
*/
|
||||
public static class BEnum {
|
||||
public BEnum() {
|
||||
mEnumName = null;
|
||||
mEnumComment = null;
|
||||
mCanUnsigned = true;
|
||||
mUseFlags = false;
|
||||
mEntries = new Vector<BEnumEntry>();
|
||||
}
|
||||
|
||||
/** The name of this enum. Can not be null. */
|
||||
public String mEnumName;
|
||||
/** The comment of this enum. null if no comment. */
|
||||
public String mEnumComment;
|
||||
/** True if this enum can use unsigned integer as its underlying type. */
|
||||
public boolean mCanUnsigned;
|
||||
/** True if this enum will use flags feature (supporting OR, AND, operators). */
|
||||
public boolean mUseFlags;
|
||||
/** The list to store entries of this enum. */
|
||||
public Vector<BEnumEntry> mEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* The struct to describe a collection of enums.
|
||||
*/
|
||||
public static class BEnumCollection {
|
||||
public BEnumCollection() {
|
||||
mEnums = new Vector<BEnum>();
|
||||
}
|
||||
|
||||
/** The list to store enums. */
|
||||
public Vector<BEnum> mEnums;
|
||||
}
|
||||
|
||||
}
|
||||
131
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/EnumsWalker.java
Normal file
131
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/EnumsWalker.java
Normal file
@@ -0,0 +1,131 @@
|
||||
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;
|
||||
}
|
||||
|
||||
public EnumsHelper.BEnumCollection getEnums() {
|
||||
return mResult;
|
||||
}
|
||||
|
||||
private String getEnumComment(Token enumHead) {
|
||||
return CommonHelper
|
||||
.cutComments(CommonHelper.getPreChannelTokens(mTokenStream, enumHead, CKGeneralLexer.COMMENTS));
|
||||
}
|
||||
|
||||
private BufferedTokenStream mTokenStream;
|
||||
private CommentsFinder mCommentsFinder;
|
||||
private EnumsHelper.BEnumCollection mResult;
|
||||
|
||||
private EnumsHelper.BEnumCollection mCurrentProg;
|
||||
private EnumsHelper.BEnum mCurrentEnum;
|
||||
private EnumsHelper.BEnumEntry mCurrentEntry;
|
||||
|
||||
@Override
|
||||
public void enterProg(CKEnumsParser.ProgContext ctx) {
|
||||
mCurrentProg = new EnumsHelper.BEnumCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitProg(CKEnumsParser.ProgContext ctx) {
|
||||
mResult = mCurrentProg;
|
||||
mCurrentProg = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterEnumBody(CKEnumsParser.EnumBodyContext ctx) {
|
||||
mCurrentEnum = new EnumsHelper.BEnum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEnumBody(CKEnumsParser.EnumBodyContext ctx) {
|
||||
// get enum comment
|
||||
mCurrentEnum.mEnumComment = getEnumComment(ctx.getStart());
|
||||
// get the last name (for typedef case)
|
||||
List<TerminalNode> allNames = ctx.CKGENERAL_ID();
|
||||
mCurrentEnum.mEnumName = allNames.get(allNames.size() - 1).getText();
|
||||
|
||||
mCurrentProg.mEnums.add(mCurrentEnum);
|
||||
mCurrentEnum = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterEntryPair(CKEnumsParser.EntryPairContext ctx) {
|
||||
mCurrentEntry = new EnumsHelper.BEnumEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEntryPair(CKEnumsParser.EntryPairContext ctx) {
|
||||
// get entry comment
|
||||
mCurrentEntry.mEntryComment = mCommentsFinder.getComment(ctx.getStart(), ctx.getStop());
|
||||
// get entry name
|
||||
mCurrentEntry.mEntryName = ctx.CKGENERAL_ID().getText();
|
||||
|
||||
mCurrentEnum.mEntries.add(mCurrentEntry);
|
||||
mCurrentEntry = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEntryDirectValue(CKEnumsParser.EntryDirectValueContext ctx) {
|
||||
// get all numbers
|
||||
List<TerminalNode> nums = ctx.CKGENERAL_NUM();
|
||||
|
||||
switch (nums.size()) {
|
||||
case 1: {
|
||||
// set value
|
||||
TerminalNode node = nums.get(0);
|
||||
mCurrentEntry.mEntryValue = node.getText();
|
||||
|
||||
// check whether this enum can be unsigned
|
||||
if (CommonHelper.isNegativeNumber(node.getText())) {
|
||||
mCurrentEnum.mCanUnsigned = false;
|
||||
}
|
||||
// if the number is in hex form, this enum MIGHT have flags feature
|
||||
if (CommonHelper.isHexNumber(node.getText())) {
|
||||
mCurrentEnum.mUseFlags = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// set value
|
||||
TerminalNode num = nums.get(0), offset = nums.get(1);
|
||||
mCurrentEntry.mEntryValue = String.format("%s << %s", num.getText(), offset.getText());
|
||||
|
||||
// << operator appears. this enum must have flags feature
|
||||
mCurrentEnum.mUseFlags = true;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + nums.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitEntryRelativeValue(CKEnumsParser.EntryRelativeValueContext ctx) {
|
||||
// get all identifiers and join them
|
||||
mCurrentEntry.mEntryValue = ctx.CKGENERAL_ID().stream().map(value -> value.getText())
|
||||
.collect(Collectors.joining(" | "));
|
||||
|
||||
// | operator appears. this enum must have flags feature
|
||||
mCurrentEnum.mUseFlags = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
116
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/IndentHelper.java
Normal file
116
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/IndentHelper.java
Normal file
@@ -0,0 +1,116 @@
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
public class IndentHelper {
|
||||
public IndentHelper(OutputStreamWriter writer, CommonHelper.LangType lang_type) {
|
||||
mIndent = 0;
|
||||
mLangType = lang_type;
|
||||
mWriter = writer;
|
||||
|
||||
// set indent chars
|
||||
switch (mLangType) {
|
||||
case Cpp:
|
||||
case CSharp:
|
||||
mIndentChars = CommonHelper.getIndentString(true);
|
||||
break;
|
||||
case Python:
|
||||
mIndentChars = CommonHelper.getIndentString(false);
|
||||
break;
|
||||
default:
|
||||
mIndentChars = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private int mIndent;
|
||||
private CommonHelper.LangType mLangType;
|
||||
private String mIndentChars;
|
||||
private OutputStreamWriter mWriter;
|
||||
|
||||
private void rawIndent() throws Exception {
|
||||
for (int i = 0; i < mIndent; ++i) {
|
||||
mWriter.write(mIndentChars);
|
||||
}
|
||||
}
|
||||
|
||||
public void inc() {
|
||||
++mIndent;
|
||||
}
|
||||
|
||||
public void dec() {
|
||||
--mIndent;
|
||||
}
|
||||
|
||||
public void indent() throws Exception {
|
||||
mWriter.write(System.lineSeparator());
|
||||
rawIndent();
|
||||
}
|
||||
|
||||
public void puts(String data) throws Exception {
|
||||
indent();
|
||||
mWriter.write(data);
|
||||
}
|
||||
|
||||
public void printf(String fmt, Object... args) throws Exception {
|
||||
indent();
|
||||
mWriter.write(String.format(fmt, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write standard Doxygen document comment.
|
||||
* <p>
|
||||
* Usually be called before writing content.
|
||||
*
|
||||
* @param comment
|
||||
* @throws Exception
|
||||
*/
|
||||
public void briefComment(String comment) throws Exception {
|
||||
if (comment == null)
|
||||
return;
|
||||
|
||||
switch (mLangType) {
|
||||
case Cpp:
|
||||
case CSharp:
|
||||
puts("/**");
|
||||
|
||||
mWriter.write(System.lineSeparator());
|
||||
mWriter.write(CommonHelper.reindentBlockString(comment, true, mIndent));
|
||||
|
||||
puts(" */");
|
||||
break;
|
||||
case Python:
|
||||
puts("\"\"\"!");
|
||||
|
||||
mWriter.write(System.lineSeparator());
|
||||
mWriter.write(CommonHelper.reindentBlockString(comment, false, mIndent));
|
||||
|
||||
puts("\"\"\"");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write suffix style Doxygen document comment.
|
||||
* <p>
|
||||
* Usually be called after writing content.
|
||||
*
|
||||
* @param comment
|
||||
* @throws Exception
|
||||
*/
|
||||
public void afterMemberComment(String comment) throws Exception {
|
||||
if (comment == null)
|
||||
return;
|
||||
|
||||
mWriter.write(mIndentChars);
|
||||
switch (mLangType) {
|
||||
case Cpp:
|
||||
case CSharp:
|
||||
mWriter.write(String.format("/**< %s */", CommonHelper.removeEol(comment)));
|
||||
break;
|
||||
case Python:
|
||||
mWriter.write(String.format("##< %s", CommonHelper.removeEol(comment)));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
73
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/JsonWriter.java
Normal file
73
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/JsonWriter.java
Normal file
@@ -0,0 +1,73 @@
|
||||
import java.io.OutputStreamWriter;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
public class JsonWriter {
|
||||
|
||||
private static JsonObject writeBEnumEntry(EnumsHelper.BEnumEntry enumEntry) {
|
||||
JsonObject data = new JsonObject();
|
||||
data.addProperty("name", enumEntry.mEntryName);
|
||||
data.addProperty("value", enumEntry.mEntryValue);
|
||||
data.addProperty("comment", enumEntry.mEntryComment);
|
||||
|
||||
// Export hierarchy if possible
|
||||
if (enumEntry instanceof EnumsHelper.BHierarchyEnumEntry hierarchyEnumEntry) {
|
||||
// We only export name in hierarchy.
|
||||
// Otherwise we may cause recursive calling.
|
||||
JsonArray entries = new JsonArray();
|
||||
for (EnumsHelper.BHierarchyEnumEntry subEntry : hierarchyEnumEntry.mHierarchy) {
|
||||
entries.add(subEntry.mEntryName);
|
||||
}
|
||||
data.add("hierarchy", entries);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static JsonObject writeBEnum(EnumsHelper.BEnum benum) {
|
||||
JsonObject data = new JsonObject();
|
||||
data.addProperty("name", benum.mEnumName);
|
||||
data.addProperty("comment", benum.mEnumComment);
|
||||
data.addProperty("can_unsigned", benum.mCanUnsigned);
|
||||
data.addProperty("use_flags", benum.mUseFlags);
|
||||
data.addProperty("use_flags", benum.mUseFlags);
|
||||
|
||||
JsonArray entries = new JsonArray();
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
entries.add(writeBEnumEntry(enumEntry));
|
||||
}
|
||||
data.add("entries", entries);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static JsonArray writeBEnumCollection(EnumsHelper.BEnumCollection enumCollection) {
|
||||
JsonArray data = new JsonArray();
|
||||
for (EnumsHelper.BEnum benum : enumCollection.mEnums) {
|
||||
data.add(writeBEnum(benum));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private static void writeJson(String filename, EnumsHelper.BEnumCollection enumCollection) throws Exception {
|
||||
OutputStreamWriter writer = CommonHelper.openOutputFile(filename);
|
||||
//Gson gsonInstance = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
Gson gsonInstance = new GsonBuilder().disableHtmlEscaping().create();
|
||||
writer.write(gsonInstance.toJson(writeBEnumCollection(enumCollection)));
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public static void writeEnums(String filename, EnumsHelper.BEnumCollection enumCollection) throws Exception {
|
||||
writeJson(filename, enumCollection);
|
||||
}
|
||||
|
||||
public static void writeEnum(String filename, EnumsHelper.BEnum benum) throws Exception {
|
||||
// Build collection manually.
|
||||
EnumsHelper.BEnumCollection collection = new EnumsHelper.BEnumCollection();
|
||||
collection.mEnums.add(benum);
|
||||
// Call underlying writer
|
||||
writeEnums(filename, collection);
|
||||
}
|
||||
}
|
||||
196
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/MainRunner.java
Normal file
196
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/MainRunner.java
Normal file
@@ -0,0 +1,196 @@
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.tree.*;
|
||||
|
||||
public class MainRunner {
|
||||
|
||||
/**
|
||||
* Extract an enums collection from given file.
|
||||
* <p>
|
||||
* This function is the most commonly used function for extracting enums.
|
||||
* <p>
|
||||
* This function is used for a file which only contain enum declarations. This
|
||||
* is not suit for extracting CKERROR and CK_CLASSID. For these declarations,
|
||||
* please use their specialized extractor as described following.
|
||||
*
|
||||
* @param filename The file name relative to input directory for reading.
|
||||
* @return An {@linkplain EnumsHelper.BEnumCollection} instance.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static EnumsHelper.BEnumCollection getEnumsCollection(String filename) throws Exception {
|
||||
String infile = CommonHelper.getInputFilePath(filename);
|
||||
CommonHelper.InputFilePair pair = CommonHelper.openInputFile(infile);
|
||||
CKGeneralLexer lexer = new CKGeneralLexer(pair.mAntlrStream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
CKEnumsParser parser = new CKEnumsParser(tokens);
|
||||
|
||||
ParseTree tree = parser.prog();
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
EnumsWalker worker = new EnumsWalker(tokens);
|
||||
walker.walk(worker, tree);
|
||||
|
||||
pair.mUnderlyingStream.close();
|
||||
return worker.getEnums();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a series of "#define" syntax as an enum.
|
||||
* <p>
|
||||
* This function will assume that given file only contain C++ "#define" syntax.
|
||||
* After reading it, it will re-organize it as an enum and return. This only is
|
||||
* used by CKERROR now. But it suit for more scenarios if there are something
|
||||
* like CKERROR in future.
|
||||
*
|
||||
* @param filename The file name relative to input directory for reading.
|
||||
* @param assignedEnumName The desired name of organized enum instance.
|
||||
* Contemporary this field should always be "CKERROR"
|
||||
* because no one else is using it.
|
||||
* @return An {@linkplain EnumsHelper.BEnum} instance.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static EnumsHelper.BEnum organiseDefines(String filename, String assignedEnumName) throws Exception {
|
||||
String infile = CommonHelper.getInputFilePath(filename);
|
||||
CommonHelper.InputFilePair pair = CommonHelper.openInputFile(infile);
|
||||
CKGeneralLexer lexer = new CKGeneralLexer(pair.mAntlrStream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
CKDefinesParser parser = new CKDefinesParser(tokens);
|
||||
|
||||
ParseTree tree = parser.prog();
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
DefinesWalker worker = new DefinesWalker(tokens);
|
||||
walker.walk(worker, tree);
|
||||
|
||||
pair.mUnderlyingStream.close();
|
||||
|
||||
EnumsHelper.BEnum result = worker.getEnum();
|
||||
result.mEnumName = assignedEnumName;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a series of macro define as an enum, considering its indent to build
|
||||
* hierarchy.
|
||||
* <p>
|
||||
* This is specialized enum extractor of CK_CLASSID. The given file should use a
|
||||
* series "#define" syntax to describe enum, and use Tab as the indent before
|
||||
* each "#define" syntax to indicate its hierarchy.
|
||||
*
|
||||
* @param filename The file name relative to input directory for reading.
|
||||
* @return An {@linkplain EnumsHelper.BEnum} instance. Actually it is an
|
||||
* instance to {@linkplain EnumsHelper.BEnum} whose entries is
|
||||
* {@linkplain EnumsHelper.BHierarchyEnumEntry}, the child class of
|
||||
* {@linkplain EnumsHelper.BEnumEntry} (the entry type of common
|
||||
* {@linkplain EnumsHelper.BEnum}) with extra hierarchy infos.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static EnumsHelper.BEnum organiseClassid(String filename) throws Exception {
|
||||
String infile = CommonHelper.getInputFilePath(filename);
|
||||
CommonHelper.InputFilePair pair = CommonHelper.openInputFile(infile);
|
||||
CKGeneralLexer lexer = new CKGeneralLexer(pair.mAntlrStream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
CKDefinesParser parser = new CKDefinesParser(tokens);
|
||||
|
||||
ParseTree tree = parser.prog();
|
||||
ParseTreeWalker walker = new ParseTreeWalker();
|
||||
ClassidWalker worker = new ClassidWalker(tokens);
|
||||
walker.walk(worker, tree);
|
||||
|
||||
pair.mUnderlyingStream.close();
|
||||
|
||||
EnumsHelper.BEnum result = worker.getEnum();
|
||||
result.mEnumName = "CK_CLASSID";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
// =========== CKERROR ===========
|
||||
EnumsHelper.BEnum ckerror = organiseDefines("CKERROR.txt", "CKERROR");
|
||||
JsonWriter.writeEnum(CommonHelper.getOutputFilePath("CKERROR.json"), ckerror);
|
||||
// CppWriter.writeEnum("dest/CKERROR.hpp", ckerror);
|
||||
// PythonWriter.writeEnum("dest/CKERROR.py", ckerror);
|
||||
// CSharpWriter.writeEnum("dest/CKERROR.cs", ckerror);
|
||||
// CppWriter.writeCkErrorAccVal("dest/CKERROR.AccVal.hpp", ckerror);
|
||||
// PythonWriter.writeAccVal("dest/CKERROR.AccVal.py", ckerror);
|
||||
// CSharpWriter.writeAccVal("dest/CKERROR.AccVal.cs", ckerror);
|
||||
|
||||
// =========== CK_CLASSID ===========
|
||||
EnumsHelper.BEnum classid = organiseClassid("CK_CLASSID.txt");
|
||||
JsonWriter.writeEnum(CommonHelper.getOutputFilePath("CK_CLASSID.json"), classid);
|
||||
// CppWriter.writeEnum("dest/CK_CLASSID.hpp", classid);
|
||||
// PythonWriter.writeEnum("dest/CK_CLASSID.py", classid);
|
||||
// CSharpWriter.writeEnum("dest/CK_CLASSID.cs", classid);
|
||||
// CppWriter.writeCkClassidAccVal("dest/CK_CLASSID.AccVal.hpp", classid);
|
||||
// PythonWriter.writeAccVal("dest/CK_CLASSID.AccVal.py", classid);
|
||||
|
||||
// =========== Define2 ===========
|
||||
// Define2 do not need annotation output.
|
||||
// Because they are CKStateChunk used value which are not exposed to outside.
|
||||
EnumsHelper.BEnumCollection def2 = getEnumsCollection("Defines2.txt");
|
||||
JsonWriter.writeEnums(CommonHelper.getOutputFilePath("Defines2.json"), def2);
|
||||
// CppWriter.writeEnums("dest/Defines2.hpp", def2);
|
||||
// PythonWriter.writeEnums("dest/Defines2.py", def2);
|
||||
// CSharpWriter.writeEnums("dest/Defines2.cs", def2);
|
||||
|
||||
// =========== Combined enums ===========
|
||||
EnumsHelper.BEnumCollection ck2Enums = getEnumsCollection("CKEnums.txt"),
|
||||
vxEnums = getEnumsCollection("VxEnums.txt");
|
||||
JsonWriter.writeEnums(CommonHelper.getOutputFilePath("CKEnums.json"), ck2Enums);
|
||||
JsonWriter.writeEnums(CommonHelper.getOutputFilePath("VxEnums.json"), vxEnums);
|
||||
|
||||
// CppWriter.writeEnums("dest/CKEnums.hpp", ck2Enums);
|
||||
// PythonWriter.writeEnums("dest/CKEnums.py", ck2Enums);
|
||||
// CSharpWriter.writeEnums("dest/CKEnums.cs", ck2Enums);
|
||||
// CppWriter.writeAccVals("dest/CKEnums.AccVal.hpp", ck2Enums, CommonHelper.CKParts.CK2);
|
||||
// PythonWriter.writeAccVals("dest/CKEnums.AccVal.py", ck2Enums);
|
||||
// CSharpWriter.writeAccVals("dest/CKEnums.AccVal.cs", ck2Enums);
|
||||
|
||||
// CppWriter.writeEnums("dest/VxEnums.hpp", vxEnums);
|
||||
// PythonWriter.writeEnums("dest/VxEnums.py", vxEnums);
|
||||
// CSharpWriter.writeEnums("dest/VxEnums.cs", vxEnums);
|
||||
// CppWriter.writeAccVals("dest/VxEnums.AccVal.hpp", vxEnums, CommonHelper.CKParts.VxMath);
|
||||
// PythonWriter.writeAccVals("dest/VxEnums.AccVal.py", vxEnums);
|
||||
// CSharpWriter.writeAccVals("dest/VxEnums.AccVal.cs", vxEnums);
|
||||
|
||||
// =========== Single enums ===========
|
||||
EnumsHelper.BEnum single;
|
||||
|
||||
single = organiseDefines("CK_STATECHUNK_CHUNKVERSION.txt", "CK_STATECHUNK_CHUNKVERSION");
|
||||
JsonWriter.writeEnum(CommonHelper.getOutputFilePath("CK_STATECHUNK_CHUNKVERSION.json"), single);
|
||||
// CppWriter.writeEnum("dest/CK_STATECHUNK_CHUNKVERSION.hpp", single);
|
||||
// PythonWriter.writeEnum("dest/CK_STATECHUNK_CHUNKVERSION.py", single);
|
||||
// CSharpWriter.writeEnum("dest/CK_STATECHUNK_CHUNKVERSION.cs", single);
|
||||
// CppWriter.writeAccVal("dest/CK_STATECHUNK_CHUNKVERSION.AccVal.hpp", single, CommonHelper.CKParts.CK2);
|
||||
// PythonWriter.writeAccVal("dest/CK_STATECHUNK_CHUNKVERSION.AccVal.py", single);
|
||||
// CSharpWriter.writeAccVal("dest/CK_STATECHUNK_CHUNKVERSION.AccVal.cs", single);
|
||||
|
||||
single = organiseDefines("CK_STATECHUNK_DATAVERSION.txt", "CK_STATECHUNK_DATAVERSION");
|
||||
JsonWriter.writeEnum(CommonHelper.getOutputFilePath("CK_STATECHUNK_DATAVERSION.json"), single);
|
||||
// CppWriter.writeEnum("dest/CK_STATECHUNK_DATAVERSION.hpp", single);
|
||||
// PythonWriter.writeEnum("dest/CK_STATECHUNK_DATAVERSION.py", single);
|
||||
// CSharpWriter.writeEnum("dest/CK_STATECHUNK_DATAVERSION.cs", single);
|
||||
// CppWriter.writeAccVal("dest/CK_STATECHUNK_DATAVERSION.AccVal.hpp", single, CommonHelper.CKParts.CK2);
|
||||
// PythonWriter.writeAccVal("dest/CK_STATECHUNK_DATAVERSION.AccVal.py", single);
|
||||
// CSharpWriter.writeAccVal("dest/CK_STATECHUNK_DATAVERSION.AccVal.cs", single);
|
||||
|
||||
single = organiseDefines("CK_BITMAPDATA_FLAGS.txt", "CK_BITMAPDATA_FLAGS");
|
||||
JsonWriter.writeEnum(CommonHelper.getOutputFilePath("CK_BITMAPDATA_FLAGS.json"), single);
|
||||
// CppWriter.writeEnum("dest/CK_BITMAPDATA_FLAGS.hpp", single);
|
||||
// PythonWriter.writeEnum("dest/CK_BITMAPDATA_FLAGS.py", single);
|
||||
// CSharpWriter.writeEnum("dest/CK_BITMAPDATA_FLAGS.cs", single);
|
||||
// CppWriter.writeAccVal("dest/CK_BITMAPDATA_FLAGS.AccVal.hpp", single, CommonHelper.CKParts.CK2);
|
||||
// PythonWriter.writeAccVal("dest/CK_BITMAPDATA_FLAGS.AccVal.py", single);
|
||||
// CSharpWriter.writeAccVal("dest/CK_BITMAPDATA_FLAGS.AccVal.cs", single);
|
||||
|
||||
single = organiseDefines("CK_CAMERA_PROJECTION.txt", "CK_CAMERA_PROJECTION");
|
||||
JsonWriter.writeEnum(CommonHelper.getOutputFilePath("CK_CAMERA_PROJECTION.json"), single);
|
||||
// CppWriter.writeEnum("dest/CK_CAMERA_PROJECTION.hpp", single);
|
||||
// PythonWriter.writeEnum("dest/CK_CAMERA_PROJECTION.py", single);
|
||||
// CSharpWriter.writeEnum("dest/CK_CAMERA_PROJECTION.cs", single);
|
||||
// CppWriter.writeAccVal("dest/CK_CAMERA_PROJECTION.AccVal.hpp", single, CommonHelper.CKParts.CK2);
|
||||
// PythonWriter.writeAccVal("dest/CK_CAMERA_PROJECTION.AccVal.py", single);
|
||||
// CSharpWriter.writeAccVal("dest/CK_CAMERA_PROJECTION.AccVal.cs", single);
|
||||
|
||||
// print message.
|
||||
System.out.println("Done");
|
||||
}
|
||||
}
|
||||
185
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/PythonWriter.java
Normal file
185
Assets/CodeGen/EnumsMigration/EnumsAnalyzer/PythonWriter.java
Normal file
@@ -0,0 +1,185 @@
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Write enum declarations and accessible value into Python format.
|
||||
*/
|
||||
public class PythonWriter {
|
||||
|
||||
// =========== Python Enum Declaration Writer ===========
|
||||
|
||||
/**
|
||||
* Internal real enum declaration writer.
|
||||
*
|
||||
* @param writer {@linkplain java.io.OutputStreamWriter} instance for writing.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void internalWriteEnums(OutputStreamWriter writer, EnumsHelper.BEnumCollection prog)
|
||||
throws Exception {
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.Python);
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
// write enum start
|
||||
indent.printf("class %s(enum.IntEnum):", benum.mEnumName);
|
||||
indent.inc();
|
||||
|
||||
// write enum comment
|
||||
indent.briefComment(benum.mEnumComment);
|
||||
|
||||
// write enum entries
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
// write entry self
|
||||
if (enumEntry.mEntryValue == null) {
|
||||
indent.printf("%s = auto()", enumEntry.mEntryName);
|
||||
} else {
|
||||
indent.printf("%s = %s", enumEntry.mEntryName,
|
||||
CommonHelper.convertToPythonNumber(enumEntry.mEntryValue));
|
||||
}
|
||||
|
||||
// write entry comment after member
|
||||
indent.afterMemberComment(enumEntry.mEntryComment);
|
||||
}
|
||||
|
||||
// enum tail
|
||||
indent.dec();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum declaration collection into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum declaration collection writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for
|
||||
* writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeEnums(String filename, EnumsHelper.BEnumCollection prog) throws Exception {
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteEnums(fs, prog);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single enum declaration into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum declaration collection writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param _enum {@linkplain EnumsHelper.BEnum} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeEnum(String filename, EnumsHelper.BEnum _enum) throws Exception {
|
||||
// create collection from single enum
|
||||
EnumsHelper.BEnumCollection col = new EnumsHelper.BEnumCollection();
|
||||
col.mEnums.add(_enum);
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteEnums(fs, col);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
// =========== Python Enum Accessible Value Writer ===========
|
||||
|
||||
/**
|
||||
* Try generate human readable name from enum entry name.
|
||||
* <p>
|
||||
* This function is only served for Python code generation.
|
||||
* <p>
|
||||
* As you noticed, almost entries of CK enums are fully capital and splitted by
|
||||
* underline. This is really not good for human reading, especially those who
|
||||
* are not programmer. So this function will try give these programmer-oriented
|
||||
* entry name a human readable name as its display name. However, this extract
|
||||
* method is not perfect. It simply do some split and replacement so the
|
||||
* generated content may still not good for reader.
|
||||
*
|
||||
* @param entry_name The name of enum entry
|
||||
* @return A human readable entry name. No guaranteen that return value is must
|
||||
* human readable.
|
||||
*/
|
||||
private static String extractHumanReadableEntryName(String entry_name) {
|
||||
// remove first part (any content before underline '_')
|
||||
entry_name = entry_name.replaceFirst("^[a-zA-Z0-9]+_", "");
|
||||
|
||||
// lower all chars except first char
|
||||
if (entry_name.length() < 1)
|
||||
return entry_name;
|
||||
else
|
||||
return entry_name.substring(0, 1) + entry_name.substring(1).toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal real enum accessible value writer.
|
||||
*
|
||||
* @param writer {@linkplain java.io.OutputStreamWriter} instance for writing.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void internalWriteAccVals(OutputStreamWriter writer, EnumsHelper.BEnumCollection prog)
|
||||
throws Exception {
|
||||
IndentHelper indent = new IndentHelper(writer, CommonHelper.LangType.Python);
|
||||
|
||||
// write implements
|
||||
for (EnumsHelper.BEnum benum : prog.mEnums) {
|
||||
// write enum desc header
|
||||
indent.printf("g_Annotation_%s: dict[int, EnumAnnotation] = {", benum.mEnumName);
|
||||
indent.inc();
|
||||
|
||||
// write enum desc entries
|
||||
for (EnumsHelper.BEnumEntry enumEntry : benum.mEntries) {
|
||||
String comment = "";
|
||||
if (enumEntry.mEntryComment != null) {
|
||||
comment = CommonHelper.escapeString(enumEntry.mEntryComment);
|
||||
}
|
||||
|
||||
indent.printf("%s.%s.value: EnumAnnotation(\"%s\", \"%s\"),", benum.mEnumName, enumEntry.mEntryName,
|
||||
extractHumanReadableEntryName(enumEntry.mEntryName), comment);
|
||||
}
|
||||
|
||||
// write enum tail
|
||||
indent.dec();
|
||||
indent.puts("}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an enum accessible value collection into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum accessible value collection
|
||||
* writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param prog {@linkplain EnumsHelper.BEnumCollection} instance for
|
||||
* writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeAccVals(String filename, EnumsHelper.BEnumCollection prog) throws Exception {
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteAccVals(fs, prog);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a single enum accessible value into given file.
|
||||
* <p>
|
||||
* Actually this is a wrapper of internal enum accessible value collection
|
||||
* writer.
|
||||
*
|
||||
* @param filename The name of written file.
|
||||
* @param _enum {@linkplain EnumsHelper.BEnum} instance for writing.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void writeAccVal(String filename, EnumsHelper.BEnum _enum) throws Exception {
|
||||
// create a collection with single enum.
|
||||
EnumsHelper.BEnumCollection col = new EnumsHelper.BEnumCollection();
|
||||
col.mEnums.add(_enum);
|
||||
// open file and write
|
||||
OutputStreamWriter fs = CommonHelper.openOutputFile(filename);
|
||||
internalWriteAccVals(fs, col);
|
||||
fs.close();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user