Skip to content
Open
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
3 changes: 2 additions & 1 deletion CodeFormatCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ target_sources(CodeFormatCore
src/Format/Analyzer/FormatDocAnalyze.cpp
src/Format/Analyzer/AlignAnalyzer.cpp
src/Format/Analyzer/TokenAnalyzer.cpp
src/Format/Analyzer/SemicolonAnalyzer.cpp
src/Format/Analyzer/FormatResolve.cpp
src/Format/Analyzer/SyntaxNodeHelper.cpp
# rangeFormat
Expand All @@ -51,7 +52,7 @@ target_sources(CodeFormatCore
src/Diagnostic/Spell/TextParser.cpp
# diagnostic/codestyle
src/Diagnostic/CodeStyle/CodeStyleChecker.cpp
)
)

if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(CodeFormatCore PUBLIC /utf-8)
Expand Down
2 changes: 2 additions & 0 deletions CodeFormatCore/include/CodeFormatCore/Config/LuaStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,6 @@ class LuaStyle {
bool leading_comma_style = false;

bool table_list_special_continue_indent = true;

EndStmtWithSemicolon end_statement_with_semicolon = EndStmtWithSemicolon(EndStmtWithSemicolon::Keep);
};
7 changes: 7 additions & 0 deletions CodeFormatCore/include/CodeFormatCore/Config/LuaStyleEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,11 @@ enum class AlignChainExpr {
None,
Always,
OnlyCallStmt
};

