mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 06:13:45 -07:00
Added sub-expression coloring.
This commit is contained in:
parent
b5490e95f6
commit
3729f4dc5d
3 changed files with 118 additions and 21 deletions
|
@ -168,7 +168,7 @@ class Parser {
|
|||
|
||||
if (Match("!")) {
|
||||
expr = std::make_shared<LogicExpression::Impl>();
|
||||
expr->type = LogicExpression::Impl::Type::Not;
|
||||
expr->type = LogicExpression::Type::Not;
|
||||
expr->children.emplace_back(ParsePrimary());
|
||||
expr->children.back()->parent = expr.get();
|
||||
} else if (Peek().Type == LETokenType::ParenOpen) {
|
||||
|
@ -188,7 +188,7 @@ class Parser {
|
|||
--pos;
|
||||
std::string id = Next().Text;
|
||||
Next(); // consume '('
|
||||
expr->type = LogicExpression::Impl::Type::FunctionCall;
|
||||
expr->type = LogicExpression::Type::FunctionCall;
|
||||
expr->functionName = id;
|
||||
while (Peek().Type != LETokenType::ParenClose) {
|
||||
if (!expr->children.empty()) {
|
||||
|
@ -203,7 +203,7 @@ class Parser {
|
|||
}
|
||||
Next(); // consume ')'
|
||||
} else {
|
||||
expr->type = LogicExpression::Impl::Type::Value;
|
||||
expr->type = LogicExpression::Type::Value;
|
||||
expr->value = token.Text;
|
||||
if (token.Type == LETokenType::Boolean)
|
||||
expr->valueType = LogicExpression::Impl::ValueType::Boolean;
|
||||
|
@ -229,7 +229,7 @@ class Parser {
|
|||
template <typename LowerFunc>
|
||||
std::shared_ptr<LogicExpression::Impl>
|
||||
ParseBinaryOp(size_t& pos, const std::vector<Token>& tokens, LowerFunc lowerFunc,
|
||||
const std::vector<std::pair<std::string, LogicExpression::Impl::Type>>& operators) {
|
||||
const std::vector<std::pair<std::string, LogicExpression::Type>>& operators) {
|
||||
size_t initial_pos = pos;
|
||||
auto left = (this->*lowerFunc)();
|
||||
|
||||
|
@ -240,9 +240,7 @@ class Parser {
|
|||
auto right = ParseBinaryOp(pos, tokens, lowerFunc, operators);
|
||||
auto expr = std::make_shared<LogicExpression::Impl>();
|
||||
expr->type = exprType;
|
||||
if (exprType == LogicExpression::Impl::Type::Comparison) {
|
||||
expr->operation = op;
|
||||
}
|
||||
expr->operation = op;
|
||||
expr->children.emplace_back(left);
|
||||
expr->children.back()->parent = expr.get();
|
||||
expr->children.emplace_back(right);
|
||||
|
@ -259,33 +257,33 @@ class Parser {
|
|||
std::shared_ptr<LogicExpression::Impl> ParseMulDiv() {
|
||||
return ParseBinaryOp(
|
||||
pos, tokens, &Parser::ParsePrimary,
|
||||
{ { "*", LogicExpression::Impl::Type::Multiply }, { "/", LogicExpression::Impl::Type::Divide } });
|
||||
{ { "*", LogicExpression::Type::Multiply }, { "/", LogicExpression::Type::Divide } });
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicExpression::Impl> ParseAddSub() {
|
||||
return ParseBinaryOp(
|
||||
pos, tokens, &Parser::ParseMulDiv,
|
||||
{ { "+", LogicExpression::Impl::Type::Add }, { "-", LogicExpression::Impl::Type::Subtract } });
|
||||
{ { "+", LogicExpression::Type::Add }, { "-", LogicExpression::Type::Subtract } });
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicExpression::Impl> ParseComparison() {
|
||||
return ParseBinaryOp(pos, tokens, &Parser::ParseAddSub,
|
||||
{ { "==", LogicExpression::Impl::Type::Comparison },
|
||||
{ "!=", LogicExpression::Impl::Type::Comparison },
|
||||
{ ">=", LogicExpression::Impl::Type::Comparison },
|
||||
{ "<=", LogicExpression::Impl::Type::Comparison },
|
||||
{ ">", LogicExpression::Impl::Type::Comparison },
|
||||
{ "<", LogicExpression::Impl::Type::Comparison } });
|
||||
{ { "==", LogicExpression::Type::Comparison },
|
||||
{ "!=", LogicExpression::Type::Comparison },
|
||||
{ ">=", LogicExpression::Type::Comparison },
|
||||
{ "<=", LogicExpression::Type::Comparison },
|
||||
{ ">", LogicExpression::Type::Comparison },
|
||||
{ "<", LogicExpression::Type::Comparison } });
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicExpression::Impl> ParseAnd() {
|
||||
return ParseBinaryOp(pos, tokens, &Parser::ParseComparison,
|
||||
{ { "&&", LogicExpression::Impl::Type::And } });
|
||||
{ { "&&", LogicExpression::Type::And } });
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicExpression::Impl> ParseOr() {
|
||||
return ParseBinaryOp(pos, tokens, &Parser::ParseAnd,
|
||||
{ { "||", LogicExpression::Impl::Type::Or } });
|
||||
{ { "||", LogicExpression::Type::Or } });
|
||||
}
|
||||
|
||||
std::shared_ptr<LogicExpression::Impl> ParseTernary() {
|
||||
|
@ -305,7 +303,7 @@ class Parser {
|
|||
auto falseExpr = ParseTernary();
|
||||
|
||||
auto expr = std::make_shared<LogicExpression::Impl>();
|
||||
expr->type = LogicExpression::Impl::Type::Ternary;
|
||||
expr->type = LogicExpression::Type::Ternary;
|
||||
|
||||
expr->children.emplace_back(cond);
|
||||
expr->children.back()->parent = expr.get();
|
||||
|
@ -368,6 +366,18 @@ const std::vector<std::shared_ptr<LogicExpression>>& LogicExpression::GetChildre
|
|||
return children;
|
||||
}
|
||||
|
||||
LogicExpression::Type LogicExpression::GetType() const {
|
||||
return impl->type;
|
||||
}
|
||||
|
||||
std::string LogicExpression::GetOperation() const {
|
||||
return impl->operation;
|
||||
}
|
||||
|
||||
std::string LogicExpression::GetFunctionName() const {
|
||||
return impl->functionName;
|
||||
}
|
||||
|
||||
std::string LogicExpression::ToString() const {
|
||||
if (impl->expressionString != nullptr) {
|
||||
return *impl->expressionString;
|
||||
|
|
|
@ -14,11 +14,17 @@ class LogicExpression {
|
|||
public:
|
||||
using ValueVariant = std::variant<bool, int, uint8_t, uint16_t>;
|
||||
// Define callback type for evaluation tracing
|
||||
using EvaluationCallback = std::function<void(const std::shared_ptr<LogicExpression>&, const std::string&, int, const std::string&, const ValueVariant&)>;
|
||||
using EvaluationCallback = std::function<void(const std::shared_ptr<LogicExpression>&, const std::string&, int,
|
||||
const std::string&, const ValueVariant&)>;
|
||||
|
||||
enum class Type { And, Or, Not, Comparison, FunctionCall, Value, Add, Subtract, Multiply, Divide, Ternary };
|
||||
|
||||
static std::shared_ptr<LogicExpression> Parse(const std::string& exprStr);
|
||||
std::string ToString() const;
|
||||
const std::vector<std::shared_ptr<LogicExpression>>& GetChildren() const;
|
||||
Type GetType() const;
|
||||
std::string GetOperation() const;
|
||||
std::string GetFunctionName() const;
|
||||
|
||||
// Add optional callback parameter to Evaluate
|
||||
template <typename T> T Evaluate(const EvaluationCallback& callback = nullptr) const {
|
||||
|
@ -54,7 +60,6 @@ class LogicExpression {
|
|||
|
||||
private:
|
||||
struct Impl {
|
||||
enum class Type { And, Or, Not, Comparison, FunctionCall, Value, Add, Subtract, Multiply, Divide, Ternary };
|
||||
|
||||
enum class ValueType { Identifier, Boolean, Number, Enum };
|
||||
|
||||
|
|
|
@ -175,6 +175,88 @@ static std::string ToString(const std::optional<LogicExpression::ValueVariant>&
|
|||
return ToString(value.value());
|
||||
}
|
||||
|
||||
static void DrawColoredWrappedText(const std::vector<std::pair<ImVec4, std::string>>& segments) {
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
float wrapWidth = ImGui::GetContentRegionAvail().x;
|
||||
float x = pos.x;
|
||||
float y = pos.y;
|
||||
float startX = x;
|
||||
ImFont* font = ImGui::GetFont();
|
||||
float fontSize = ImGui::GetFontSize();
|
||||
|
||||
for (const auto& [color, text] : segments) {
|
||||
std::istringstream iss(text + " ");
|
||||
std::string word;
|
||||
bool firstWordInSegment = true;
|
||||
while (std::getline(iss, word, ' ')) {
|
||||
std::string toDraw = word;
|
||||
if (!firstWordInSegment) {
|
||||
toDraw = " " + word;
|
||||
}
|
||||
ImVec2 textSize = ImGui::CalcTextSize(toDraw.c_str());
|
||||
if (x + textSize.x > startX + wrapWidth && x > startX) {
|
||||
x = startX;
|
||||
y += fontSize;
|
||||
toDraw = word;
|
||||
textSize = ImGui::CalcTextSize(toDraw.c_str());
|
||||
}
|
||||
draw_list->AddText(font, fontSize, ImVec2(x, y), ImGui::ColorConvertFloat4ToU32(color), toDraw.c_str());
|
||||
x += textSize.x;
|
||||
firstWordInSegment = false;
|
||||
}
|
||||
}
|
||||
ImGui::SetCursorScreenPos(ImVec2(x, y + fontSize));
|
||||
}
|
||||
|
||||
static void DrawCondition(const LogicExpression& expression) {
|
||||
static ImVec4 fontColors[] = {
|
||||
ImVec4(0.5f, 0.5f, 1.0f, 1.0f), // Blue
|
||||
ImVec4(0.5f, 1.0f, 0.5f, 1.0f), // Green
|
||||
ImVec4(1.0f, 0.5f, 0.5f, 1.0f), // Red
|
||||
ImVec4(1.0f, 1.0f, 0.5f, 1.0f), // Yellow
|
||||
ImVec4(1.0f, 0.5f, 1.0f, 1.0f), // Magenta
|
||||
ImVec4(0.5f, 1.0f, 1.0f, 1.0f), // Cyan
|
||||
};
|
||||
static size_t fontColorsLength = std::size(fontColors);
|
||||
static ImVec4 defaultColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
|
||||
|
||||
LogicExpression::Type type = expression.GetType();
|
||||
if (type == LogicExpression::Type::And || type == LogicExpression::Type::Or ||
|
||||
type == LogicExpression::Type::Comparison || type == LogicExpression::Type::Add ||
|
||||
type == LogicExpression::Type::Subtract || type == LogicExpression::Type::Multiply ||
|
||||
type == LogicExpression::Type::Divide) {
|
||||
DrawColoredWrappedText({ { fontColors[0], expression.GetChildren()[0]->ToString() },
|
||||
{ defaultColor, " " + expression.GetOperation() + " " },
|
||||
{ fontColors[1], expression.GetChildren()[1]->ToString() } });
|
||||
} else if (type == LogicExpression::Type::Not) {
|
||||
DrawColoredWrappedText({ { defaultColor, "!" },
|
||||
{ fontColors[0], expression.GetChildren()[0]->ToString() } });
|
||||
} else if (type == LogicExpression::Type::FunctionCall) {
|
||||
std::vector<std::pair<ImVec4, std::string>> segments;
|
||||
segments.emplace_back(fontColors[0], expression.GetFunctionName());
|
||||
segments.emplace_back(defaultColor, "(");
|
||||
for (size_t i = 0; i < expression.GetChildren().size(); ++i) {
|
||||
segments.emplace_back(fontColors[i + 1 % fontColorsLength], expression.GetChildren()[i]->ToString());
|
||||
if (i < expression.GetChildren().size() - 1) {
|
||||
segments.emplace_back(defaultColor, ", ");
|
||||
}
|
||||
}
|
||||
segments.emplace_back(defaultColor, ")");
|
||||
DrawColoredWrappedText(segments);
|
||||
} else if (type == LogicExpression::Type::Ternary) {
|
||||
DrawColoredWrappedText({ { fontColors[0], expression.GetChildren()[0]->ToString() },
|
||||
{ defaultColor, " ? " },
|
||||
{ fontColors[1], expression.GetChildren()[1]->ToString() },
|
||||
{ defaultColor, " : " },
|
||||
{ fontColors[2], expression.GetChildren()[2]->ToString() } });
|
||||
} else if (type == LogicExpression::Type::Value) {
|
||||
DrawColoredWrappedText({ { fontColors[0], expression.ToString() } });
|
||||
} else {
|
||||
DrawColoredWrappedText({ { defaultColor, expression.ToString() } });
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawExpressionRow(const LogicTrackerCheck::Region& region, LogicTrackerCheck::Region::ExpressionRow& row,
|
||||
int level) {
|
||||
ImGui::TableNextRow();
|
||||
|
@ -196,7 +278,7 @@ static void DrawExpressionRow(const LogicTrackerCheck::Region& region, LogicTrac
|
|||
}
|
||||
ImGui::PopID();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextWrapped("%s", row.Expression->ToString().c_str());
|
||||
DrawCondition(*row.Expression);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(ToString(row.ChildDay).c_str());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue