Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

18982: Invalid JSON conversion now returns NaS (not-a-string) instead of an empty string #56

Merged
merged 13 commits into from
Jan 15, 2024
7 changes: 4 additions & 3 deletions src/Amalgam/entity/EntityExternalInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,8 @@ std::string EntityExternalInterface::GetJSONFromLabel(std::string &handle, std::
return "";

EvaluableNode *label_val = bundle->entity->GetValueAtLabel(label, nullptr, false);
return EvaluableNodeJSONTranslation::EvaluableNodeToJson(label_val);
auto [result, converted] = EvaluableNodeJSONTranslation::EvaluableNodeToJson(label_val);
return (converted ? result : string_intern_pool.GetStringFromID(string_intern_pool.NOT_A_STRING_ID));
}

std::string EntityExternalInterface::ExecuteEntityJSON(std::string &handle, std::string &label, std::string_view json)
Expand All @@ -552,9 +553,9 @@ std::string EntityExternalInterface::ExecuteEntityJSON(std::string &handle, std:
//ConvertArgsToCallStack always adds an outer list that is safe to free
enm.FreeNode(call_stack);

std::string result = EvaluableNodeJSONTranslation::EvaluableNodeToJson(returned_value);
auto [result, converted] = EvaluableNodeJSONTranslation::EvaluableNodeToJson(returned_value);
enm.FreeNodeTreeIfPossible(returned_value);
return result;
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)
Expand Down
19 changes: 12 additions & 7 deletions src/Amalgam/importexport/FileSupportJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,21 +319,20 @@ EvaluableNode *EvaluableNodeJSONTranslation::JsonToEvaluableNode(EvaluableNodeMa
}
}

std::string EvaluableNodeJSONTranslation::EvaluableNodeToJson(EvaluableNode *code, bool sort_keys)
std::pair<std::string, bool> EvaluableNodeJSONTranslation::EvaluableNodeToJson(EvaluableNode *code, bool sort_keys)
{
if(code == nullptr)
return "null";
return std::make_pair("null", true);

//if need cycle check, double-check
if(!EvaluableNode::CanNodeTreeBeFlattened(code))
return "";
return std::make_pair("", false);

//if successful return the json, otherwise return blank
std::string json_str;
if(EvaluableNodeToJsonStringRecurse(code, json_str, sort_keys))
return json_str;
return std::make_pair(json_str, true);
else
return "";
return std::make_pair("", false);
}

EvaluableNode *EvaluableNodeJSONTranslation::Load(const std::string &resource_path, EvaluableNodeManager *enm)
Expand Down Expand Up @@ -371,8 +370,14 @@ bool EvaluableNodeJSONTranslation::Store(EvaluableNode *code, const std::string
return false;
}

auto [result, converted] = EvaluableNodeToJson(code, sort_keys);
if(!converted)
{
std::cerr << "Error storing JSON: cannot convert node to JSON" << std::endl;
return false;
}
std::ofstream file(resource_path);
file << EvaluableNodeToJson(code, sort_keys);
file << result;

return true;
}
4 changes: 2 additions & 2 deletions src/Amalgam/importexport/FileSupportJSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace EvaluableNodeJSONTranslation
//converts JSON string_view to EvaluableNode tree
EvaluableNode *JsonToEvaluableNode(EvaluableNodeManager *enm, std::string_view json_str);

//converts EvaluableNode tree to JSON string
//converts EvaluableNode tree to JSON string. Returns false if EN cannot be converted to JSON
// if sort_keys is true, it will sort all of the assoc keys
std::string EvaluableNodeToJson(EvaluableNode *code, bool sort_keys = false);
std::pair<std::string, bool> EvaluableNodeToJson(EvaluableNode *code, bool sort_keys = false);

//loads json file to EvaluableNode tree
EvaluableNode *Load(const std::string &resource_path, EvaluableNodeManager *enm);
Expand Down
18 changes: 12 additions & 6 deletions src/Amalgam/importexport/FileSupportYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,21 +158,21 @@ EvaluableNode *EvaluableNodeYAMLTranslation::YamlToEvaluableNode(EvaluableNodeMa
return YamlToEvaluableNodeRecurse(enm, yaml_top_element);
}

