Update gsc-tool + add gsc error lines

This commit is contained in:
fed 2024-01-17 19:21:57 +01:00
parent dbe995452c
commit d8cf3f53ab
6 changed files with 127 additions and 24 deletions

2
deps/gsc-tool vendored

@ -1 +1 @@
Subproject commit 4806a285b6e6719f5ea968a4199a34ee86eb7cfb Subproject commit 2dbff1a408096e418c5b3eda01bc9a91eee6587b

View File

@ -76,7 +76,7 @@ namespace gsc
{ {
const auto& pos = function.value(); const auto& pos = function.value();
unknown_function_error = std::format( unknown_function_error = std::format(
"while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file "while processing function '{}' in script '{}':\nunknown script '{}'", pos.function, pos.file, scripting::current_file
); );
} }
else else
@ -293,16 +293,21 @@ namespace gsc
} }
} }
std::optional<std::pair<std::string, std::string>> find_function(const char* pos) std::optional<script_info_t> find_function(const char* pos)
{ {
for (const auto& file : scripting::script_function_table_sort) for (const auto& file : scripting::script_function_table_sort)
{ {
const auto first_function = file.second.begin();
for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i) for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i)
{ {
const auto next = std::next(i); const auto next = std::next(i);
if (pos >= i->second && pos < next->second) if (pos >= i->second && pos < next->second)
{ {
return {std::make_pair(i->first, file.first)}; script_info_t info{};
info.function = i->first;
info.file = file.first;
info.script_start = first_function->second;
return {info};
} }
} }
} }

View File

@ -4,5 +4,12 @@ namespace gsc
{ {
extern std::array<const char*, 27> var_typename; extern std::array<const char*, 27> var_typename;
std::optional<std::pair<std::string, std::string>> find_function(const char* pos); struct script_info_t
{
const char* script_start;
std::string file;
std::string function;
};
std::optional<script_info_t> find_function(const char* pos);
} }

View File

@ -130,16 +130,39 @@ namespace gsc
{ {
for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame) for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame)
{ {
const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos; const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos - 1 : frame->fs.pos;
const auto function = find_function(frame->fs.pos); const auto info = find_function(pos);
if (function.has_value()) if (!info.has_value())
{ {
console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), function.value().second.data()); console::warn("\tat unknown location %p\n", pos);
continue;
}
const auto& function = info->function;
const auto& file = info->file;
const auto devmap_opt = get_script_devmap(file);
if (devmap_opt.has_value())
{
const auto& devmap = devmap_opt.value();
const auto rel_pos = static_cast<std::uint32_t>(pos - info->script_start);
const auto& iter = devmap->find(rel_pos);
if (iter != devmap->end())
{
console::warn("\tat function \"%s\" in file \"%s.gsc\" (line %d, column %d)\n",
function.data(), file.data(),
iter->second.line, iter->second.column);
} }
else else
{ {
console::warn("\tat unknown location %p\n", pos); console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.data(), file.data());
}
}
else
{
console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.data(), file.data());
} }
} }
} }

View File

