Skip to content

Commit

Permalink
22250: Adds EvalOnEntity to Amalgam API, MINOR (#324)
Browse files Browse the repository at this point in the history
`EvalOnEntity(handle, "(arbitrary_code)")` runs that code in the context
of some entity.
  • Loading branch information
dmaze authored Dec 15, 2024
1 parent 21b9e28 commit ba08bba
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/Amalgam/Amalgam.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
8 changes: 8 additions & 0 deletions src/Amalgam/AmalgamAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions src/Amalgam/AmalgamTrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
33 changes: 33 additions & 0 deletions src/Amalgam/entity/EntityExternalInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/Amalgam/entity/EntityExternalInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -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);
Expand Down
20 changes: 14 additions & 6 deletions test/lib_smoke_test/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit ba08bba

Please sign in to comment.