std::string EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(EvaluableNode *code, bool sort_keys)
std::pair<std::string, bool> EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(EvaluableNode *code, bool sort_keys)
{
if(code == nullptr)
return "null";
return std::make_pair("null", true);

//if need cycle check, double-check
if(!EvaluableNode::CanNodeTreeBeFlattened(code))
return "";
return std::make_pair("", false);

ryml::Tree tree;
auto top_node = tree.rootref();
if(EvaluableNodeToYamlStringRecurse(code, top_node, sort_keys))
return ryml::emitrs_yaml<std::string>(tree);
return std::make_pair(ryml::emitrs_yaml<std::string>(tree), true);
else
return "";
return std::make_pair("", false);
}

EvaluableNode *EvaluableNodeYAMLTranslation::Load(const std::string &resource_path, EvaluableNodeManager *enm)
Expand Down Expand Up @@ -200,8 +200,14 @@ bool EvaluableNodeYAMLTranslation::Store(EvaluableNode *code, const std::string
return false;
}

auto [result, converted] = EvaluableNodeToYaml(code, sort_keys);
if(!converted)
{
std::cerr << "Error storing YAML: cannot convert node to YAML" << std::endl;
return false;
}
std::ofstream file(resource_path);
file << EvaluableNodeToYaml(code, sort_keys);
file << result;

return true;
}
4 changes: 2 additions & 2 deletions src/Amalgam/importexport/FileSupportYAML.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace EvaluableNodeYAMLTranslation
//converts YAML string_view to EvaluableNode tree
EvaluableNode *YamlToEvaluableNode(EvaluableNodeManager *enm, std::string &yaml_str);

//converts EvaluableNode tree to YAML string
//converts EvaluableNode tree to YAML string. Returns false if EN cannot be converted to YAML
// if sort_keys is true, it will sort all of the assoc keys
std::string EvaluableNodeToYaml(EvaluableNode *code, bool sort_keys = false);
std::pair<std::string, bool> EvaluableNodeToYaml(EvaluableNode *code, bool sort_keys = false);

