Skip to content

Commit

Permalink
19641: Improves flexibility and documentation of entity traversal wit…
Browse files Browse the repository at this point in the history
…h nulls, MINOR (#95)
  • Loading branch information
howsohazard authored Mar 14, 2024
1 parent 3c65741 commit fc26b24
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 184 deletions.
4 changes: 2 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,8 @@ <h2>Type descriptions</h2>
Comparisons and sorting on any strings are done in "natural order", meaning that 1x comes before 10, and m20x comes after m2a
<p>
IDs that only consist of integers, that is, 0-9, are considered as automatically generated IDs. For entity mixing, entities with IDs are compared against each other and automatically merged. In general, these IDs should not be stored by the container, but rather iterated over.<p>
IDs that have non-integer characters are considered named Entities. Since named entities are considered as explicitly referenced by the container, they will only be merged against other entities with the same name.

IDs that have non-integer characters are considered named Entities. Since named entities are considered as explicitly referenced by the container, they will only be merged against other entities with the same name.<p>
For opcodes that use IDs, if no id specified or the id is null, then the current entity is used. If the id is an immediate value, it accesses a contained entity by that name. If the id is a list, then it starts from the current entity and traverses each contained entity by name, ignoring nulls in the list.
<hr>

<a name="syntax"></a>
Expand Down
2 changes: 1 addition & 1 deletion docs/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -1237,7 +1237,7 @@ var data = [
"output" : "*",
"permissions" : "e",
"new value" : "new",
"description" : "Evaluates to the entity's code, looking up the entity by the id. If no id specified or the id is null, then uses the current entity, otherwise accesses a contained entity. If suppress_label_escapes is false or omitted, will disable any labels obtained by inserting an extra # at the beginning of each.",
"description" : "Evaluates to the entity's code, looking up the entity by the id. If suppress_label_escapes is false or omitted, will disable any labels obtained by inserting an extra # at the beginning of each.",
"example" : "(print (retrieve_entity_root))\n(print (retrieve_entity_root 1))"
},

Expand Down
1 change: 1 addition & 0 deletions src/Amalgam/Opcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ void StringInternPool::InitializeStaticStrings()

//dynamically generated function parameters
EmplaceStaticString(ENBISI__, "_");
EmplaceStaticString(ENBISI_create_new_entity, "create_new_entity");
EmplaceStaticString(ENBISI_new_entity, "new_entity");

//entity access parameters
Expand Down
1 change: 1 addition & 0 deletions src/Amalgam/Opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ enum EvaluableNodeBuiltInStringId

//dynamically generated function parameters
ENBISI__,
ENBISI_create_new_entity,
ENBISI_new_entity,

//entity access parameters
Expand Down
3 changes: 2 additions & 1 deletion src/Amalgam/amlg_code/full_test.amlg
Original file line number Diff line number Diff line change
Expand Up @@ -1915,7 +1915,8 @@
(print "--retrieve_entity_root--\n")
(create_entities "SetGetCodeTest" (lambda (list 1 2 ##three 3)))
(print (retrieve_entity_root "SetGetCodeTest"))
(print (retrieve_entity_root "SetGetCodeTest" 1))
(print (retrieve_entity_root "SetGetCodeTest" (true)))
(print (retrieve_entity_root (list (null) (null) "SetGetCodeTest" (null)) ))

(print "--assign_entity_roots--\n")
(assign_entity_roots "SetGetCodeTest" (list 4 5 6))
Expand Down
4 changes: 2 additions & 2 deletions src/Amalgam/amlg_code/test.amlg
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(seq
(print "17 " (generalized_distance (null) (list "nominal_numeric") (list 1) (null) 1 (list 1 2 3) (list 10 2 4) ) "\n")

(create_entities "MergeEntity1" (lambda (associate "a" 3 "b" 4)) )
(print (retrieve_entity_root (list) ))
)
12 changes: 9 additions & 3 deletions src/Amalgam/entity/EntityManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ EvaluableNodeReference EntityManipulation::DifferenceEntities(Interpreter *inter

//////////
//build code to look like:
// (declare (assoc _ null)
// (declare (assoc _ (null))
// (let (assoc new_entity (create_entity
// (call (lambda *entity difference code*)
// (assoc _ (get_entity_code _) )
Expand Down Expand Up @@ -273,7 +273,7 @@ EvaluableNodeReference EntityManipulation::DifferenceEntities(Interpreter *inter
}

//create the following:
// (declare (assoc _ null)
// (declare (assoc _ (null))
// (let (assoc new_entity (first (create_entities)) ) )
// )
EvaluableNode *let_new_entity = enm->AllocNode(ENT_LET);
Expand All @@ -286,7 +286,7 @@ EvaluableNodeReference EntityManipulation::DifferenceEntities(Interpreter *inter
let_assoc->SetMappedChildNode(ENBISI_new_entity, first_of_create_entity);

//apply difference in code from source to build:
// (declare (assoc _ null)
// (declare (assoc _ (null))
// (let (assoc new_entity (first (create_entities
// (call (lambda *entity difference code*)
// (assoc _ (get_entity_code _) )
Expand Down Expand Up @@ -650,11 +650,17 @@ EvaluableNodeReference EntityManipulation::FlattenEntity(Interpreter *interprete
{
EvaluableNodeManager *enm = interpreter->evaluableNodeManager;

//TODO 19641: add code and tests to handle null root, and update documentation

//////////
//build code to look like:
// (let (assoc new_entity (first (create_entities
// (lambda *entity code*) )
// ) ) )
//
// (declare (assoc _ (null) create_new_entity (true) .... separate parameter to overwrite current entity, ENBISI_create_new_entity
//
//
// [if include_rand_seeds]
// (set_entity_rand_seed
// new_entity
Expand Down
55 changes: 37 additions & 18 deletions src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,35 +58,54 @@ EntityReferenceType TraverseToExistingEntityReferenceViaEvaluableNodeIDPath(Enti

auto &ocn = id_path->GetOrderedChildNodes();

//always keep one to two locks active at once to walk down the entity containers
EntityReadReference relative_entity_read(container);
//size of the entity list excluding trailing nulls
size_t non_null_size = ocn.size();
for(; non_null_size > 0; non_null_size--)
{
if(!EvaluableNode::IsNull(ocn[non_null_size - 1]))
break;
}

if(ocn.size() == 0)
if(non_null_size == 0)
{
//if empty list, return the container itself
if(id_path->GetType() == ENT_LIST)
return EntityReferenceType(container);

//if the string doesn't exist, then there can't be an entity with that name
StringInternPool::StringID sid = EvaluableNode::ToStringIDIfExists(id_path);
return EntityReferenceType(container->GetContainedEntity(sid));
}

size_t last_ce = ocn.size();
for(size_t i = 0; i < last_ce; i++)
//if traversing, then it needs to be a list, otherwise not a valid entity
if(id_path->GetType() != ENT_LIST)
return EntityReferenceType(nullptr);

//always keep one to two locks active at once to walk down the entity containers
EntityReadReference cur_traversing_entity(container);

for(size_t i = 0; i < non_null_size; i++)
{
EvaluableNode *cn = ocn[i];

//null means current entity wherever it is in the traversal
if(EvaluableNode::IsNull(cn))
continue;

//if the string doesn't exist, then there can't be an entity with that name
StringInternPool::StringID sid = EvaluableNode::ToStringIDIfExists(cn);
if(i + 1 == last_ce)
{
//last reference, use destination type
return EntityReferenceType(relative_entity_read->GetContainedEntity(sid));
}
else
{
//assignment should keep both read locks simultaneously
relative_entity_read = relative_entity_read->GetContainedEntity(sid);
//if doesn't exist, exit gracefully
if(relative_entity_read == nullptr)
return EntityReferenceType(nullptr);
}
Entity *relative_entity = cur_traversing_entity->GetContainedEntity(sid);

//if entity doesn't exist, exit gracefully
if(relative_entity == nullptr)
return EntityReferenceType(nullptr);

//if last reference, use destination type
if(i + 1 == non_null_size)
return EntityReferenceType(relative_entity);

//create new read lock and overwrite existing to walk down the list
cur_traversing_entity = EntityReadReference(relative_entity);
}

//shouldn't make it here
Expand Down
Loading

0 comments on commit fc26b24

Please sign in to comment.