Skip to content

Commit

Permalink
18982: Invalid JSON conversion now returns NaS (not-a-string) instead…
Browse files Browse the repository at this point in the history
… of an empty string (#56)

Also reduces length of some extra long function names.
  • Loading branch information
calebwherry authored Jan 15, 2024
1 parent 5bf50a5 commit d229848
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 65 deletions.
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

0 comments on commit d229848

Please sign in to comment.