enum class EndStmtWithSemicolon {
Keep,
Never,
Always,
SameLine
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum class DiagnosticType {
StatementLineSpace,
EndWithNewLine,
Indent,
Semicolon,
NameStyle,
Spell
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ enum class FormatAnalyzerType {
AlignAnalyzer,
TokenAnalyzer,
FormatDocAnalyze,

SemicolonAnalyzer,
Count,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ enum class TokenStrategy {
StringDoubleQuote,
TableSepSemicolon,
TableSepComma,
OriginRange
OriginRange,
StmtEndSemicolon,
NewLineBeforeToken
};

enum class TokenAddStrategy {
None,
TableAddColon,
TableAddComma
TableAddComma,
StmtEndSemicolon
};

enum class IndentStrategy {
Expand Down Expand Up @@ -120,3 +123,9 @@ struct AlignGroup {
bool Resolve;
std::size_t AlignPos;
};

enum class SemicolonStrategy {
Add,
Remove,
InsertNewLine
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include "FormatAnalyzer.h"
#include "FormatStrategy.h"
#include <unordered_map>
#include <unordered_set>

class SemicolonAnalyzer : public FormatAnalyzer {
public:
DECLARE_FORMAT_ANALYZER(SemicolonAnalyzer)

SemicolonAnalyzer();

void Analyze(FormatState& f, const LuaSyntaxTree& t) override;

void Query(FormatState& f, LuaSyntaxNode syntaxNode, const LuaSyntaxTree& t, FormatResolve& resolve) override;

private:
void AddSemicolon(LuaSyntaxNode n, const LuaSyntaxTree& t);
void InsertNewLineBeforeNode(LuaSyntaxNode n, const LuaSyntaxTree& t);
void RemoveSemicolon(LuaSyntaxNode n, const LuaSyntaxTree& t);
bool IsFirstStmtOfLine(LuaSyntaxNode n, const LuaSyntaxTree& t);
bool IsLastStmtOfLine(LuaSyntaxNode n, const LuaSyntaxTree& t);
bool EndsWithSemicolon(LuaSyntaxNode n, const LuaSyntaxTree& t);
LuaSyntaxNode GetLastNonCommentToken(LuaSyntaxNode n, const LuaSyntaxTree& t);

std::unordered_map<std::size_t, SemicolonStrategy> _semicolon;
};
22 changes: 22 additions & 0 deletions CodeFormatCore/src/Config/LuaStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,26 @@ void LuaStyle::ParseFromMap(std::map<std::string, std::string, std::less<>> &con
BOOL_OPTION(ignore_space_after_colon)

BOOL_OPTION(remove_call_expression_list_finish_comma)

//if (configMap.count("align_chain_expr")) {
// if (configMap.at("align_chain_expr") == "none") {
// align_chain_expr = AlignChainExpr::None;
// } else if (configMap.at("align_chain_expr") == "always") {
// align_chain_expr = AlignChainExpr::Always;
// } else if (configMap.at("align_chain_expr") == "only_call_stmt") {
// align_chain_expr = AlignChainExpr::OnlyCallStmt;
// }
//}

if (configMap.count("end_statement_with_semicolon")) {
if (configMap.at("end_statement_with_semicolon") == "keep") {
end_statement_with_semicolon = EndStmtWithSemicolon::Keep;
} else if (configMap.at("end_statement_with_semicolon") == "always") {
end_statement_with_semicolon = EndStmtWithSemicolon::Always;
} else if (configMap.at("end_statement_with_semicolon") == "never") {
end_statement_with_semicolon = EndStmtWithSemicolon::Never;
} else if (configMap.at("end_statement_with_semicolon") == "sameLine") {
end_statement_with_semicolon = EndStmtWithSemicolon::SameLine;
}
}
}
36 changes: 36 additions & 0 deletions CodeFormatCore/src/Diagnostic/CodeStyle/CodeStyleChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,35 @@ void CodeStyleChecker::BasicResolve(LuaSyntaxNode syntaxNode, const LuaSyntaxTre

break;
}
case TokenStrategy::StmtEndSemicolon: {
switch (d.GetState().GetStyle().end_statement_with_semicolon) {
case EndStmtWithSemicolon::Never:
d.PushDiagnostic(DiagnosticType::Semicolon, textRange,
LText("Statement should not end with ;"));
break;
case EndStmtWithSemicolon::SameLine:
d.PushDiagnostic(DiagnosticType::Semicolon, textRange,
LText("; should only separate multiple statements on a single line"));
break;
default:
break;
}
break;
}
default: {
break;
}
}

switch (resolve.GetTokenAddStrategy()) {
case TokenAddStrategy::StmtEndSemicolon:
d.PushDiagnostic(DiagnosticType::Semicolon, textRange,
LText("Missing ; at end of statement"));
break;
default:
break;
}

switch (resolve.GetNextSpaceStrategy()) {
case NextSpaceStrategy::Space: {
auto nextToken = syntaxNode.GetNextToken(t);
Expand All @@ -115,6 +139,18 @@ void CodeStyleChecker::BasicResolve(LuaSyntaxNode syntaxNode, const LuaSyntaxTre
}
}
}
if (syntaxNode.IsNode(t)) {
auto textRange = syntaxNode.GetTextRange(t);
switch (resolve.GetTokenStrategy()) {
case TokenStrategy::StmtEndSemicolon: {
d.PushDiagnostic(DiagnosticType::Indent, textRange, LText("semicolon diagnostic"));
break;
}
default: {
break;
}
}
}
}

void CodeStyleChecker::ProcessSpaceDiagnostic(LuaSyntaxNode &node, LuaSyntaxNode &next, size_t shouldSpace,
Expand Down
135 changes: 135 additions & 0 deletions CodeFormatCore/src/Format/Analyzer/SemicolonAnalyzer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#include "CodeFormatCore/Format/Analyzer/SemicolonAnalyzer.h"
#include "CodeFormatCore/Format/FormatState.h"
#include "CodeFormatCore/Config/LuaStyleEnum.h"
#include <iostream>
#include <LuaParser/Lexer/LuaTokenTypeDetail.h>

SemicolonAnalyzer::SemicolonAnalyzer() {

}

void SemicolonAnalyzer::Analyze(FormatState& f, const LuaSyntaxTree& t) {
if (f.GetStyle().end_statement_with_semicolon == EndStmtWithSemicolon::Keep) {
return; // No analysis needed
}

for (auto syntaxNode : t.GetSyntaxNodes()) {
if (syntaxNode.IsNode(t)) {
if (detail::multi_match::StatementMatch(syntaxNode.GetSyntaxKind(t))) {
auto text = syntaxNode.GetText(t);
switch (f.GetStyle().end_statement_with_semicolon) {
case EndStmtWithSemicolon::Always:
// TODO handle stray semicolons that are unnecessarily added!
/*if (syntaxNode.GetTextRange(t).Length < 2)
break;*/
if (!EndsWithSemicolon(syntaxNode, t)) {
AddSemicolon(syntaxNode, t);
}
break;
case EndStmtWithSemicolon::Never:
// is on same line as other statement -> needs to go on new line
if (!IsFirstStmtOfLine(syntaxNode, t)) {
InsertNewLineBeforeNode(syntaxNode, t);
}
if (EndsWithSemicolon(syntaxNode, t)) {
RemoveSemicolon(syntaxNode, t);
}
break;
case EndStmtWithSemicolon::SameLine:
if (EndsWithSemicolon(syntaxNode, t)) {
if (IsLastStmtOfLine(syntaxNode, t)) {
RemoveSemicolon(syntaxNode, t);
}
}
break;
default:
break;
}
}
}
}
}

void SemicolonAnalyzer::Query(FormatState& f, LuaSyntaxNode n, const LuaSyntaxTree& t, FormatResolve& resolve) {
auto it = _semicolon.find(n.GetIndex());
if (it != _semicolon.end()) {
auto& strategy = it->second;
switch (strategy) {
case SemicolonStrategy::Add:
resolve.SetTokenAddStrategy(TokenAddStrategy::StmtEndSemicolon);
break;
case SemicolonStrategy::Remove:
resolve.SetTokenStrategy(TokenStrategy::StmtEndSemicolon);
break;
case SemicolonStrategy::InsertNewLine:
resolve.SetTokenStrategy(TokenStrategy::NewLineBeforeToken);
break;
default:
break;
}
}
}

void SemicolonAnalyzer::AddSemicolon(LuaSyntaxNode n, const LuaSyntaxTree& t) {
auto token = GetLastNonCommentToken(n, t);
if (token.IsToken(t)) {
_semicolon[token.GetIndex()] = SemicolonStrategy::Add;
}
}

void SemicolonAnalyzer::InsertNewLineBeforeNode(LuaSyntaxNode n, const LuaSyntaxTree& t) {
auto token = n.GetFirstToken(t); // line breaks are put in front of the statement itself by non-first statements
if (token.IsToken(t)) {
_semicolon[token.GetIndex()] = SemicolonStrategy::InsertNewLine;
}
}

void SemicolonAnalyzer::RemoveSemicolon(LuaSyntaxNode n, const LuaSyntaxTree& t) {
auto token = GetLastNonCommentToken(n, t);
if (token.IsToken(t)) {
_semicolon[token.GetIndex()] = SemicolonStrategy::Remove;
}
}

bool SemicolonAnalyzer::IsFirstStmtOfLine(LuaSyntaxNode n, const LuaSyntaxTree& t) {
// check if current stmt starts on same line as the previous one ends
auto startCurrent = n.GetStartLine(t);
auto prev = n.GetPrevToken(t);
if (!prev.IsNull(t)) {
auto endPrev = prev.GetEndLine(t);
return endPrev < startCurrent;
}
return true; // there's no previous token
}

bool SemicolonAnalyzer::IsLastStmtOfLine(LuaSyntaxNode n, const LuaSyntaxTree& t) {
// check if next stmt starts on same line as the current one ends
auto currentEnd = n.GetEndLine(t);
auto nextToken = n.GetNextToken(t);
if (!nextToken.IsNull(t)) {
auto nextStart = nextToken.GetStartLine(t);
return currentEnd != nextStart;
}
return true; // there's no next token
}

bool SemicolonAnalyzer::EndsWithSemicolon(LuaSyntaxNode n, const LuaSyntaxTree& t) {
auto token = GetLastNonCommentToken(n, t);
auto text = token.GetText(t);

return text == ";";
}

LuaSyntaxNode SemicolonAnalyzer::GetLastNonCommentToken(LuaSyntaxNode n, const LuaSyntaxTree& t) {
auto token = n.GetLastToken(t);
switch (token.GetTokenKind(t)) {
case TK_SHORT_COMMENT:
case TK_LONG_COMMENT:
case TK_SHEBANG: {
return token.GetPrevToken(t);
}
default: {
return token;
}
}
}
10 changes: 10 additions & 0 deletions CodeFormatCore/src/Format/FormatBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void FormatBuilder::DoResolve(LuaSyntaxNode &syntaxNode, const LuaSyntaxTree &t,
WriteSyntaxNode(syntaxNode, t);
break;
}
case TokenStrategy::StmtEndSemicolon:
case TokenStrategy::Remove: {
break;
}
Expand Down Expand Up @@ -139,6 +140,11 @@ void FormatBuilder::DoResolve(LuaSyntaxNode &syntaxNode, const LuaSyntaxTree &t,
}
return;
}
case TokenStrategy::NewLineBeforeToken: {
WriteLine(1);
WriteSyntaxNode(syntaxNode, t);
break;
}
default: {
break;
}
Expand All @@ -153,6 +159,10 @@ void FormatBuilder::DoResolve(LuaSyntaxNode &syntaxNode, const LuaSyntaxTree &t,
WriteChar(';');
break;
}
case TokenAddStrategy::StmtEndSemicolon: {
WriteChar(';');
break;
}
default: {
break;
}
Expand Down
5 changes: 4 additions & 1 deletion CodeFormatCore/src/Format/FormatState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "CodeFormatCore/Format/Analyzer/LineBreakAnalyzer.h"
#include "CodeFormatCore/Format/Analyzer/SpaceAnalyzer.h"
#include "CodeFormatCore/Format/Analyzer/TokenAnalyzer.h"
#include <CodeFormatCore/Format/Analyzer/SemicolonAnalyzer.h>

FormatState::FormatState(Mode mode)
: _currentWidth(0),
Expand Down Expand Up @@ -52,6 +53,7 @@ void FormatState::Analyze(const LuaSyntaxTree &t) {
AddAnalyzer<AlignAnalyzer>();
AddAnalyzer<TokenAnalyzer>();
AddAnalyzer<FormatDocAnalyze>();
AddAnalyzer<SemicolonAnalyzer>();

_fileEndOfLine = t.GetFile().GetEndOfLine();
for (const auto &analyzer: _analyzers) {
Expand Down Expand Up @@ -161,7 +163,8 @@ void FormatState::DfsForeach(std::vector<LuaSyntaxNode> &startNodes,
}
}
for (auto &analyzer: _analyzers) {
analyzer->Query(*this, traverse.Node, t, resolve);
if(analyzer)
analyzer->Query(*this, traverse.Node, t, resolve);
}
auto children = traverse.Node.GetChildren(t);
// 不采用 <range>
Expand Down
2 changes: 2 additions & 0 deletions CodeFormatLib/src/CodeFormatLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ std::string GetDiagnosisString(DiagnosticType type) {
return "spell";
case DiagnosticType::StringQuote:
return "string-quote";
case DiagnosticType::Semicolon:
return "semicolon";
default: {
break;
}
Expand Down
Loading