//loads yaml file to EvaluableNode tree
EvaluableNode *Load(const std::string &resource_path, EvaluableNodeManager *enm);
Expand Down
16 changes: 8 additions & 8 deletions src/Amalgam/interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ class Interpreter
//calls InterpretNode on tpl, traverses source based on tpl.
// If create_destination_if_necessary is set, then it will expand anything in the source as appropriate
//Returns the location of the EvaluableNode * of the destination, nullptr if it does not exist
__forceinline EvaluableNode **InterpretNodeIntoDestinationFromTraversalPathList(EvaluableNode **source,
__forceinline EvaluableNode **InterpretNodeIntoDestination(EvaluableNode **source,
EvaluableNode *tpl, bool create_destination_if_necessary)
{
EvaluableNodeReference address_list_node = InterpretNodeForImmediateUse(tpl);
Expand All @@ -432,7 +432,7 @@ class Interpreter

//Interprets node_id_path_to_interpret and then attempts to find the Entity relative to curEntity. Returns nullptr if cannot find
template<typename EntityReferenceType>
EntityReferenceType InterpretNodeIntoRelativeSourceEntityReferenceFromInterpretedEvaluableNodeIDPath(EvaluableNode *node_id_path_to_interpret)
EntityReferenceType InterpretNodeIntoRelativeSourceEntityReference(EvaluableNode *node_id_path_to_interpret)
{
if(curEntity == nullptr)
return EntityReferenceType(nullptr);
Expand All @@ -448,16 +448,16 @@ class Interpreter
return source_entity;
}

//like InterpretNodeIntoRelativeSourceEntityReferenceFromInterpretedEvaluableNodeIDPath but with a read reference
inline EntityReadReference InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(EvaluableNode *node_id_path_to_interpret)
//like InterpretNodeIntoRelativeSourceEntityReference but with a read reference
inline EntityReadReference InterpretNodeIntoRelativeSourceEntityReadReference(EvaluableNode *node_id_path_to_interpret)
{
return InterpretNodeIntoRelativeSourceEntityReferenceFromInterpretedEvaluableNodeIDPath<EntityReadReference>(node_id_path_to_interpret);
return InterpretNodeIntoRelativeSourceEntityReference<EntityReadReference>(node_id_path_to_interpret);
}

//like InterpretNodeIntoRelativeSourceEntityReferenceFromInterpretedEvaluableNodeIDPath but with a write reference
inline EntityWriteReference InterpretNodeIntoRelativeSourceEntityWriteReferenceFromInterpretedEvaluableNodeIDPath(EvaluableNode *node_id_path_to_interpret)
//like InterpretNodeIntoRelativeSourceEntityReference but with a write reference
inline EntityWriteReference InterpretNodeIntoRelativeSourceEntityWriteReference(EvaluableNode *node_id_path_to_interpret)
{
return InterpretNodeIntoRelativeSourceEntityReferenceFromInterpretedEvaluableNodeIDPath<EntityWriteReference>(node_id_path_to_interpret);
return InterpretNodeIntoRelativeSourceEntityReference<EntityWriteReference>(node_id_path_to_interpret);
}

protected:
Expand Down
6 changes: 3 additions & 3 deletions src/Amalgam/interpreter/InterpreterOpcodesBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_GET(EvaluableNode *en, boo
//if just a single index passed to get
if(ocn_size == 2)
{
EvaluableNode **target = InterpretNodeIntoDestinationFromTraversalPathList(&source.GetReference(), ocn[1], false);
EvaluableNode **target = InterpretNodeIntoDestination(&source.GetReference(), ocn[1], false);

node_stack.PopEvaluableNode();

Expand All @@ -1095,7 +1095,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_GET(EvaluableNode *en, boo

for(size_t param_index = 1; param_index < ocn_size; param_index++)
{
EvaluableNode **target = InterpretNodeIntoDestinationFromTraversalPathList(&source.GetReference(), ocn[param_index], false);
EvaluableNode **target = InterpretNodeIntoDestination(&source.GetReference(), ocn[param_index], false);
if(target != nullptr)
retrieved_list->AppendOrderedChildNode(*target);
else
Expand Down Expand Up @@ -1131,7 +1131,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_SET_and_REPLACE(EvaluableN
{
//find replacement location, make sure it's a valid target
EvaluableNode *previous_result = result;
EvaluableNode **copy_destination = InterpretNodeIntoDestinationFromTraversalPathList(&result.GetReference(), ocn[replace_change_index], true);
EvaluableNode **copy_destination = InterpretNodeIntoDestination(&result.GetReference(), ocn[replace_change_index], true);
//if the target changed, keep track of the proper reference
if(result != previous_result)
{
Expand Down
30 changes: 15 additions & 15 deletions src/Amalgam/interpreter/InterpreterOpcodesCodeMixing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_TOTAL_ENTITY_SIZE(Evaluabl

//TODO 10975: lock entire entity tree
//get the id of the first source entity
EntityReadReference source_entity = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
EntityReadReference source_entity = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
if(source_entity == nullptr)
return EvaluableNodeReference::Null();

Expand All @@ -323,7 +323,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_FLATTEN_ENTITY(EvaluableNo

//TODO 10975: lock entire entity tree
//get the id of the first source entity
EntityReadReference source_entity = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
EntityReadReference source_entity = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
if(source_entity == nullptr)
return EvaluableNodeReference::Null();

Expand Down Expand Up @@ -388,7 +388,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_MUTATE_ENTITY(EvaluableNod
//retrieve the entities after other parameters to minimize time in locks
// and prevent deadlock if one of the params accessed the entity
//get the id of the first source entity
EntityReadReference source_entity = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
EntityReadReference source_entity = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity == nullptr || source_entity == curEntity)
return EvaluableNodeReference::Null();
Expand Down Expand Up @@ -423,12 +423,12 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_COMMONALITY_ENTITIES(Evalu

//TODO 10975: change this to lock all entities at once
//get the id of the first source entity
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
if(source_entity_1 == nullptr)
return EvaluableNodeReference::Null();

//get the id of the second source entity
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[1]);
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[1]);
if(source_entity_2 == nullptr)
return EvaluableNodeReference::Null();

Expand All @@ -445,12 +445,12 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_EDIT_DISTANCE_ENTITIES(Eva

//TODO 10975: change this to lock all entities at once
//get the id of the first source entity
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
if(source_entity_1 == nullptr)
return EvaluableNodeReference::Null();

//get the id of the second source entity
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[1]);
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[1]);
if(source_entity_2 == nullptr)
return EvaluableNodeReference::Null();

Expand All @@ -471,13 +471,13 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_INTERSECT_ENTITIES(Evaluab

//TODO 10975: change this to lock all entities at once
//get the id of the first source entity
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity_1 == nullptr || source_entity_1 == curEntity)
return EvaluableNodeReference::Null();

//get the id of the second source entity
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[1]);
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[1]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity_2 == nullptr || source_entity_2 == curEntity)
return EvaluableNodeReference::Null();
Expand Down Expand Up @@ -524,13 +524,13 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_UNION_ENTITIES(EvaluableNo

//TODO 10975: change this to lock all entities at once
//get the id of the first source entity
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
Entity *source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity_1 == nullptr || source_entity_1 == curEntity)
return EvaluableNodeReference::Null();

//get the id of the second source entity
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[1]);
Entity *source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[1]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity_2 == nullptr || source_entity_2 == curEntity)
return EvaluableNodeReference::Null();
Expand Down Expand Up @@ -573,13 +573,13 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_DIFFERENCE_ENTITIES(Evalua

//TODO 10975: change this to lock all entities at once
//get the id of the first source entity
Entity *entity_1 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
Entity *entity_1 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
//need a source entity, and can't copy self! (that could cause badness)
if(entity_1 == nullptr || entity_1 == curEntity)
return EvaluableNodeReference::Null();

//get the id of the second source entity
Entity *entity_2 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[1]);
Entity *entity_2 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[1]);
//need a source entity, and can't copy self! (that could cause badness)
if(entity_2 == nullptr || entity_2 == curEntity)
return EvaluableNodeReference::Null();
Expand Down Expand Up @@ -630,13 +630,13 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_MIX_ENTITIES(EvaluableNode
//retrieve the entities after other parameters to minimize time in locks
// and prevent deadlock if one of the params accessed the entity
//get the id of the first source entity
Entity* source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[0]);
Entity* source_entity_1 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[0]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity_1 == nullptr || source_entity_1 == curEntity)
return EvaluableNodeReference::Null();

//get the id of the second source entity
Entity* source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReferenceFromInterpretedEvaluableNodeIDPath(ocn[1]);
Entity* source_entity_2 = InterpretNodeIntoRelativeSourceEntityReadReference(ocn[1]);
//need a source entity, and can't copy self! (that could cause badness)
if(source_entity_2 == nullptr || source_entity_2 == curEntity)
return EvaluableNodeReference::Null();
Expand Down
17 changes: 10 additions & 7 deletions src/Amalgam/interpreter/InterpreterOpcodesDataTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_FORMAT(EvaluableNode *en,

bool use_string = false;
std::string string_value = "";
bool valid_string_value = true;

const std::string date_string("date:");

Expand Down Expand Up @@ -805,7 +806,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_FORMAT(EvaluableNode *en,
else if(use_string)
{
EvaluableNode en_str(ENT_STRING, string_value);
string_value = EvaluableNodeJSONTranslation::EvaluableNodeToJson(&en_str);
std::tie(string_value, valid_string_value) = EvaluableNodeJSONTranslation::EvaluableNodeToJson(&en_str);
}
else if(use_code)
{
Expand All @@ -819,30 +820,30 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_FORMAT(EvaluableNode *en,
sort_keys = EvaluableNode::IsTrue(found_sort_keys->second);
}

string_value = EvaluableNodeJSONTranslation::EvaluableNodeToJson(code_value, sort_keys);
std::tie(string_value, valid_string_value) = EvaluableNodeJSONTranslation::EvaluableNodeToJson(code_value, sort_keys);
}
}
else if(to_type == ENBISI_yaml)
{
if(use_number)
{
EvaluableNode value(number_value);
string_value = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&value);
std::tie(string_value, valid_string_value) = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&value);
}
else if(use_uint_number)
{
EvaluableNode value(static_cast<double>(uint_number_value));
string_value = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&value);
std::tie(string_value, valid_string_value) = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&value);
}
else if(use_int_number)
{
EvaluableNode value(static_cast<double>(int_number_value));
string_value = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&value);
std::tie(string_value, valid_string_value) = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&value);
}
else if(use_string)
{
EvaluableNode en_str(ENT_STRING, string_value);
string_value = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&en_str);
std::tie(string_value, valid_string_value) = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(&en_str);
}
else if(use_code)
{
Expand All @@ -856,7 +857,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_FORMAT(EvaluableNode *en,
sort_keys = EvaluableNode::IsTrue(found_sort_keys->second);
}

string_value = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(code_value, sort_keys);
std::tie(string_value, valid_string_value) = EvaluableNodeYAMLTranslation::EvaluableNodeToYaml(code_value, sort_keys);
}
}
else //need to parse the string
Expand Down Expand Up @@ -893,6 +894,8 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_FORMAT(EvaluableNode *en,

string_intern_pool.DestroyStringReference(to_type);

if(!valid_string_value)
return ReuseOrAllocReturn(to_params, string_intern_pool.NOT_A_STRING_ID, immediate_result);
return ReuseOrAllocOneOfReturn(to_params, code_value, string_value, immediate_result);
}

Expand Down
Loading