Skip to content

Commit

Permalink
jup foreach and hashes
Browse files Browse the repository at this point in the history
  • Loading branch information
ate47 committed May 9, 2024
1 parent 09579d2 commit 0cee3ff
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 208 deletions.
2 changes: 1 addition & 1 deletion grammar/gsc.g4
Original file line number Diff line number Diff line change
Expand Up @@ -158,4 +158,4 @@ IDENTIFIER: [a-z_A-Z] ([a-z_A-Z0-9])*;
STRUCT_IDENTIFIER: '#' [a-z_A-Z] ([a-z_A-Z0-9])*;
PATH: [a-z_A-Z0-9\\/]+ ('.gsc' | '.csc')?;
STRING: '"' (~["\\] | ('\\'.))* '"';
HASHSTRING: [#] STRING;
HASHSTRING: ('#' | '@' | 't' | '%') STRING;
328 changes: 164 additions & 164 deletions src/acts/compiler/gscLexer.cpp

Large diffs are not rendered by default.

157 changes: 120 additions & 37 deletions src/acts/compiler/gsc_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,24 @@ class CompileObject {

return true;
}

void AddImport(AscmNodeFunctionCall* funcCall, uint64_t funcNspHash, uint64_t funcHash, size_t paramCount, uint8_t importFlags) {
// link by the game, but we write it for test
Located located{ funcNspHash, funcHash };

auto& impList = imports[located];

auto it = std::find_if(impList.begin(), impList.end(), [importFlags](const auto& e) { return e.flags == importFlags; });

if (it == impList.end()) {
// no equivalent, we need to create our own node
impList.emplace_back(importFlags, (byte)paramCount).nodes.push_back(funcCall);
}
else {
// same local/flags, we can add our node
it->nodes.push_back(funcCall);
}
}
};


Expand Down Expand Up @@ -2190,18 +2208,12 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,
}
case gscParser::RuleStatement_foreach: {
auto [var1err, arrayVal] = fobj.RegisterVarRnd();
auto [var2err, iteratorVal] = fobj.RegisterVarRnd();

if (var1err) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule, std::format("Error when registering foreach variable: {}", var1err));
return false;
}

if (var2err) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule, std::format("Error when registering foreach iterator variable: {}", var2err));
return false;
}

// foreach (key, value in level.var_4afb8f5a) {

FunctionVar* keyVar;
Expand Down Expand Up @@ -2254,6 +2266,12 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,

switch (forEachType) {
case tool::gsc::GOHF_FOREACH_TYPE_T8: {
auto [var2err, iteratorVal] = fobj.RegisterVarRnd();
if (var2err) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule, std::format("Error when registering foreach iterator variable: {}", var2err));
return false;
}

// array = ...;
fobj.AddNode(arrVal, new AscmNodeVariable(arrayVal->id, OPCODE_EvalLocalVariableRefCached));
fobj.AddNode(arrVal, new AscmNodeOpCode(OPCODE_SetVariableField));
Expand Down Expand Up @@ -2314,6 +2332,12 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,
ok = false;
}

auto [var2err, iteratorVal] = fobj.RegisterVarRnd();
if (var2err) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule, std::format("Error when registering foreach iterator variable: {}", var2err));
return false;
}

