mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 05:40:01 -06:00
Parser and Assembler implementations
This commit is contained in:
261
Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp
Normal file
261
Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "DolphinQt/Debugger/GekkoSyntaxHighlight.h"
|
||||
|
||||
#include "Common/Assembler/GekkoParser.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPalette>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace Common::GekkoAssembler;
|
||||
using namespace Common::GekkoAssembler::detail;
|
||||
|
||||
class HighlightParsePlugin : public ParsePlugin
|
||||
{
|
||||
public:
|
||||
virtual ~HighlightParsePlugin() = default;
|
||||
|
||||
std::vector<std::pair<int, int>>&& MoveParens() { return std::move(m_matched_parens); }
|
||||
std::vector<std::tuple<int, int, HighlightFormat>>&& MoveFormatting()
|
||||
{
|
||||
return std::move(m_formatting);
|
||||
}
|
||||
|
||||
void OnDirectivePre(GekkoDirective) override { HighlightCurToken(HighlightFormat::Directive); }
|
||||
|
||||
void OnInstructionPre(const ParseInfo&, bool) override
|
||||
{
|
||||
HighlightCurToken(HighlightFormat::Mnemonic);
|
||||
}
|
||||
|
||||
void OnTerminal(Terminal type, const AssemblerToken& val) override
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Terminal::Id:
|
||||
HighlightCurToken(HighlightFormat::Symbol);
|
||||
break;
|
||||
|
||||
case Terminal::Hex:
|
||||
case Terminal::Dec:
|
||||
case Terminal::Oct:
|
||||
case Terminal::Bin:
|
||||
case Terminal::Flt:
|
||||
HighlightCurToken(HighlightFormat::Immediate);
|
||||
break;
|
||||
|
||||
case Terminal::GPR:
|
||||
HighlightCurToken(HighlightFormat::GPR);
|
||||
break;
|
||||
|
||||
case Terminal::FPR:
|
||||
HighlightCurToken(HighlightFormat::GPR);
|
||||
break;
|
||||
|
||||
case Terminal::SPR:
|
||||
HighlightCurToken(HighlightFormat::SPR);
|
||||
break;
|
||||
|
||||
case Terminal::CRField:
|
||||
HighlightCurToken(HighlightFormat::CRField);
|
||||
break;
|
||||
|
||||
case Terminal::Lt:
|
||||
case Terminal::Gt:
|
||||
case Terminal::Eq:
|
||||
case Terminal::So:
|
||||
HighlightCurToken(HighlightFormat::CRFlag);
|
||||
break;
|
||||
|
||||
case Terminal::Str:
|
||||
HighlightCurToken(HighlightFormat::Str);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnHiaddr(std::string_view) override
|
||||
{
|
||||
HighlightCurToken(HighlightFormat::Symbol);
|
||||
auto&& [ha_pos, ha_tok] = m_owner->lexer.LookaheadTagRef(2);
|
||||
m_formatting.emplace_back(static_cast<int>(ha_pos.col),
|
||||
static_cast<int>(ha_tok.token_val.length()), HighlightFormat::HaLa);
|
||||
}
|
||||
|
||||
void OnLoaddr(std::string_view id) override { OnHiaddr(id); }
|
||||
|
||||
void OnOpenParen(ParenType type) override
|
||||
{
|
||||
m_paren_stack.push_back(static_cast<int>(m_owner->lexer.ColNumber()));
|
||||
}
|
||||
|
||||
void OnCloseParen(ParenType type) override
|
||||
{
|
||||
if (m_paren_stack.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_matched_parens.emplace_back(m_paren_stack.back(),
|
||||
static_cast<int>(m_owner->lexer.ColNumber()));
|
||||
m_paren_stack.pop_back();
|
||||
}
|
||||
|
||||
void OnError() override
|
||||
{
|
||||
m_formatting.emplace_back(static_cast<int>(m_owner->error->col),
|
||||
static_cast<int>(m_owner->error->len), HighlightFormat::Error);
|
||||
}
|
||||
|
||||
void OnLabelDecl(std::string_view name) override
|
||||
{
|
||||
const int len = static_cast<int>(m_owner->lexer.LookaheadRef().token_val.length());
|
||||
const int off = static_cast<int>(m_owner->lexer.ColNumber());
|
||||
m_formatting.emplace_back(len, off, HighlightFormat::Symbol);
|
||||
}
|
||||
|
||||
void OnVarDecl(std::string_view name) override { OnLabelDecl(name); }
|
||||
|
||||
private:
|
||||
std::vector<int> m_paren_stack;
|
||||
std::vector<std::pair<int, int>> m_matched_parens;
|
||||
std::vector<std::tuple<int, int, HighlightFormat>> m_formatting;
|
||||
|
||||
void HighlightCurToken(HighlightFormat format)
|
||||
{
|
||||
const int len = static_cast<int>(m_owner->lexer.LookaheadRef().token_val.length());
|
||||
const int off = static_cast<int>(m_owner->lexer.ColNumber());
|
||||
m_formatting.emplace_back(off, len, format);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void GekkoSyntaxHighlight::highlightBlock(const QString& text)
|
||||
{
|
||||
BlockInfo* info = static_cast<BlockInfo*>(currentBlockUserData());
|
||||
if (info == nullptr)
|
||||
{
|
||||
info = new BlockInfo;
|
||||
setCurrentBlockUserData(info);
|
||||
}
|
||||
|
||||
qsizetype comment_idx = text.indexOf(QLatin1Char('#'));
|
||||
if (comment_idx != -1)
|
||||
{
|
||||
HighlightSubstr(comment_idx, text.length() - comment_idx, HighlightFormat::Comment);
|
||||
}
|
||||
|
||||
if (m_mode == 0)
|
||||
{
|
||||
HighlightParsePlugin plugin;
|
||||
ParseWithPlugin(&plugin, text.toStdString());
|
||||
|
||||
info->block_format = plugin.MoveFormatting();
|
||||
info->parens = plugin.MoveParens();
|
||||
info->error = std::move(plugin.Error());
|
||||
info->error_at_eol = info->error && info->error->len == 0;
|
||||
}
|
||||
else if (m_mode == 1)
|
||||
{
|
||||
auto paren_it = std::find_if(info->parens.begin(), info->parens.end(),
|
||||
[this](const std::pair<int, int>& p) {
|
||||
return p.first == m_cursor_loc || p.second == m_cursor_loc;
|
||||
});
|
||||
if (paren_it != info->parens.end())
|
||||
{
|
||||
HighlightSubstr(paren_it->first, 1, HighlightFormat::Paren);
|
||||
HighlightSubstr(paren_it->second, 1, HighlightFormat::Paren);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto&& [off, len, format] : info->block_format)
|
||||
{
|
||||
HighlightSubstr(off, len, format);
|
||||
}
|
||||
}
|
||||
|
||||
GekkoSyntaxHighlight::GekkoSyntaxHighlight(QTextDocument* document, QTextCharFormat base_format,
|
||||
bool dark_scheme)
|
||||
: QSyntaxHighlighter(document), m_base_format(base_format)
|
||||
{
|
||||
QPalette base_scheme;
|
||||
m_theme_idx = dark_scheme ? 1 : 0;
|
||||
}
|
||||
|
||||
void GekkoSyntaxHighlight::HighlightSubstr(int start, int len, HighlightFormat format)
|
||||
{
|
||||
QTextCharFormat hl_format = m_base_format;
|
||||
const QColor DIRECTIVE_COLOR[2] = {QColor(0x9d, 0x00, 0x06),
|
||||
QColor(0xfb, 0x49, 0x34)}; // Gruvbox darkred
|
||||
const QColor MNEMONIC_COLOR[2] = {QColor(0x79, 0x74, 0x0e),
|
||||
QColor(0xb8, 0xbb, 0x26)}; // Gruvbox darkgreen
|
||||
const QColor IMM_COLOR[2] = {QColor(0xb5, 0x76, 0x14),
|
||||
QColor(0xfa, 0xbd, 0x2f)}; // Gruvbox darkyellow
|
||||
const QColor BUILTIN_COLOR[2] = {QColor(0x07, 0x66, 0x78),
|
||||
QColor(0x83, 0xa5, 0x98)}; // Gruvbox darkblue
|
||||
const QColor HA_LA_COLOR[2] = {QColor(0xaf, 0x3a, 0x03),
|
||||
QColor(0xfe, 0x80, 0x19)}; // Gruvbox darkorange
|
||||
const QColor HOVER_BG_COLOR[2] = {QColor(0xd5, 0xc4, 0xa1),
|
||||
QColor(0x50, 0x49, 0x45)}; // Gruvbox bg2
|
||||
const QColor STRING_COLOR[2] = {QColor(0x98, 0x97, 0x1a),
|
||||
QColor(0x98, 0x97, 0x1a)}; // Gruvbox green
|
||||
const QColor COMMENT_COLOR[2] = {QColor(0x68, 0x9d, 0x6a),
|
||||
QColor(0x68, 0x9d, 0x6a)}; // Gruvbox aqua
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case HighlightFormat::Directive:
|
||||
hl_format.setForeground(DIRECTIVE_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::Mnemonic:
|
||||
hl_format.setForeground(MNEMONIC_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::Symbol:
|
||||
break;
|
||||
case HighlightFormat::Immediate:
|
||||
hl_format.setForeground(IMM_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::GPR:
|
||||
hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::FPR:
|
||||
hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::SPR:
|
||||
hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::CRField:
|
||||
hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::CRFlag:
|
||||
hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::Str:
|
||||
hl_format.setForeground(STRING_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::HaLa:
|
||||
hl_format.setForeground(HA_LA_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::Paren:
|
||||
hl_format.setBackground(HOVER_BG_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::Default:
|
||||
hl_format.clearForeground();
|
||||
hl_format.clearBackground();
|
||||
break;
|
||||
case HighlightFormat::Comment:
|
||||
hl_format.setForeground(COMMENT_COLOR[m_theme_idx]);
|
||||
break;
|
||||
case HighlightFormat::Error:
|
||||
hl_format.setUnderlineColor(Qt::red);
|
||||
hl_format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
|
||||
break;
|
||||
}
|
||||
|
||||
setFormat(start, len, hl_format);
|
||||
}
|
Reference in New Issue
Block a user