// Copyright 2023 xensik. All rights reserved. // // Use of this source code is governed by a GNU GPLv3 license // that can be found in the LICENSE file. #include "xsk/stdinc.hpp" #include "xsk/utils/string.hpp" #include "xsk/gsc/source.hpp" #include "xsk/gsc/context.hpp" #include "xsk/gsc/preprocessor.hpp" #include "xsk/gsc/parser.hpp" namespace xsk::gsc { source::source(context* ctx) : ctx_{ ctx }, indent_{ 0 } { } auto source::parse_assembly(buffer const& data) -> assembly::ptr { return parse_assembly(data.data, data.size); } auto source::parse_assembly(std::vector const& data) -> assembly::ptr { return parse_assembly(data.data(), data.size()); } auto source::parse_assembly(u8 const* data, usize size) -> assembly::ptr { auto buffer = std::vector{}; buffer.resize(size); std::memcpy(buffer.data(), data, buffer.size()); auto lines = utils::string::clean_buffer_lines(buffer); auto assembly = assembly::make(); auto func = function::ptr{ nullptr }; u32 index = 1; u16 switchnum = 0; for (auto& line : lines) { if (line == "" || line.substr(0, 2) == "//") { continue; } else if (line.substr(0, 4) == "sub:") { func = function::make(); func->index = index; func->name = line.substr(4); func->id = ctx_->token_id(func->name); } else if (line.substr(0, 4) == "end:") { if (func != nullptr) { func->size = index - func->index; assembly->functions.push_back(std::move(func)); } } else if (line.substr(0, 4) == "loc_") { func->labels[index] = line; } else { auto opdata = utils::string::parse_code(line); if (switchnum) { if (opdata[0] == "case" || opdata[0] == "default") { for (auto& entry : opdata) { func->instructions.back()->data.push_back(entry); } switchnum--; continue; } throw asm_error("invalid instruction inside endswitch \""s + line + "\""); } else { auto inst = instruction::make(); inst->index = index; inst->opcode = ctx_->opcode_enum(opdata[0]); inst->size = ctx_->opcode_size(inst->opcode); opdata.erase(opdata.begin()); inst->data = std::move(opdata); switch (inst->opcode) { case opcode::OP_GetVector: { if (ctx_->endian() == endian::big) { auto base = inst->index + 1; auto algn = (base + 3) & ~3; inst->size += (algn - base); } break; } case opcode::OP_GetLocalFunction: case opcode::OP_ScriptLocalFunctionCall: case opcode::OP_ScriptLocalFunctionCall2: case opcode::OP_ScriptLocalMethodCall: case opcode::OP_ScriptLocalThreadCall: case opcode::OP_ScriptLocalChildThreadCall: case opcode::OP_ScriptLocalMethodThreadCall: case opcode::OP_ScriptLocalMethodChildThreadCall: inst->data[0] = inst->data[0].substr(4); break; case opcode::OP_endswitch: switchnum = static_cast(std::stoi(inst->data[0])); inst->size += 7 * switchnum; break; default: break; } index += inst->size; func->instructions.push_back(std::move(inst)); } } } return assembly; } auto source::parse_program(std::string const& name, buffer const& data) -> program::ptr { return parse_program(name, data.data, data.size); } auto source::parse_program(std::string const& name, std::vector const& data) -> program::ptr { return parse_program(name, data.data(), data.size()); } auto source::parse_program(std::string const& name, u8 const* data, usize size) -> program::ptr { auto res = program::ptr{ nullptr }; auto ppr = preprocessor{ ctx_, name, reinterpret_cast(data), size }; auto psr = parser{ ctx_, ppr, res, 0 }; if (!psr.parse() && res != nullptr) return res; throw error{ fmt::format("an unknown error ocurred while parsing script {}", name) }; } auto source::dump(assembly const& data) -> std::vector { buf_ = std::vector{}; buf_.reserve(0x10000); fmt::format_to(std::back_inserter(buf_), "// {} GSC ASSEMBLY\n", ctx_->engine_name()); fmt::format_to(std::back_inserter(buf_), "// Generated by https://github.com/xensik/gsc-tool\n"); dump_assembly(data); return std::move(buf_); } auto source::dump(program const& data) -> std::vector { buf_ = std::vector{}; buf_.reserve(0x10000); fmt::format_to(std::back_inserter(buf_), "// {} GSC SOURCE\n", ctx_->engine_name()); fmt::format_to(std::back_inserter(buf_), "// Generated by https://github.com/xensik/gsc-tool\n"); dump_program(data); return std::move(buf_); } auto source::dump_assembly(assembly const& data) -> void { for (auto const& func : data.functions) { dump_function(*func); } } auto source::dump_function(function const& func) -> void { fmt::format_to(std::back_inserter(buf_), "\nsub:{}\n", func.name); for (auto const& inst : func.instructions) { auto const itr = func.labels.find(inst->index); if (itr != func.labels.end()) { fmt::format_to(std::back_inserter(buf_), "\t{}\n", itr->second); } dump_instruction(*inst); } fmt::format_to(std::back_inserter(buf_), "end:{}\n", func.name); } auto source::dump_instruction(instruction const& inst) -> void { fmt::format_to(std::back_inserter(buf_), "\t\t{}", ctx_->opcode_name(inst.opcode)); switch (inst.opcode) { case opcode::OP_GetString: case opcode::OP_GetIString: case opcode::OP_GetAnimTree: fmt::format_to(std::back_inserter(buf_), " \"{}\"", inst.data[0]); break; case opcode::OP_GetAnimation: fmt::format_to(std::back_inserter(buf_), " \"{}\" \"{}\"", inst.data[0], inst.data[1]); break; case opcode::OP_GetLocalFunction: case opcode::OP_ScriptLocalFunctionCall: case opcode::OP_ScriptLocalFunctionCall2: case opcode::OP_ScriptLocalMethodCall: fmt::format_to(std::back_inserter(buf_), " {}", inst.data[0]); break; case opcode::OP_ScriptLocalThreadCall: case opcode::OP_ScriptLocalChildThreadCall: case opcode::OP_ScriptLocalMethodThreadCall: case opcode::OP_ScriptLocalMethodChildThreadCall: fmt::format_to(std::back_inserter(buf_), " {} {}\n", inst.data[0], inst.data[1]); break; case opcode::OP_endswitch: { auto count = static_cast(std::stoul(inst.data[0])); auto type = static_cast(std::stoul(inst.data.back())); auto index = 1; fmt::format_to(std::back_inserter(buf_), " {}\n", count); for (auto i = 0u; i < count; i++) { if (inst.data[index] == "case") { if (ctx_->engine() == engine::iw9) { type = static_cast(std::stoul(inst.data[index + 1])); auto data = (type == switch_type::integer) ? fmt::format("{}", inst.data[index + 2]) : fmt::format("\"{}\"", inst.data[index + 2]); fmt::format_to(std::back_inserter(buf_), "\t\t\t{} {} {}", inst.data[index], data, inst.data[index + 3]); index += 4; } else { auto data = (type == switch_type::integer) ? fmt::format("{}", inst.data[index + 1]) : fmt::format("\"{}\"", inst.data[index + 1]); fmt::format_to(std::back_inserter(buf_), "\t\t\t{} {} {}", inst.data[index], data, inst.data[index + 2]); index += 3; } } else if (inst.data[index] == "default") { fmt::format_to(std::back_inserter(buf_), "\t\t\t{} {}", inst.data[index], inst.data[index + 1]); index += 2; } if (i != count - 1) { fmt::format_to(std::back_inserter(buf_), "\n"); } } break; } default: for (auto const& entry : inst.data) { fmt::format_to(std::back_inserter(buf_), " {}", entry); } break; } fmt::format_to(std::back_inserter(buf_), "\n"); } auto source::dump_program(program const& data) -> void { for (auto const& inc : data.includes) { dump_include(*inc); } for (auto const& dec : data.declarations) { fmt::format_to(std::back_inserter(buf_), "\n"); dump_decl(*dec); } } auto source::dump_include(include const& inc) -> void { fmt::format_to(std::back_inserter(buf_), "#include "); dump_expr_path(*inc.path); fmt::format_to(std::back_inserter(buf_), ";\n"); } auto source::dump_decl(decl const& dec) -> void { switch (dec.kind()) { case node::decl_dev_begin: dump_decl_dev_begin(dec.as()); break; case node::decl_dev_end: dump_decl_dev_end(dec.as()); break; case node::decl_usingtree: dump_decl_usingtree(dec.as()); break; case node::decl_constant: dump_decl_constant(dec.as()); break; case node::decl_function: dump_decl_function(dec.as()); break; case node::decl_empty: dump_decl_empty(dec.as()); break; default: break; } } auto source::dump_decl_dev_begin(decl_dev_begin const&) -> void { fmt::format_to(std::back_inserter(buf_), "/#"); } auto source::dump_decl_dev_end(decl_dev_end const&) -> void { fmt::format_to(std::back_inserter(buf_), "#/"); } auto source::dump_decl_usingtree(decl_usingtree const& dec) -> void { fmt::format_to(std::back_inserter(buf_), "#using_animtree("); dump_expr_string(*dec.name); fmt::format_to(std::back_inserter(buf_), ");\n"); } auto source::dump_decl_constant(decl_constant const& dec) -> void { dump_expr_identifier(*dec.name); fmt::format_to(std::back_inserter(buf_), " = "); dump_expr(*dec.value); fmt::format_to(std::back_inserter(buf_), ";\n"); } auto source::dump_decl_function(decl_function const& dec) -> void { indent_ = 0; dump_expr_identifier(*dec.name); fmt::format_to(std::back_inserter(buf_), "("); dump_expr_parameters(*dec.params); fmt::format_to(std::back_inserter(buf_), ")\n"); dump_stmt_comp(*dec.body); fmt::format_to(std::back_inserter(buf_), "\n"); } auto source::dump_decl_empty(decl_empty const&) -> void { fmt::format_to(std::back_inserter(buf_), ";"); } auto source::dump_stmt(stmt const& stm) -> void { switch (stm.kind()) { case node::stmt_list: dump_stmt_list(stm.as()); break; case node::stmt_comp: dump_stmt_comp(stm.as()); break; case node::stmt_dev: dump_stmt_dev(stm.as()); break; case node::stmt_expr: dump_stmt_expr(stm.as()); break; case node::stmt_endon: dump_stmt_endon(stm.as()); break; case node::stmt_notify: dump_stmt_notify(stm.as()); break; case node::stmt_wait: dump_stmt_wait(stm.as()); break; case node::stmt_waittill: dump_stmt_waittill(stm.as()); break; case node::stmt_waittillmatch: dump_stmt_waittillmatch(stm.as()); break; case node::stmt_waittillframeend: dump_stmt_waittillframeend(stm.as()); break; case node::stmt_waitframe: dump_stmt_waitframe(stm.as()); break; case node::stmt_if: dump_stmt_if(stm.as()); break; case node::stmt_ifelse: dump_stmt_ifelse(stm.as()); break; case node::stmt_while: dump_stmt_while(stm.as()); break; case node::stmt_dowhile: dump_stmt_dowhile(stm.as()); break; case node::stmt_for: dump_stmt_for(stm.as()); break; case node::stmt_foreach: dump_stmt_foreach(stm.as()); break; case node::stmt_switch: dump_stmt_switch(stm.as()); break; case node::stmt_case: dump_stmt_case(stm.as()); break; case node::stmt_default: dump_stmt_default(stm.as()); break; case node::stmt_break: dump_stmt_break(stm.as()); break; case node::stmt_continue: dump_stmt_continue(stm.as()); break; case node::stmt_return: dump_stmt_return(stm.as()); break; case node::stmt_breakpoint: dump_stmt_breakpoint(stm.as()); break; case node::stmt_prof_begin: dump_stmt_prof_begin(stm.as()); break; case node::stmt_prof_end: dump_stmt_prof_end(stm.as()); break; case node::stmt_assert: dump_stmt_assert(stm.as()); break; case node::stmt_assertex: dump_stmt_assertex(stm.as()); break; case node::stmt_assertmsg: dump_stmt_assertmsg(stm.as()); break; case node::stmt_create: dump_stmt_create(stm.as()); break; case node::stmt_remove: dump_stmt_remove(stm.as()); break; case node::stmt_clear: dump_stmt_clear(stm.as()); break; case node::stmt_jmp: dump_stmt_jmp(stm.as()); break; case node::stmt_jmp_back: dump_stmt_jmp_back(stm.as()); break; case node::stmt_jmp_cond: dump_stmt_jmp_cond(stm.as()); break; case node::stmt_jmp_switch: dump_stmt_jmp_switch(stm.as()); break; case node::stmt_jmp_endswitch: dump_stmt_jmp_endswitch(stm.as()); break; default: break; } } auto source::dump_stmt_empty(stmt_empty const&) -> void { fmt::format_to(std::back_inserter(buf_), ";"); } auto source::dump_stmt_list(stmt_list const& stm) -> void { auto last_special = false; indent_ += 4; for (auto const& entry : stm.list) { if ((&entry != &stm.list.front() && entry->is_special_stmt()) || last_special) fmt::format_to(std::back_inserter(buf_), "\n"); if (entry->is()) { dump_stmt(*entry); } else { fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*entry); } if (&entry != &stm.list.back()) fmt::format_to(std::back_inserter(buf_), "\n"); if (entry->is_special_stmt()) last_special = true; else last_special = false; } indent_ -= 4; } auto source::dump_stmt_comp(stmt_comp const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "{: >{}}\n", "{", indent_ + 1); dump_stmt_list(*stm.block); fmt::format_to(std::back_inserter(buf_), "\n{: >{}}", "}", indent_ + 1); } auto source::dump_stmt_dev(stmt_dev const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "/#\n"); dump_stmt_list(*stm.block); fmt::format_to(std::back_inserter(buf_), "\n#/"); } auto source::dump_stmt_expr(stmt_expr const& stm) -> void { switch (stm.value->kind()) { case node::expr_increment: dump_expr_increment(stm.value->as()); break; case node::expr_decrement: dump_expr_decrement(stm.value->as()); break; case node::expr_assign: dump_expr_assign(stm.value->as()); break; case node::expr_call: dump_expr_call(stm.value->as()); break; case node::expr_method: dump_expr_method(stm.value->as()); break; case node::expr_empty: default: break; } fmt::format_to(std::back_inserter(buf_), ";"); } auto source::dump_stmt_endon(stmt_endon const& stm) -> void { dump_expr(*stm.obj); fmt::format_to(std::back_inserter(buf_), " endon( "); dump_expr(*stm.event); fmt::format_to(std::back_inserter(buf_), " );"); } auto source::dump_stmt_notify(stmt_notify const& stm) -> void { dump_expr(*stm.obj); fmt::format_to(std::back_inserter(buf_), " notify( "); dump_expr(*stm.event); if (stm.args->list.size() > 0) { fmt::format_to(std::back_inserter(buf_), ","); dump_expr_arguments(*stm.args); } else { fmt::format_to(std::back_inserter(buf_), " "); } fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_wait(stmt_wait const& stm) -> void { if (stm.time->is() || stm.time->is()) { fmt::format_to(std::back_inserter(buf_), "wait "); dump_expr(*stm.time); fmt::format_to(std::back_inserter(buf_), ";"); } else if (stm.time->is()) { fmt::format_to(std::back_inserter(buf_), "wait"); dump_expr(*stm.time); fmt::format_to(std::back_inserter(buf_), ";"); } else { fmt::format_to(std::back_inserter(buf_), "wait( "); dump_expr(*stm.time); fmt::format_to(std::back_inserter(buf_), " );"); } } auto source::dump_stmt_waittill(stmt_waittill const& stm) -> void { dump_expr(*stm.obj); fmt::format_to(std::back_inserter(buf_), " waittill( "); dump_expr(*stm.event); if (stm.args->list.size() > 0) { fmt::format_to(std::back_inserter(buf_), ","); dump_expr_arguments(*stm.args); } else { fmt::format_to(std::back_inserter(buf_), " "); } fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_waittillmatch(stmt_waittillmatch const& stm) -> void { dump_expr(*stm.obj); fmt::format_to(std::back_inserter(buf_), " waittillmatch( "); dump_expr(*stm.event); if (stm.args->list.size() > 0) { fmt::format_to(std::back_inserter(buf_), ","); dump_expr_arguments(*stm.args); } else { fmt::format_to(std::back_inserter(buf_), " "); } fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_waittillframeend(stmt_waittillframeend const&) -> void { fmt::format_to(std::back_inserter(buf_), "waittillframeend;"); } auto source::dump_stmt_waitframe(stmt_waitframe const&) -> void { fmt::format_to(std::back_inserter(buf_), "waitframe();"); } auto source::dump_stmt_if(stmt_if const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "if ( "); dump_expr(*stm.test); fmt::format_to(std::back_inserter(buf_), " )\n"); if (stm.body->is()) { dump_stmt(*stm.body); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*stm.body); indent_ -= 4; } } auto source::dump_stmt_ifelse(stmt_ifelse const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "if ( "); dump_expr(*stm.test); fmt::format_to(std::back_inserter(buf_), " )\n"); if (stm.stmt_if->is()) { dump_stmt(*stm.stmt_if); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*stm.stmt_if); indent_ -= 4; } fmt::format_to(std::back_inserter(buf_), "\n{: >{}}else", "", indent_); if (stm.stmt_else->is()) { fmt::format_to(std::back_inserter(buf_), "\n"); dump_stmt(*stm.stmt_else); } else { if (stm.stmt_else->is() || stm.stmt_else ->is()) { fmt::format_to(std::back_inserter(buf_), " "); dump_stmt(*stm.stmt_else); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "\n{: >{}}", "", indent_); dump_stmt(*stm.stmt_else); indent_ -= 4; } } } auto source::dump_stmt_while(stmt_while const& stm) -> void { if (stm.test->is()) { fmt::format_to(std::back_inserter(buf_), "while ( true )\n"); } else { fmt::format_to(std::back_inserter(buf_), "while ( "); dump_expr(*stm.test); fmt::format_to(std::back_inserter(buf_), " )\n"); } if (stm.body->is()) { dump_stmt(*stm.body); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*stm.body); indent_ -= 4; } } auto source::dump_stmt_dowhile(stmt_dowhile const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "do\n"); if (stm.body->is()) { dump_stmt(*stm.body); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*stm.body); indent_ -= 4; } if (stm.test->is()) { fmt::format_to(std::back_inserter(buf_), "\n{: >{}}while ( true )", "", indent_); } else { fmt::format_to(std::back_inserter(buf_), "\n{: >{}}while (", "", indent_); dump_expr(*stm.test); fmt::format_to(std::back_inserter(buf_), " );"); } } auto source::dump_stmt_for(stmt_for const& stm) -> void { if (stm.test->is()) { fmt::format_to(std::back_inserter(buf_), "for (;;)\n"); } else { fmt::format_to(std::back_inserter(buf_), "for ( "); dump_stmt(*stm.init); buf_.pop_back(); fmt::format_to(std::back_inserter(buf_), "; "); dump_expr(*stm.test); fmt::format_to(std::back_inserter(buf_), "; "); dump_stmt(*stm.iter); buf_.pop_back(); fmt::format_to(std::back_inserter(buf_), " )\n"); } if (stm.body->is()) { dump_stmt(*stm.body); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*stm.body); indent_ -= 4; } } auto source::dump_stmt_foreach(stmt_foreach const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "foreach ( "); if (stm.use_key) { dump_expr((ctx_->props() & props::foreach) ? *stm.index : *stm.key); fmt::format_to(std::back_inserter(buf_), ", "); } dump_expr(*stm.value); fmt::format_to(std::back_inserter(buf_), " in "); dump_expr(*stm.container); fmt::format_to(std::back_inserter(buf_), " )\n"); if (stm.body->is()) { dump_stmt(*stm.body); } else { indent_ += 4; fmt::format_to(std::back_inserter(buf_), "{: >{}}", "", indent_); dump_stmt(*stm.body); indent_ -= 4; } } auto source::dump_stmt_switch(stmt_switch const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "switch ( "); dump_expr(*stm.test); fmt::format_to(std::back_inserter(buf_), " )\n"); dump_stmt_comp(*stm.body); } auto source::dump_stmt_case(stmt_case const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "case "); dump_expr(*stm.value); fmt::format_to(std::back_inserter(buf_), ":"); if (stm.body != nullptr && stm.body->list.size() > 0) { fmt::format_to(std::back_inserter(buf_), "\n"); dump_stmt_list(*stm.body); } } auto source::dump_stmt_default(stmt_default const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "default:"); if (stm.body != nullptr && stm.body->list.size() > 0) { fmt::format_to(std::back_inserter(buf_), "\n"); dump_stmt_list(*stm.body); } } auto source::dump_stmt_break(stmt_break const&) -> void { fmt::format_to(std::back_inserter(buf_), "break;"); } auto source::dump_stmt_continue(stmt_continue const&) -> void { fmt::format_to(std::back_inserter(buf_), "continue;"); } auto source::dump_stmt_return(stmt_return const& stm) -> void { if (stm.value->is()) { fmt::format_to(std::back_inserter(buf_), "return;"); } else { fmt::format_to(std::back_inserter(buf_), "return "); dump_expr(*stm.value); fmt::format_to(std::back_inserter(buf_), ";"); } } auto source::dump_stmt_breakpoint(stmt_breakpoint const&) -> void { fmt::format_to(std::back_inserter(buf_), "breakpoint;"); } auto source::dump_stmt_prof_begin(stmt_prof_begin const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "prof_begin("); dump_expr_arguments(*stm.args); fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_prof_end(stmt_prof_end const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "prof_end("); dump_expr_arguments(*stm.args); fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_assert(stmt_assert const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "assert("); dump_expr_arguments(*stm.args); fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_assertex(stmt_assertex const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "assertex("); dump_expr_arguments(*stm.args); fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_assertmsg(stmt_assertmsg const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "assertmsg("); dump_expr_arguments(*stm.args); fmt::format_to(std::back_inserter(buf_), ");"); } auto source::dump_stmt_create(stmt_create const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_var_create( {} )", stm.index); } auto source::dump_stmt_remove(stmt_remove const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_var_remove( {} )", stm.index); } auto source::dump_stmt_clear(stmt_clear const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_var_clear( {} )", stm.index); } auto source::dump_stmt_jmp(stmt_jmp const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_jmp( {} )", stm.value); } auto source::dump_stmt_jmp_back(stmt_jmp_back const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_jmp_back( {} )", stm.value); } auto source::dump_stmt_jmp_cond(stmt_jmp_cond const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_jmp_cond( {} )", stm.value); } auto source::dump_stmt_jmp_true(stmt_jmp_true const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_jmp_expr_true( {} )", stm.value); } auto source::dump_stmt_jmp_false(stmt_jmp_false const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_jmp_expr_false( {} )", stm.value); } auto source::dump_stmt_jmp_switch(stmt_jmp_switch const& stm) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_switch( {} )", stm.value); } auto source::dump_stmt_jmp_endswitch(stmt_jmp_endswitch const&) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_endswitch()"); } auto source::dump_expr(expr const& exp) -> void { switch (exp.kind()) { case node::expr_ternary: dump_expr_ternary(exp.as()); break; case node::expr_binary: dump_expr_binary(exp.as()); break; case node::expr_complement: dump_expr_complement(exp.as()); break; case node::expr_negate: dump_expr_negate(exp.as()); break; case node::expr_not: dump_expr_not(exp.as()); break; case node::expr_call: dump_expr_call(exp.as()); break; case node::expr_method: dump_expr_method(exp.as()); break; case node::expr_function: dump_expr_function(exp.as()); break; case node::expr_pointer: dump_expr_pointer(exp.as()); break; case node::expr_add_array: dump_expr_add_array(exp.as()); break; case node::expr_parameters: dump_expr_parameters(exp.as()); break; case node::expr_arguments: dump_expr_arguments(exp.as()); break; case node::expr_isdefined: dump_expr_isdefined(exp.as()); break; case node::expr_istrue: dump_expr_istrue(exp.as()); break; case node::expr_reference: dump_expr_reference(exp.as()); break; case node::expr_tuple: dump_expr_tuple(exp.as()); break; case node::expr_array: dump_expr_array(exp.as()); break; case node::expr_field: dump_expr_field(exp.as()); break; case node::expr_size: dump_expr_size(exp.as()); break; case node::expr_paren: dump_expr_paren(exp.as()); break; case node::expr_thisthread: dump_expr_thisthread(exp.as()); break; case node::expr_empty_array: dump_expr_empty_array(exp.as()); break; case node::expr_undefined: dump_expr_undefined(exp.as()); break; case node::expr_game: dump_expr_game(exp.as()); break; case node::expr_self: dump_expr_self(exp.as()); break; case node::expr_anim: dump_expr_anim(exp.as()); break; case node::expr_level: dump_expr_level(exp.as()); break; case node::expr_animation: dump_expr_animation(exp.as()); break; case node::expr_animtree: dump_expr_animtree(exp.as()); break; case node::expr_identifier: dump_expr_identifier(exp.as()); break; case node::expr_path: dump_expr_path(exp.as()); break; case node::expr_istring: dump_expr_istring(exp.as()); break; case node::expr_string: dump_expr_string(exp.as()); break; case node::expr_vector: dump_expr_vector(exp.as()); break; case node::expr_float: dump_expr_float(exp.as()); break; case node::expr_integer: dump_expr_integer(exp.as()); break; case node::expr_false: dump_expr_false(exp.as()); break; case node::expr_true: dump_expr_true(exp.as()); break; case node::expr_var_create: dump_expr_var_create(exp.as()); break; case node::expr_var_access: dump_expr_var_access(exp.as()); break; default: break; } } auto source::dump_expr_increment(expr_increment const& exp) -> void { if (exp.prefix) { fmt::format_to(std::back_inserter(buf_), "++"); dump_expr(*exp.lvalue); } else { dump_expr(*exp.lvalue); fmt::format_to(std::back_inserter(buf_), "++"); } } auto source::dump_expr_decrement(expr_decrement const& exp) -> void { if (exp.prefix) { fmt::format_to(std::back_inserter(buf_), "--"); dump_expr(*exp.lvalue); } else { dump_expr(*exp.lvalue); fmt::format_to(std::back_inserter(buf_), "--"); } } auto source::dump_expr_assign(expr_assign const& exp) -> void { dump_expr(*exp.lvalue); switch (exp.oper) { case expr_assign::op::eq: fmt::format_to(std::back_inserter(buf_), " = "); break; case expr_assign::op::add: fmt::format_to(std::back_inserter(buf_), " += "); break; case expr_assign::op::sub: fmt::format_to(std::back_inserter(buf_), " -= "); break; case expr_assign::op::mul: fmt::format_to(std::back_inserter(buf_), " *= "); break; case expr_assign::op::div: fmt::format_to(std::back_inserter(buf_), " /= "); break; case expr_assign::op::mod: fmt::format_to(std::back_inserter(buf_), " %= "); break; case expr_assign::op::shl: fmt::format_to(std::back_inserter(buf_), " <<= "); break; case expr_assign::op::shr: fmt::format_to(std::back_inserter(buf_), " >>= "); break; case expr_assign::op::bwor: fmt::format_to(std::back_inserter(buf_), " |= "); break; case expr_assign::op::bwand: fmt::format_to(std::back_inserter(buf_), " &= "); break; case expr_assign::op::bwexor: fmt::format_to(std::back_inserter(buf_), " ^= "); break; } dump_expr(*exp.rvalue); } auto source::dump_expr_ternary(expr_ternary const& exp) -> void { dump_expr(*exp.test); fmt::format_to(std::back_inserter(buf_), " ? "); dump_expr(*exp.true_expr); fmt::format_to(std::back_inserter(buf_), " : "); dump_expr(*exp.false_expr); } auto source::dump_expr_binary(expr_binary const& exp) -> void { dump_expr(*exp.lvalue); switch (exp.oper) { case expr_binary::op::bool_or: fmt::format_to(std::back_inserter(buf_), " || "); break; case expr_binary::op::bool_and: fmt::format_to(std::back_inserter(buf_), " && "); break; case expr_binary::op::eq: fmt::format_to(std::back_inserter(buf_), " == "); break; case expr_binary::op::ne: fmt::format_to(std::back_inserter(buf_), " != "); break; case expr_binary::op::le: fmt::format_to(std::back_inserter(buf_), " <= "); break; case expr_binary::op::ge: fmt::format_to(std::back_inserter(buf_), " >= "); break; case expr_binary::op::lt: fmt::format_to(std::back_inserter(buf_), " < "); break; case expr_binary::op::gt: fmt::format_to(std::back_inserter(buf_), " > "); break; case expr_binary::op::add: fmt::format_to(std::back_inserter(buf_), " + "); break; case expr_binary::op::sub: fmt::format_to(std::back_inserter(buf_), " - "); break; case expr_binary::op::mul: fmt::format_to(std::back_inserter(buf_), " * "); break; case expr_binary::op::div: fmt::format_to(std::back_inserter(buf_), " / "); break; case expr_binary::op::mod: fmt::format_to(std::back_inserter(buf_), " % "); break; case expr_binary::op::shl: fmt::format_to(std::back_inserter(buf_), " << "); break; case expr_binary::op::shr: fmt::format_to(std::back_inserter(buf_), " >> "); break; case expr_binary::op::bwor: fmt::format_to(std::back_inserter(buf_), " | "); break; case expr_binary::op::bwand: fmt::format_to(std::back_inserter(buf_), " & "); break; case expr_binary::op::bwexor: fmt::format_to(std::back_inserter(buf_), " ^ "); break; } dump_expr(*exp.rvalue); } auto source::dump_expr_not(expr_not const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "!"); dump_expr(*exp.rvalue); } auto source::dump_expr_negate(expr_negate const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "-"); dump_expr(*exp.rvalue); } auto source::dump_expr_complement(expr_complement const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "~"); dump_expr(*exp.rvalue); } auto source::dump_expr_call(expr_call const& exp) -> void { dump_call(*exp.value); } auto source::dump_expr_method(expr_method const& exp) -> void { dump_expr(*exp.obj); fmt::format_to(std::back_inserter(buf_), " "); dump_call(*exp.value); } auto source::dump_call(call const& exp) -> void { switch (exp.kind()) { case node::expr_function: dump_expr_function(exp.as()); break; case node::expr_pointer: dump_expr_pointer(exp.as()); break; default: break; } } auto source::dump_expr_function(expr_function const& exp) -> void { if (exp.mode == call::mode::thread) fmt::format_to(std::back_inserter(buf_), "thread "); else if (exp.mode == call::mode::childthread) fmt::format_to(std::back_inserter(buf_), "childthread "); if (exp.path->value != "") { dump_expr_path(*exp.path); fmt::format_to(std::back_inserter(buf_), "::"); } dump_expr_identifier(*exp.name); fmt::format_to(std::back_inserter(buf_), "("); dump_expr_arguments(*exp.args); fmt::format_to(std::back_inserter(buf_), ")"); } auto source::dump_expr_pointer(expr_pointer const& exp) -> void { if (exp.mode == call::mode::builtin) fmt::format_to(std::back_inserter(buf_), "call "); else if (exp.mode == call::mode::thread) fmt::format_to(std::back_inserter(buf_), "thread "); else if (exp.mode == call::mode::childthread) fmt::format_to(std::back_inserter(buf_), "childthread "); fmt::format_to(std::back_inserter(buf_), "[[ "); dump_expr(*exp.func); fmt::format_to(std::back_inserter(buf_), " ]]("); dump_expr_arguments(*exp.args); fmt::format_to(std::back_inserter(buf_), ")"); } auto source::dump_expr_add_array(expr_add_array const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "["); dump_expr_arguments(*exp.args); fmt::format_to(std::back_inserter(buf_), "]"); } auto source::dump_expr_parameters(expr_parameters const& exp) -> void { for (auto const& entry : exp.list) { fmt::format_to(std::back_inserter(buf_), " "); dump_expr_identifier(*entry); if (&entry != &exp.list.back()) fmt::format_to(std::back_inserter(buf_), ","); else fmt::format_to(std::back_inserter(buf_), " "); } } auto source::dump_expr_arguments(expr_arguments const& exp) -> void { for (auto const& entry : exp.list) { fmt::format_to(std::back_inserter(buf_), " "); dump_expr(*entry); if (&entry != &exp.list.back()) fmt::format_to(std::back_inserter(buf_), ","); else fmt::format_to(std::back_inserter(buf_), " "); } } auto source::dump_expr_isdefined(expr_isdefined const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "isdefined( "); dump_expr(*exp.value); fmt::format_to(std::back_inserter(buf_), " )"); } auto source::dump_expr_istrue(expr_istrue const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "istrue( "); dump_expr(*exp.value); fmt::format_to(std::back_inserter(buf_), " )"); } auto source::dump_expr_reference(expr_reference const& exp) -> void { dump_expr_path(*exp.path); fmt::format_to(std::back_inserter(buf_), "::"); dump_expr_identifier(*exp.name); } auto source::dump_expr_tuple(expr_tuple const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "["); for (auto const& entry : exp.list) { dump_expr(*entry); if (&entry != &exp.list.back()) fmt::format_to(std::back_inserter(buf_), ", "); } fmt::format_to(std::back_inserter(buf_), "]"); } auto source::dump_expr_array(expr_array const& exp) -> void { dump_expr(*exp.obj); fmt::format_to(std::back_inserter(buf_), "["); dump_expr(*exp.key); fmt::format_to(std::back_inserter(buf_), "]"); } auto source::dump_expr_field(expr_field const& exp) -> void { dump_expr(*exp.obj); fmt::format_to(std::back_inserter(buf_), "."); dump_expr_identifier(*exp.field); } auto source::dump_expr_size(expr_size const& exp) -> void { dump_expr(*exp.obj); fmt::format_to(std::back_inserter(buf_), ".size"); } auto source::dump_expr_paren(expr_paren const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "( "); dump_expr(*exp.value); fmt::format_to(std::back_inserter(buf_), " )"); } auto source::dump_expr_thisthread(expr_thisthread const&) -> void { fmt::format_to(std::back_inserter(buf_), "thisthread"); } auto source::dump_expr_empty_array(expr_empty_array const&) -> void { fmt::format_to(std::back_inserter(buf_), "[]"); } auto source::dump_expr_undefined(expr_undefined const&) -> void { fmt::format_to(std::back_inserter(buf_), "undefined"); } auto source::dump_expr_game(expr_game const&) -> void { fmt::format_to(std::back_inserter(buf_), "game"); } auto source::dump_expr_self(expr_self const&) -> void { fmt::format_to(std::back_inserter(buf_), "self"); } auto source::dump_expr_anim(expr_anim const&) -> void { fmt::format_to(std::back_inserter(buf_), "anim"); } auto source::dump_expr_level(expr_level const&) -> void { fmt::format_to(std::back_inserter(buf_), "level"); } auto source::dump_expr_animation(expr_animation const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "%{}", exp.value); } auto source::dump_expr_animtree(expr_animtree const&) -> void { fmt::format_to(std::back_inserter(buf_), "#animtree"); } auto source::dump_expr_identifier(expr_identifier const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "{}", exp.value); } auto source::dump_expr_path(expr_path const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "{}", utils::string::backslash(exp.value)); } auto source::dump_expr_istring(expr_istring const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "&{}", utils::string::to_literal(exp.value)); } auto source::dump_expr_string(expr_string const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "{}", utils::string::to_literal(exp.value)); } auto source::dump_expr_vector(expr_vector const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "( "); dump_expr(*exp.x); fmt::format_to(std::back_inserter(buf_), ", "); dump_expr(*exp.y); fmt::format_to(std::back_inserter(buf_), ", "); dump_expr(*exp.z); fmt::format_to(std::back_inserter(buf_), " )"); } auto source::dump_expr_float(expr_float const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "{}", exp.value); } auto source::dump_expr_integer(expr_integer const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "{}", exp.value); } auto source::dump_expr_false(expr_false const&) -> void { fmt::format_to(std::back_inserter(buf_), "false"); } auto source::dump_expr_true(expr_true const&) -> void { fmt::format_to(std::back_inserter(buf_), "true"); } auto source::dump_expr_var_create(expr_var_create const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_var_create( {} )", exp.index); } auto source::dump_expr_var_access(expr_var_access const& exp) -> void { fmt::format_to(std::back_inserter(buf_), "__asm_var_access( {} )", exp.index); } } // namespace xsk::gsc