// array = ...;
fobj.AddNode(arrVal, new AscmNodeVariable(arrayVal->id, OPCODE_EvalLocalVariableRefCached));
fobj.AddNode(arrVal, new AscmNodeOpCode(OPCODE_SetVariableField));
Expand Down Expand Up @@ -2369,6 +2393,66 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,
fobj.AddNode(rule->children[rule->children.size() - 1], loopBreak);
}
break;
case tool::gsc::GOHF_FOREACH_TYPE_JUP: {
// array = ...;
fobj.AddNode(arrVal, new AscmNodeVariable(arrayVal->id, OPCODE_SetLocalVariableCached));
// key = getfirstarraykey(array);
fobj.AddNode(arrVal, new AscmNodeOpCode(OPCODE_PreScriptCall));
fobj.AddNode(arrVal, new AscmNodeVariable(arrayVal->id, OPCODE_EvalLocalVariableCached));
uint64_t fakHash = obj.vmInfo->HashField("getfirstarraykey");
AscmNodeFunctionCall* fakNode = new AscmNodeFunctionCall(OPCODE_CallBuiltinFunction, 0, 1, fakHash, obj.currentNamespace, obj.vmInfo);
obj.AddImport(fakNode, obj.currentNamespace, fakHash, obj.currentNamespace, tool::gsc::FUNCTION | tool::gsc::GET_CALL);
fobj.AddNode(arrVal, fakNode);
fobj.AddNode(arrVal, new AscmNodeVariable(keyVar->id, OPCODE_SetLocalVariableCached));

AscmNode* loopBreak = new AscmNode();
AscmNode* loopContinue = new AscmNode();
AscmNode* loopIt = new AscmNode();

fobj.PushBreakNode(loopBreak);
fobj.PushContinueNode(loopContinue);

fobj.AddNode(arrVal, loopIt);
// jumpiffalse(isdefined(key)) loopBreak
fobj.AddNode(arrVal, new AscmNodeVariable(keyVar->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(arrVal, new AscmNodeOpCode(OPCODE_IsDefined));
fobj.AddNode(arrVal, new AscmNodeJump(loopBreak, OPCODE_JumpOnFalse));

// val = array[key];
fobj.AddNode(arrVal, new AscmNodeVariable(keyVar->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(arrVal, new AscmNodeVariable(arrayVal->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(arrVal, new AscmNodeOpCode(OPCODE_EvalArray));
fobj.AddNode(arrVal, new AscmNodeVariable(valueVar->id, OPCODE_SetLocalVariableCached));


if (!ParseExpressionNode(rule->children[rule->children.size() - 1], parser, obj, fobj, false)) {
ok = false;
}

fobj.AddNode(rule->children[rule->children.size() - 1], loopContinue);
// key = getnextarraykey(array, key);
fobj.AddNode(arrVal, new AscmNodeOpCode(OPCODE_PreScriptCall));
fobj.AddNode(rule->children[rule->children.size() - 1], new AscmNodeVariable(keyVar->id, OPCODE_EvalLocalVariableCached));
fobj.AddNode(rule->children[rule->children.size() - 1], new AscmNodeVariable(arrayVal->id, OPCODE_EvalLocalVariableCached));

uint64_t gakHash = obj.vmInfo->HashField("getnextarraykey");
AscmNodeFunctionCall* gakNode = new AscmNodeFunctionCall(OPCODE_CallBuiltinFunction, 0, 2, gakHash, obj.currentNamespace, obj.vmInfo);
obj.AddImport(gakNode, obj.currentNamespace, gakHash, obj.currentNamespace, tool::gsc::FUNCTION | tool::gsc::GET_CALL);
fobj.AddNode(arrVal, gakNode);
fobj.AddNode(rule->children[rule->children.size() - 1], new AscmNodeVariable(keyVar->id, OPCODE_SetLocalVariableCached));

// loop back
fobj.AddNode(rule->children[rule->children.size() - 1], new AscmNodeJump(loopIt, OPCODE_Jump));

fobj.PopBreakNode();
fobj.PopContinueNode();
// end
fobj.AddNode(rule->children[rule->children.size() - 1], loopBreak);

//fobj.AddNode(rule->children[rule->children.size() - 1], new AscmNodeVariable(keyVar->id, OPCODE_IW_ClearFieldVariableRef));
//fobj.AddNode(rule->children[rule->children.size() - 1], new AscmNodeVariable(arrayVal->id, OPCODE_IW_ClearFieldVariableRef));
}
break;
default:
obj.info.PrintLineMessage(alogs::LVL_ERROR, rule, std::format("foreach not implemented for vm {} (0x{:x})", obj.vmInfo->name, forEachType));
ok = false;
Expand Down Expand Up @@ -2871,21 +2955,7 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,

auto* funcCall = new AscmNodeFunctionCall(opcode, flags, (byte)paramCount, funcHash, funcNspHash, obj.vmInfo);

// link by the game, but we write it for test
Located located{ funcNspHash, funcHash };

auto& impList = obj.imports[located];

auto it = std::find_if(impList.begin(), impList.end(), [flags](const auto& e) { return e.flags == flags; });

if (it == impList.end()) {
// no equivalent, we need to create our own node
impList.emplace_back(importFlags, (byte)paramCount).nodes.push_back(funcCall);
}
else {
// same local/flags, we can add our node
it->nodes.push_back(funcCall);
}
obj.AddImport(funcCall, funcNspHash, funcHash, paramCount, importFlags);

fobj.AddNode(rule, funcCall);
}
Expand Down Expand Up @@ -3386,22 +3456,9 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,

// link by the game, but we write it for test
AscmNodeFunctionCall* asmc = new AscmNodeFunctionCall(OPCODE_GetResolveFunction, FCF_GETTER, 0, 0, 0, obj.vmInfo);
obj.AddImport(asmc, nsp, func, 0, flags);
fobj.AddNode(rule, asmc);

Located located{ nsp, func };
auto& impList = obj.imports[located];

auto it = std::find_if(impList.begin(), impList.end(), [flags](const auto& e) { return e.flags == flags; });

if (it == impList.end()) {
// no equivalent, we need to create our own node
impList.emplace_back(flags, 0).nodes.push_back(asmc);
}
else {
// same local/flags, we can add our node
it->nodes.push_back(asmc);
}

return true;
}
case gscParser::RuleObject_left_value:
Expand Down Expand Up @@ -3662,9 +3719,35 @@ bool ParseExpressionNode(ParseTree* exp, gscParser& parser, CompileObject& obj,
return true;
}
case gscParser::HASHSTRING: {
auto sub = term->getText().substr(2, len - 3);
std::string hash = term->getText();
char type = hash[0];
std::string sub = hash.substr(2, len - 3);
obj.AddHash(sub);
fobj.AddNode(term, new AscmNodeData<uint64_t>(hash::Hash64Pattern(sub.c_str()), OPCODE_GetHash));
auto ith = obj.vmInfo->hashesFunc.find(type);

if (ith == obj.vmInfo->hashesFunc.end()) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, exp, std::format("Hash type not available for this vm: {}", type));
return false;
}

uint64_t val = ith->second.hashFunc(sub.c_str());

if (!val) {
obj.info.PrintLineMessage(alogs::LVL_ERROR, exp, std::format("Can't hash the string '{}' with the type {}", sub, type));
return false;
}

switch (ith->second.size) {
case 8: fobj.AddNode(term, new AscmNodeData<uint64_t>((uint64_t)val, ith->second.opCode)); break;
case 4: fobj.AddNode(term, new AscmNodeData<uint32_t>((uint32_t)val, ith->second.opCode)); break;
case 2: fobj.AddNode(term, new AscmNodeData<uint16_t>((uint16_t)val, ith->second.opCode)); break;
case 1: fobj.AddNode(term, new AscmNodeData<uint8_t>((uint8_t)val, ith->second.opCode)); break;
default: {
obj.info.PrintLineMessage(alogs::LVL_ERROR, exp, std::format("Invalid hash size definition: {} / {} bytes", type, ith->second.size));
return false;
}
}

return true;
}
case gscParser::STRING: {
Expand Down
24 changes: 22 additions & 2 deletions src/acts/tools/gsc_opcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4528,6 +4528,26 @@ void tool::gsc::opcode::RegisterVMPlatform(byte vm, Platform plt) {

ref->second.AddPlatform(plt);
}
void tool::gsc::opcode::RegisterVMHashOPCode(byte vm, char type, OPCode opCode, int size, std::function<uint64_t(const char*)> hashFunc) {
auto ref = g_opcodeMap.find(vm);

if (ref == g_opcodeMap.end()) {
LOG_ERROR("Registered hash to bad vm: VM_{:x}", (int)vm);
return;
}

if (!(size == 8 || size == 4)) {
LOG_ERROR("Invalid size for hash vm: VM_{:x}: '{}' / {} bytes", (int)vm, type, size);
return;
}

auto [h, ok] = ref->second.hashesFunc.try_emplace(type, type, opCode, size, hashFunc);

if (!ok) {
LOG_ERROR("Registered existing hash into vm: VM_{:x}: '{}'", (int)vm, type);
return;
}
}
void tool::gsc::opcode::RegisterOpCode(byte vm, Platform platform, OPCode enumValue, uint16_t op) {
auto ref = g_opcodeMap.find(vm);
if (ref == g_opcodeMap.end()) {
Expand Down Expand Up @@ -5656,8 +5676,8 @@ int ASMContextNodeBlock::ComputeForEachBlocks(ASMContext& ctx) {
var_23ea8daa is the key, it might not be used, idea: counting the ref?
e_clip is the value
*/
constexpr auto getfirstarraykeyIWHash = hashutils::HashIW2("getfirstarraykey");
constexpr auto getnextarraykeyIWHash = hashutils::HashIW2("getnextarraykey");
constexpr uint64_t getfirstarraykeyIWHash = hashutils::HashIW2("getfirstarraykey");
constexpr uint64_t getnextarraykeyIWHash = hashutils::HashIW2("getnextarraykey");

size_t index = 0;

Expand Down
9 changes: 9 additions & 0 deletions src/acts/tools/gsc_opcodes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,21 @@ namespace tool::gsc::opcode {
}
};

struct VmHashFunc {
char type;
OPCode opCode;
int size;
std::function<uint64_t(const char*)> hashFunc;
};

class OPCodeInfo;
struct VmInfo {
byte vm;
const char* name;
const char* codeName;
uint64_t flags;
byte platforms{};
std::unordered_map<char, VmHashFunc> hashesFunc{};
std::unordered_set<uint64_t> devCallsNames{};
std::unordered_map<uint16_t, std::unordered_map<Platform, OPCode>> opcodemap{};
std::unordered_map<OPCode, std::unordered_map<Platform, uint16_t>> opcodemaplookup{};
Expand Down Expand Up @@ -111,6 +119,7 @@ namespace tool::gsc::opcode {
void RegisterVMGlobalVariable(byte vm, const char* name, OPCode getOpCode = OPCODE_Undefined);
void RegisterVMOperatorFunction(byte vm, const char* name, const char* usage, OPCode opcode, int flags, int minArgs = 0, int maxArgs = 255);
void RegisterVMPlatform(byte vm, Platform plt);
void RegisterVMHashOPCode(byte vm, char type, OPCode opCode, int size, std::function<uint64_t(const char*)> hashFunc);
void RegisterOpCode(byte vm, Platform platform, OPCode enumValue, uint16_t op);
void RegisterDevCall(byte vm, const char* devCall);
void RegisterOpCodes();
Expand Down
7 changes: 7 additions & 0 deletions src/acts/tools/gsc_opcodes_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T8, "wait", "wait(time)", OPCODE_Wait, VPFD_NONE, 1, 1);
RegisterVMOperatorFunction(VM_T8, "waitframe", "waitframe(frames)", OPCODE_WaitFrame, VPFD_NONE, 1, 1);
RegisterVMOperatorFunction(VM_T8, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T8, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64Pattern(str); });
RegisterDevCall(VM_T8, "assert", "assertmsg", "errormsg", "throw", "println");


Expand Down Expand Up @@ -327,6 +328,7 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T937, "wait", "wait(time)", OPCODE_Wait, VPFD_NONE, 1, 1);
RegisterVMOperatorFunction(VM_T937, "waitframe", "waitframe(frames)", OPCODE_WaitFrame, VPFD_NONE, 1, 1);
RegisterVMOperatorFunction(VM_T937, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T937, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64Pattern(str); });
RegisterDevCall(VM_T937, "assert", "assertmsg", "errormsg", "throw", "println");

RegisterOpCode(VM_T937, PLATFORM_PLAYSTATION, OPCODE_Unknown0, 0x0);
Expand Down Expand Up @@ -420,6 +422,7 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_T9, "wait", "wait(time)", OPCODE_Wait, VPFD_NONE, 1, 1);
RegisterVMOperatorFunction(VM_T9, "waitframe", "waitframe(frames)", OPCODE_WaitFrame, VPFD_NONE, 1, 1);
RegisterVMOperatorFunction(VM_T9, "waittillframeend", "waittillframeend()", OPCODE_WaitTillFrameEnd, VPFD_NONE, 0, 0);
RegisterVMHashOPCode(VM_T9, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64Pattern(str); });
RegisterDevCall(VM_T9, "assert", "assertmsg", "errormsg", "throw", "println");

RegisterOpCode(VM_T9, PLATFORM_PC, OPCODE_Unknown0, 0x0);
Expand Down Expand Up @@ -656,6 +659,10 @@ namespace tool::gsc::opcode {
RegisterVMOperatorFunction(VM_MW23, "waitframe", "waitframe()", OPCODE_IW_WaitFrame, VPFD_NONE, 0, 0);
RegisterVMOperatorFunction(VM_MW23, "getthread", "getthread() -> thread", OPCODE_IW_GetThread, VPFD_RETURN_VALUE, 0, 0);
RegisterVMOperatorFunction(VM_MW23, "istrue", "istrue() -> bool", OPCODE_IW_IsTrue, VPFD_RETURN_VALUE, 1, 1);
RegisterVMHashOPCode(VM_MW23, '#', OPCODE_GetHash, 8, [](const char* str) { return hash::Hash64Pattern(str); });
RegisterVMHashOPCode(VM_MW23, '@', OPCODE_IW_GetDVarHash, 8, [](const char* str) { return hash::HashPattern(str); });
RegisterVMHashOPCode(VM_MW23, '%', OPCODE_IW_GetUnk9, 8, [](const char* str) { return hash::HashPattern(str); });
RegisterVMHashOPCode(VM_MW23, 't', OPCODE_IW_GetUnkb, 4, [](const char* str) { return hash::HashPattern(str); });
RegisterDevCall(VM_MW23, "assert", "assertmsg", "assertex", "println");
#ifdef SP23_INCLUDES
sp23::opcodes::RegisterMW23OpCodes();
Expand Down
8 changes: 4 additions & 4 deletions src/shared/hash.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ namespace hash {
std::string_view v{ str };

if (!v.rfind("var_", 0)) {
return std::strtoul(&str[4], nullptr, 16);
return std::strtoull(&str[4], nullptr, 16);
}
if (!v.rfind("event_", 0)) {
return std::strtoul(&str[6], nullptr, 16);
return std::strtoull(&str[6], nullptr, 16);
}
if (!v.rfind("function_", 0)) {
return std::strtoul(&str[9], nullptr, 16);
return std::strtoull(&str[9], nullptr, 16);
}
if (!v.rfind("namespace_", 0)) {
return std::strtoul(&str[10], nullptr, 16);
return std::strtoull(&str[10], nullptr, 16);
}
if (!v.rfind("script_", 0)) {
return std::strtoull(&str[7], nullptr, 16);
Expand Down

0 comments on commit 0cee3ff

Please sign in to comment.