diff --git a/src/Amalgam/Amalgam.h b/src/Amalgam/Amalgam.h index 45e988335..eede83080 100644 --- a/src/Amalgam/Amalgam.h +++ b/src/Amalgam/Amalgam.h @@ -60,6 +60,8 @@ extern "C" AMALGAM_EXPORT wchar_t *ExecuteEntityJsonPtrWide(char *handle, char *label, char *json); AMALGAM_EXPORT char *ExecuteEntityJsonPtr(char *handle, char *label, char *json); + AMALGAM_EXPORT char *EvalOnEntity(char *handle, char *amlg); + AMALGAM_EXPORT wchar_t *GetVersionStringWide(); AMALGAM_EXPORT char *GetVersionString(); diff --git a/src/Amalgam/AmalgamAPI.cpp b/src/Amalgam/AmalgamAPI.cpp index 355058eff..d317a9f2f 100644 --- a/src/Amalgam/AmalgamAPI.cpp +++ b/src/Amalgam/AmalgamAPI.cpp @@ -202,6 +202,14 @@ extern "C" entint.ExecuteEntity(h, l); } + char *EvalOnEntity(char *handle, char *amlg) + { + std::string h(handle); + std::string a(amlg); + std::string ret = entint.EvalOnEntity(h, a); + return StringToCharPtr(ret); + } + void DestroyEntity(char *handle) { std::string h(handle); diff --git a/src/Amalgam/AmalgamTrace.cpp b/src/Amalgam/AmalgamTrace.cpp index 9deec45a4..474bc1f46 100644 --- a/src/Amalgam/AmalgamTrace.cpp +++ b/src/Amalgam/AmalgamTrace.cpp @@ -31,6 +31,7 @@ int32_t RunAmalgamTrace(std::istream *in_stream, std::ostream *out_stream, std:: std::string input; std::string handle; std::string label; + std::string amlg; std::string clone_handle; std::string command; std::string path; @@ -188,6 +189,12 @@ int32_t RunAmalgamTrace(std::istream *in_stream, std::ostream *out_stream, std:: json_payload = input; // json data response = entint.ExecuteEntityJSON(handle, label, json_payload); } + else if(command == "EVAL_ON_ENTITY") + { + handle = StringManipulation::RemoveFirstToken(input); + amlg = StringManipulation::RemoveFirstToken(input); + response = entint.EvalOnEntity(handle, amlg); + } else if(command == "SET_RANDOM_SEED") { handle = StringManipulation::RemoveFirstToken(input); diff --git a/src/Amalgam/entity/EntityExternalInterface.cpp b/src/Amalgam/entity/EntityExternalInterface.cpp index 32f06db07..ef92819f1 100644 --- a/src/Amalgam/entity/EntityExternalInterface.cpp +++ b/src/Amalgam/entity/EntityExternalInterface.cpp @@ -260,6 +260,39 @@ std::string EntityExternalInterface::ExecuteEntityJSON(std::string &handle, std: return (converted ? result : string_intern_pool.GetStringFromID(string_intern_pool.NOT_A_STRING_ID)); } +std::string EntityExternalInterface::EvalOnEntity(const std::string &handle, const std::string &amlg) +{ + auto bundle = FindEntityBundle(handle); + if(bundle == nullptr) + return ""; + + EvaluableNodeManager &enm = bundle->entity->evaluableNodeManager; +#ifdef MULTITHREAD_SUPPORT + //lock memory before allocating call stack + Concurrency::ReadLock enm_lock(enm.memoryModificationMutex); +#endif + + auto [code, warnings, offset] = Parser::Parse(amlg, &enm); + if(code == nullptr) + return ""; + + auto call_stack = Interpreter::ConvertArgsToCallStack(EvaluableNodeReference::Null(), enm); + + EvaluableNodeReference returned_value = bundle->entity->ExecuteCodeAsEntity(code, call_stack, nullptr, + &bundle->writeListeners, bundle->printListener, nullptr +#ifdef MULTITHREAD_SUPPORT + , &enm_lock +#endif + ); + + enm.FreeNode(call_stack); + enm.FreeNodeTreeIfPossible(code); + + auto [result, converted] = EvaluableNodeJSONTranslation::EvaluableNodeToJson(returned_value); + enm.FreeNodeTreeIfPossible(returned_value); + return (converted ? result : string_intern_pool.GetStringFromID(string_intern_pool.NOT_A_STRING_ID)); +} + bool EntityExternalInterface::EntityListenerBundle::SetEntityValueAtLabel(std::string &label_name, EvaluableNodeReference new_value) { StringInternPool::StringID label_sid = string_intern_pool.GetIDFromString(label_name); diff --git a/src/Amalgam/entity/EntityExternalInterface.h b/src/Amalgam/entity/EntityExternalInterface.h index e7127036b..8db200e2f 100644 --- a/src/Amalgam/entity/EntityExternalInterface.h +++ b/src/Amalgam/entity/EntityExternalInterface.h @@ -58,6 +58,7 @@ class EntityExternalInterface bool SetJSONToLabel(std::string &handle, std::string &label, std::string_view json); std::string GetJSONFromLabel(std::string &handle, std::string &label); std::string ExecuteEntityJSON(std::string &handle, std::string &label, std::string_view json); + std::string EvalOnEntity(const std::string &handle, const std::string &amlg); protected: @@ -171,7 +172,7 @@ class EntityExternalInterface }; //looks up the bundle and returns it, will return nullptr if not found - inline EntityListenerBundleReadReference FindEntityBundle(std::string &handle) + inline EntityListenerBundleReadReference FindEntityBundle(const std::string &handle) { #ifdef MULTITHREAD_INTERFACE Concurrency::ReadLock read_lock(mutex); diff --git a/test/lib_smoke_test/main.cpp b/test/lib_smoke_test/main.cpp index 320f4b5cb..ef3b814ba 100644 --- a/test/lib_smoke_test/main.cpp +++ b/test/lib_smoke_test/main.cpp @@ -22,13 +22,21 @@ int main(int argc, char* argv[]) char write_log[] = ""; char print_log[] = ""; auto status = LoadEntity(handle, file, file_type, false, json_file_params, write_log, print_log); - if(status.loaded) + if(!status.loaded) + return 1; + + int retval = 0; + char label[] = "test"; + ExecuteEntity(handle, label); + + std::string amlg("(size (contained_entities))"); + std::string result = EvalOnEntity(handle, amlg.data()); + if(result != std::string("24")) { - char label[] = "test"; - ExecuteEntity(handle, label); - DestroyEntity(handle); - return 0; + std::cerr << "EvalOnEntity produced " << result << " but expected 24"; + retval = 1; } - return 1; + DestroyEntity(handle); + return retval; }