@ -27,7 +27,13 @@ namespace gsc
std::unordered_map<std::string, unsigned int> main_handles; std::unordered_map<std::string, unsigned int> main_handles;
std::unordered_map<std::string, unsigned int> init_handles; std::unordered_map<std::string, unsigned int> init_handles;
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts; struct loaded_script_t
{
game::ScriptFile* ptr;
std::map<std::uint32_t, col_line_t> devmap;
};
std::unordered_map<std::string, loaded_script_t> loaded_scripts;
utils::memory::allocator script_allocator; utils::memory::allocator script_allocator;
struct struct
@ -97,11 +103,44 @@ namespace gsc
return false; return false;
} }
std::map<std::uint32_t, col_line_t> parse_devmap(const xsk::gsc::buffer& devmap)
{
auto devmap_ptr = devmap.data;
const auto read_32 = [&]()
{
const auto val = *reinterpret_cast<const std::uint32_t*>(devmap_ptr);
devmap_ptr += sizeof(std::uint32_t);
return val;
};
const auto read_16 = [&]()
{
const auto val = *reinterpret_cast<const std::uint16_t*>(devmap_ptr);
devmap_ptr += sizeof(std::uint16_t);
return val;
};
std::map<std::uint32_t, col_line_t> pos_map;
const auto devmap_count = read_32();
for (auto i = 0u; i < devmap_count; i++)
{
const auto script_pos = read_32() - 1;
const auto line = read_16();
const auto col = read_16();
pos_map[script_pos] = {line, col};
}
return pos_map;
}
game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name) game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name)
{ {
if (const auto itr = loaded_scripts.find(file_name); itr != loaded_scripts.end()) if (const auto itr = loaded_scripts.find(file_name); itr != loaded_scripts.end())
{ {
return itr->second; return itr->second.ptr;
} }
try try
@ -119,26 +158,29 @@ namespace gsc
data.assign(source_buffer.begin(), source_buffer.end()); data.assign(source_buffer.begin(), source_buffer.end());
const auto assembly_ptr = compiler.compile(real_name, data); const auto assembly_ptr = compiler.compile(real_name, data);
const auto output_script = assembler.assemble(*assembly_ptr); [[maybe_unused]] const auto& [script, stack, devmap] = assembler.assemble(*assembly_ptr);
const auto script_file_ptr = static_cast<game::ScriptFile*>(script_allocator.allocate(sizeof(game::ScriptFile))); const auto script_file_ptr = static_cast<game::ScriptFile*>(script_allocator.allocate(sizeof(game::ScriptFile)));
script_file_ptr->name = file_name; script_file_ptr->name = file_name;
script_file_ptr->len = static_cast<int>(output_script.second.size); script_file_ptr->len = static_cast<int>(stack.size);
script_file_ptr->bytecodeLen = static_cast<int>(output_script.first.size); script_file_ptr->bytecodeLen = static_cast<int>(script.size);
const auto stack_size = static_cast<std::uint32_t>(output_script.second.size + 1); const auto stack_size = static_cast<std::uint32_t>(stack.size + 1);
const auto byte_code_size = static_cast<std::uint32_t>(output_script.first.size + 1); const auto byte_code_size = static_cast<std::uint32_t>(script.size + 1);
script_file_ptr->buffer = static_cast<char*>(script_allocator.allocate(stack_size)); script_file_ptr->buffer = static_cast<char*>(script_allocator.allocate(stack_size));
std::memcpy(const_cast<char*>(script_file_ptr->buffer), output_script.second.data, output_script.second.size); std::memcpy(const_cast<char*>(script_file_ptr->buffer), stack.data, stack.size);
script_file_ptr->bytecode = allocate_buffer(byte_code_size); script_file_ptr->bytecode = allocate_buffer(byte_code_size);
std::memcpy(script_file_ptr->bytecode, output_script.first.data, output_script.first.size); std::memcpy(script_file_ptr->bytecode, script.data, script.size);
script_file_ptr->compressedLen = 0; script_file_ptr->compressedLen = 0;
loaded_scripts[file_name] = script_file_ptr; loaded_script_t loaded_script{};
loaded_script.ptr = script_file_ptr;
loaded_script.devmap = parse_devmap(devmap);
loaded_scripts.insert(std::make_pair(file_name, loaded_script));
return script_file_ptr; return script_file_ptr;
} }
@ -153,7 +195,7 @@ namespace gsc
std::string get_raw_script_file_name(const std::string& name) std::string get_raw_script_file_name(const std::string& name)
{ {
if (name.ends_with(".gsh")) if (name.ends_with(".gsh") || name.ends_with(".gsc"))
{ {
return name; return name;
} }
@ -163,10 +205,17 @@ namespace gsc
std::string get_script_file_name(const std::string& name) std::string get_script_file_name(const std::string& name)
{ {
const auto id = gsc_ctx->token_id(name); std::string script_name = name;
if (script_name.ends_with(".gsc"))
{
const auto dot_idx = script_name.find_last_of('.');
script_name = script_name.substr(0, dot_idx);
}
const auto id = gsc_ctx->token_id(script_name);
if (!id) if (!id)
{ {
return name; return script_name;
} }
return std::to_string(id); return std::to_string(id);
@ -319,7 +368,7 @@ namespace gsc
? xsk::gsc::build::dev ? xsk::gsc::build::dev
: xsk::gsc::build::prod; : xsk::gsc::build::prod;
gsc_ctx->init(comp_mode, [](const std::string& include_name) gsc_ctx->init(comp_mode, [](const xsk::gsc::context* context, const std::string& include_name)
-> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>> -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>>
{ {
const auto real_name = get_raw_script_file_name(include_name); const auto real_name = get_raw_script_file_name(include_name);
@ -388,6 +437,17 @@ namespace gsc
return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile; return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile;
} }
std::optional<std::map<std::uint32_t, col_line_t>*> get_script_devmap(const std::string& name)
{
const auto iter = loaded_scripts.find(name);
if (iter == loaded_scripts.end())
{
return {};
}
return {&iter->second.devmap};
}
class loading final : public component_interface class loading final : public component_interface
{ {
public: public:

View File

@ -5,8 +5,16 @@
namespace gsc namespace gsc
{ {
struct col_line_t
{
std::uint16_t line;
std::uint16_t column;
};
extern std::unique_ptr<xsk::gsc::h2::context> gsc_ctx; extern std::unique_ptr<xsk::gsc::h2::context> gsc_ctx;
extern game::dvar_t* developer_script; extern game::dvar_t* developer_script;
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default); game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default);
std::optional<std::map<std::uint32_t, col_line_t>*> get_script_devmap(const std::string& name);
} }