From e4761bb06fa12ac769eadccd614d03310f98b58d Mon Sep 17 00:00:00 2001 From: howsohazard <143410553+howsohazard@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:46:10 -0400 Subject: [PATCH] 20396: Adds return opcode, MINOR (#140) --- docs/language.js | 17 +- src/Amalgam/Opcodes.cpp | 1 + src/Amalgam/Opcodes.h | 5 +- src/Amalgam/amlg_code/full_test.amlg | 6 + .../evaluablenode/EvaluableNodeManagement.h | 5 + .../EvaluableNodeTreeFunctions.h | 18 + .../EvaluableNodeTreeManipulation.cpp | 1 + src/Amalgam/interpreter/Interpreter.cpp | 3 +- src/Amalgam/interpreter/Interpreter.h | 2 +- .../interpreter/InterpreterOpcodesBase.cpp | 96 +++-- .../InterpreterOpcodesEntityAccess.cpp | 32 +- src/Amalgam/out.txt | 369 +++++++++--------- 12 files changed, 308 insertions(+), 247 deletions(-) diff --git a/docs/language.js b/docs/language.js index 26961c85..64dd5591 100644 --- a/docs/language.js +++ b/docs/language.js @@ -52,7 +52,7 @@ var data = [ { "parameter" : "seq [code c1] [code c2] ... [code cN]", "output" : "*", - "description" : "Runs each code block sequentially. Evaluates to the result of the last code block run, unless it encounters a conclude in an earlier step, in which case it will halt processing and evaluate to the value returned by conclude. Note that the last step will not consume a concluded value.", + "description" : "Runs each code block sequentially. Evaluates to the result of the last code block run, unless it encounters a conclude or return in an earlier step, in which case it will halt processing and evaluate to the value returned by conclude or propagate the return. Note that the last step will not consume a concluded value.", "example" : "(seq (print 1) (print 2) (print 3))" }, @@ -74,9 +74,16 @@ var data = [ { "parameter" : "conclude * conclusion", "output" : "*", - "description" : "Evaluates to the conclusion wrapped in a conclude opcode. If a step in a seq, let, declare, or while evaluates to a conclude (excluding variable declarations for let and declare, the last step in set, let, and declare, or the condition of while), then it will conclude the execution and evaluate to the value conclusion. Note that conclude opcodes may be nested to break out of outer opcodes", + "description" : "Evaluates to the conclusion wrapped in a conclude opcode. If a step in a seq, let, declare, or while evaluates to a conclude (excluding variable declarations for let and declare, the last step in set, let, and declare, or the condition of while), then it will conclude the execution and evaluate to the value conclusion. Note that conclude opcodes may be nested to break out of outer opcodes.", "example" : "(print (seq (print \"seq1 \") (conclude \"success\") (print \"seq2\") ) )" }, + + { + "parameter" : "return * return_value", + "output" : "*", + "description" : "Evaluates to return_value wrapped in a return opcode. If a step in a seq, let, declare, or while evaluates to a return (excluding variable declarations for let and declare, the last step in set, let, and declare, or the condition of while), then it will conclude the execution and evaluate to the return opcode with its return_value. This means it will continue to conclude each level up the stack until it reaches any kind of call opcode, including call, call_sandboxed, call_entity, call_entity_get_changes, or call_container, at which point it will evaluate to return_value. Note that return opcodes may be nested to break out of multiple calls.", + "example" : " (print (call (seq 1 2 (seq (return 3) 4) 5)) \"\\n\")" + }, { "parameter" : "call * function assoc arguments", @@ -98,7 +105,7 @@ var data = [ "parameter" : "while bool condition [code code1] [code code2] ... [code codeN]", "output" : "*", "new target scope": true, - "description" : "Each time the condition evaluates to true, it runs each of the code trees sequentially, looping. Evaluates to the last codeN or null if the condition was initially false or if it encounters a conclude, it will halt processing and evaluate to the value returned by conclude. For iteration of the loop, pushes a new target scope onto the target stack, with current_index being the iteration count, and previous_result being the last evaluated codeN of the previous loop.", + "description" : "Each time the condition evaluates to true, it runs each of the code trees sequentially, looping. Evaluates to the last codeN or null if the condition was initially false or if it encounters a conclude or return, it will halt processing and evaluate to the value returned by conclude or propagate the return. For iteration of the loop, pushes a new target scope onto the target stack, with current_index being the iteration count, and previous_result being the last evaluated codeN of the previous loop.", "example" : "(let (assoc zz 1)\n (while (< zz 10)\n (print zz)\n (assign (assoc zz (+ zz 1)))\n )\n)" }, @@ -106,14 +113,14 @@ var data = [ "parameter" : "let assoc data [code function1] [code function2] ... [code functionN]", "output" : "*", "new scope" : true, - "description" : "Pushes the key-value pairs of data onto the scope stack so that they become the new variables, then runs each code block sequentially, evaluating to the last code block run, unless it encounters a conclude, in which case it will halt processing and evaluate to the value returned by conclude. Note that the last step will not consume a concluded value.", + "description" : "Pushes the key-value pairs of data onto the scope stack so that they become the new variables, then runs each code block sequentially, evaluating to the last code block run, unless it encounters a conclude or return, in which case it will halt processing and evaluate to the value returned by conclude or propagate the return. Note that the last step will not consume a concluded value.", "example" : "(let (assoc x 4 y 6) (print (+ x y)))" }, { "parameter" : "declare assoc data [code function1] [code function2] ... [code functionN]", "output" : "*", - "description" : "For each key-value pair of data, if not already in the current context in the scope stack, it will define them. Then runs each code block sequentially, evaluating to the last code block run, unless it encounters a conclude, in which case it will halt processing and evaluate to the value returned by conclude. Note that the last step will not consume a concluded value.", + "description" : "For each key-value pair of data, if not already in the current context in the scope stack, it will define them. Then runs each code block sequentially, evaluating to the last code block run, unless it encounters a conclude or return, in which case it will halt processing and evaluate to the value returned by conclude or propagate the return. Note that the last step will not consume a concluded value.", "example" : "(let (assoc x 4 y 6)\n (declare (assoc x 5 z 1)\n (print (+ x y z)) )\n)" }, diff --git a/src/Amalgam/Opcodes.cpp b/src/Amalgam/Opcodes.cpp index ad739f98..555ee9ba 100644 --- a/src/Amalgam/Opcodes.cpp +++ b/src/Amalgam/Opcodes.cpp @@ -30,6 +30,7 @@ void StringInternPool::InitializeStaticStrings() EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_PARALLEL), "parallel"); EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_LAMBDA), "lambda"); EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_CONCLUDE), "conclude"); + EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_RETURN), "return"); EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_CALL), "call"); EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_CALL_SANDBOXED), "call_sandboxed"); EmplaceStaticString(GetStringIdFromNodeTypeFromString(ENT_WHILE), "while"); diff --git a/src/Amalgam/Opcodes.h b/src/Amalgam/Opcodes.h index ffe39c0a..f2ff46aa 100644 --- a/src/Amalgam/Opcodes.h +++ b/src/Amalgam/Opcodes.h @@ -20,6 +20,7 @@ enum EvaluableNodeType : uint8_t ENT_PARALLEL, ENT_LAMBDA, ENT_CONCLUDE, + ENT_RETURN, ENT_CALL, ENT_CALL_SANDBOXED, ENT_WHILE, @@ -370,7 +371,7 @@ constexpr OrderedChildNodeType GetInstructionOrderedChildNodeType(EvaluableNodeT return OCNT_ONE_POSITION_THEN_PAIRED; case ENT_PARSE: case ENT_UNPARSE: case ENT_IF: case ENT_LAMBDA: - case ENT_CONCLUDE: + case ENT_CONCLUDE: case ENT_RETURN: case ENT_CALL: case ENT_CALL_SANDBOXED: case ENT_RETRIEVE: case ENT_GET: @@ -487,7 +488,7 @@ constexpr bool IsEvaluableNodeTypePotentiallyIdempotent(EvaluableNodeType type) return (type == ENT_NUMBER || type == ENT_STRING || type == ENT_TRUE || type == ENT_FALSE || type == ENT_NULL || type == ENT_LIST || type == ENT_ASSOC - || type == ENT_CONCLUDE + || type == ENT_CONCLUDE || type == ENT_RETURN || IsEvaluableNodeTypeQuery(type)); } diff --git a/src/Amalgam/amlg_code/full_test.amlg b/src/Amalgam/amlg_code/full_test.amlg index 9e1f4f76..7faa5eb4 100644 --- a/src/Amalgam/amlg_code/full_test.amlg +++ b/src/Amalgam/amlg_code/full_test.amlg @@ -103,6 +103,12 @@ (print "2\n") ) + (print "--return--\n") + + (print (call + (seq 1 2 (seq (return 3) 4) 5) + ) "\n") + (print "--declare--\n") (declare (assoc x 7)) (print x "\n") diff --git a/src/Amalgam/evaluablenode/EvaluableNodeManagement.h b/src/Amalgam/evaluablenode/EvaluableNodeManagement.h index e9b353d2..bb8f501b 100644 --- a/src/Amalgam/evaluablenode/EvaluableNodeManagement.h +++ b/src/Amalgam/evaluablenode/EvaluableNodeManagement.h @@ -114,6 +114,11 @@ class EvaluableNodeReference return value.nodeType != ENIVT_CODE; } + constexpr bool IsNonNullNodeReference() + { + return (value.nodeType == ENIVT_CODE && value.nodeValue.code != nullptr); + } + constexpr EvaluableNodeImmediateValueWithType &GetValue() { return value; diff --git a/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.h b/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.h index 1b34355e..cba00e48 100644 --- a/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.h +++ b/src/Amalgam/evaluablenode/EvaluableNodeTreeFunctions.h @@ -277,3 +277,21 @@ inline EvaluableNodeReference CreateListOfStringsFromIteratorAndFunction(StringC return EvaluableNodeReference(list, true); } + +//removes the top conclude or return node and, if possible, will free it, saving memory +inline EvaluableNodeReference RemoveTopConcludeOrReturnNode(EvaluableNodeReference result, EvaluableNodeManager *enm) +{ + if(result == nullptr) + return EvaluableNodeReference::Null(); + + if(result->GetOrderedChildNodes().size() == 0) + { + enm->FreeNodeTreeIfPossible(result); + return EvaluableNodeReference::Null(); + } + + EvaluableNode *conclusion = result->GetOrderedChildNodes()[0]; + enm->FreeNodeIfPossible(result); + + return EvaluableNodeReference(conclusion, result.unique); +} diff --git a/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp b/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp index d27a1f00..978986f0 100644 --- a/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp +++ b/src/Amalgam/evaluablenode/EvaluableNodeTreeManipulation.cpp @@ -1896,6 +1896,7 @@ CompactHashMap EvaluableNodeTreeManipulation::evaluab {ENT_PARALLEL, 0.5}, {ENT_LAMBDA, 1.5}, {ENT_CONCLUDE, 0.05}, + {ENT_RETURN, 0.05}, {ENT_CALL, 1.5}, {ENT_CALL_SANDBOXED, 0.25}, {ENT_WHILE, 0.1}, diff --git a/src/Amalgam/interpreter/Interpreter.cpp b/src/Amalgam/interpreter/Interpreter.cpp index a2d95110..3b201b33 100644 --- a/src/Amalgam/interpreter/Interpreter.cpp +++ b/src/Amalgam/interpreter/Interpreter.cpp @@ -40,7 +40,8 @@ std::array Interpreter &Interpreter::InterpretNode_ENT_SEQUENCE, // ENT_SEQUENCE &Interpreter::InterpretNode_ENT_PARALLEL, // ENT_PARALLEL &Interpreter::InterpretNode_ENT_LAMBDA, // ENT_LAMBDA - &Interpreter::InterpretNode_ENT_CONCLUDE, // ENT_CONCLUDE + &Interpreter::InterpretNode_ENT_CONCLUDE_and_RETURN, // ENT_CONCLUDE + &Interpreter::InterpretNode_ENT_CONCLUDE_and_RETURN, // ENT_RETURN &Interpreter::InterpretNode_ENT_CALL, // ENT_CALL &Interpreter::InterpretNode_ENT_CALL_SANDBOXED, // ENT_CALL_SANDBOXED &Interpreter::InterpretNode_ENT_WHILE, // ENT_WHILE diff --git a/src/Amalgam/interpreter/Interpreter.h b/src/Amalgam/interpreter/Interpreter.h index 230f255d..27f4a7ac 100644 --- a/src/Amalgam/interpreter/Interpreter.h +++ b/src/Amalgam/interpreter/Interpreter.h @@ -706,7 +706,7 @@ class Interpreter EvaluableNodeReference InterpretNode_ENT_SEQUENCE(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_PARALLEL(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_LAMBDA(EvaluableNode *en, bool immediate_result); - EvaluableNodeReference InterpretNode_ENT_CONCLUDE(EvaluableNode *en, bool immediate_result); + EvaluableNodeReference InterpretNode_ENT_CONCLUDE_and_RETURN(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_CALL(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_CALL_SANDBOXED(EvaluableNode *en, bool immediate_result); EvaluableNodeReference InterpretNode_ENT_WHILE(EvaluableNode *en, bool immediate_result); diff --git a/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp b/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp index 3dc7ead1..81a3df1e 100644 --- a/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp +++ b/src/Amalgam/interpreter/InterpreterOpcodesBase.cpp @@ -338,18 +338,6 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_IF(EvaluableNode *en, bool return EvaluableNodeReference::Null(); } -//removes the conclude node from the top of the conclusion and, if possible, will free it, saving memory -inline EvaluableNodeReference RemoveConcludeFromConclusion(EvaluableNodeReference result, EvaluableNodeManager *enm) -{ - if(result == nullptr || result->GetOrderedChildNodes().size() == 0) - return EvaluableNodeReference::Null(); - - EvaluableNode *conclusion = result->GetOrderedChildNodes()[0]; - enm->FreeNodeIfPossible(result); - - return EvaluableNodeReference(conclusion, result.unique); -} - EvaluableNodeReference Interpreter::InterpretNode_ENT_SEQUENCE(EvaluableNode *en, bool immediate_result) { auto &ocn = en->GetOrderedChildNodes(); @@ -358,11 +346,18 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_SEQUENCE(EvaluableNode *en EvaluableNodeReference result = EvaluableNodeReference::Null(); for(size_t i = 0; i < ocn_size; i++) { - if(!result.IsImmediateValue() && result != nullptr && result->GetType() == ENT_CONCLUDE) - return RemoveConcludeFromConclusion(result, evaluableNodeManager); + if(result.IsNonNullNodeReference()) + { + auto result_type = result->GetType(); + if(result_type == ENT_CONCLUDE) + return RemoveTopConcludeOrReturnNode(result, evaluableNodeManager); + else if(result_type == ENT_RETURN) + return result; + } //free from previous iteration evaluableNodeManager->FreeNodeTreeIfPossible(result); + //request immediate values when not last, since any allocs for returns would be wasted //concludes won't be immediate result = InterpretNode(ocn[i], immediate_result || i + 1 < ocn_size); @@ -457,7 +452,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_LAMBDA(EvaluableNode *en, } } -EvaluableNodeReference Interpreter::InterpretNode_ENT_CONCLUDE(EvaluableNode *en, bool immediate_result) +EvaluableNodeReference Interpreter::InterpretNode_ENT_CONCLUDE_and_RETURN(EvaluableNode *en, bool immediate_result) { auto &ocn = en->GetOrderedChildNodes(); @@ -469,14 +464,15 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CONCLUDE(EvaluableNode *en if(en->GetIsIdempotent()) return evaluableNodeManager->DeepAllocCopy(en, EvaluableNodeManager::ENMM_REMOVE_ALL); - EvaluableNodeReference conclusion_value = InterpretNode(ocn[0]); + EvaluableNodeReference value = InterpretNode(ocn[0]); //need to evaluate its parameter and return a new node encapsulating it - EvaluableNodeReference conclusion(evaluableNodeManager->AllocNode(ENT_CONCLUDE), true); - conclusion->AppendOrderedChildNode(conclusion_value); - conclusion.UpdatePropertiesBasedOnAttachedNode(conclusion_value); + auto node_type = en->GetType(); + EvaluableNodeReference result(evaluableNodeManager->AllocNode(node_type), true); + result->AppendOrderedChildNode(value); + result.UpdatePropertiesBasedOnAttachedNode(value); - return conclusion; + return result; } EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL(EvaluableNode *en, bool immediate_result) @@ -503,15 +499,19 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL(EvaluableNode *en, bo PushNewCallStack(new_context); //call the code - auto retval = InterpretNode(function, immediate_result); + auto result = InterpretNode(function, immediate_result); //all finished with new context, but can't free it in case returning something PopCallStack(); + //call opcodes should consume the outer return opcode if there is one + if(result.IsNonNullNodeReference() && result->GetType() == ENT_RETURN) + result = RemoveTopConcludeOrReturnNode(result, evaluableNodeManager); + if(_label_profiling_enabled && function->GetNumLabels() > 0) PerformanceProfiler::EndOperation(evaluableNodeManager->GetNumberOfUsedNodes()); - return retval; + return result; } EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_SANDBOXED(EvaluableNode *en, bool immediate_result) @@ -599,6 +599,10 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_SANDBOXED(EvaluableNo curExecutionStep += sandbox.curExecutionStep; + //call opcodes should consume the outer return opcode if there is one + if(result.IsNonNullNodeReference() && result->GetType() == ENT_RETURN) + result = RemoveTopConcludeOrReturnNode(result, evaluableNodeManager); + if(_label_profiling_enabled && function->GetNumLabels() > 0) PerformanceProfiler::EndOperation(evaluableNodeManager->GetNumberOfUsedNodes()); @@ -645,14 +649,22 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_WHILE(EvaluableNode *en, b //cannot be evaulated as immediate new_result = InterpretNode(ocn[i], i + 1 < ocn_size); - if(!new_result.IsImmediateValue() && new_result != nullptr && new_result->GetType() == ENT_CONCLUDE) + if(new_result.IsNonNullNodeReference()) { - //if previous result is unconsumed, free if possible - previous_result = GetAndClearPreviousResultInConstructionStack(0); - evaluableNodeManager->FreeNodeTreeIfPossible(previous_result); + auto new_result_type = new_result->GetType(); + if(new_result_type == ENT_CONCLUDE || new_result_type == ENT_RETURN) + { + //if previous result is unconsumed, free if possible + previous_result = GetAndClearPreviousResultInConstructionStack(0); + evaluableNodeManager->FreeNodeTreeIfPossible(previous_result); - PopConstructionContext(); - return RemoveConcludeFromConclusion(new_result, evaluableNodeManager); + PopConstructionContext(); + + if(new_result_type == ENT_CONCLUDE) + return RemoveTopConcludeOrReturnNode(new_result, evaluableNodeManager); + else if(new_result_type == ENT_RETURN) + return new_result; + } } //don't free the last new_result @@ -686,14 +698,24 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_LET(EvaluableNode *en, boo EvaluableNodeReference result = EvaluableNodeReference::Null(); for(size_t i = 1; i < ocn_size; i++) { - if(!result.IsImmediateValue() && result != nullptr && result->GetType() == ENT_CONCLUDE) + if(result.IsNonNullNodeReference()) { - PopCallStack(); - return RemoveConcludeFromConclusion(result, evaluableNodeManager); + auto result_type = result->GetType(); + if(result_type == ENT_CONCLUDE) + { + PopCallStack(); + return RemoveTopConcludeOrReturnNode(result, evaluableNodeManager); + } + else if(result_type == ENT_RETURN) + { + PopCallStack(); + return result; + } } //free from previous iteration evaluableNodeManager->FreeNodeTreeIfPossible(result); + //request immediate values when not last, since any allocs for returns would be wasted //concludes won't be immediate result = InterpretNode(ocn[i], immediate_result || i + 1 < ocn_size); @@ -701,7 +723,6 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_LET(EvaluableNode *en, boo //all finished with new context, but can't free it in case returning something PopCallStack(); - return result; } @@ -823,11 +844,18 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_DECLARE(EvaluableNode *en, //run code for(size_t i = 1; i < ocn_size; i++) { - if(!result.IsImmediateValue() && result != nullptr && result->GetType() == ENT_CONCLUDE) - return RemoveConcludeFromConclusion(result, evaluableNodeManager); + if(result.IsNonNullNodeReference()) + { + auto result_type = result->GetType(); + if(result_type == ENT_CONCLUDE) + return RemoveTopConcludeOrReturnNode(result, evaluableNodeManager); + else if(result_type == ENT_RETURN) + return result; + } //free from previous iteration evaluableNodeManager->FreeNodeTreeIfPossible(result); + //request immediate values when not last, since any allocs for returns would be wasted //concludes won't be immediate result = InterpretNode(ocn[i], immediate_result || i + 1 < ocn_size); diff --git a/src/Amalgam/interpreter/InterpreterOpcodesEntityAccess.cpp b/src/Amalgam/interpreter/InterpreterOpcodesEntityAccess.cpp index aca820a5..9fd7c106 100644 --- a/src/Amalgam/interpreter/InterpreterOpcodesEntityAccess.cpp +++ b/src/Amalgam/interpreter/InterpreterOpcodesEntityAccess.cpp @@ -502,7 +502,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_ENTITY_and_CALL_ENTIT ExecutionCycleCount num_steps_executed = 0; size_t num_nodes_allocated = 0; - EvaluableNodeReference retval = called_entity->Execute(num_steps_allowed, num_steps_executed, + EvaluableNodeReference result = called_entity->Execute(num_steps_allowed, num_steps_executed, num_nodes_allowed, num_nodes_allocated, entity_label_sid, call_stack, called_entity == curEntity, this, cur_write_listeners, printListener #ifdef MULTITHREAD_SUPPORT @@ -514,11 +514,15 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_ENTITY_and_CALL_ENTIT curExecutionStep += num_steps_executed; curNumExecutionNodesAllocatedToEntities += num_nodes_allocated; + //call opcodes should consume the outer return opcode if there is one + if(result.IsNonNullNodeReference() && result->GetType() == ENT_RETURN) + result = RemoveTopConcludeOrReturnNode(result, &called_entity->evaluableNodeManager); + if(called_entity != curEntity) { - EvaluableNodeReference copied_result = evaluableNodeManager->DeepAllocCopy(retval); - called_entity->evaluableNodeManager.FreeNodeTreeIfPossible(retval); - retval = copied_result; + EvaluableNodeReference copied_result = evaluableNodeManager->DeepAllocCopy(result); + called_entity->evaluableNodeManager.FreeNodeTreeIfPossible(result); + result = copied_result; } if(en->GetType() == ENT_CALL_ENTITY_GET_CHANGES) @@ -528,21 +532,21 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_ENTITY_and_CALL_ENTIT EvaluableNode *list = evaluableNodeManager->AllocNode(ENT_LIST); //copy the data out of the write listener - list->AppendOrderedChildNode(retval); + list->AppendOrderedChildNode(result); list->AppendOrderedChildNode(evaluableNodeManager->DeepAllocCopy(writes)); //delete the write listener and all of its memory delete wl; - retval.SetReference(list); - retval.SetNeedCycleCheck(true); //can't count on that due to things written in the write listener - retval->SetIsIdempotent(false); + result.SetReference(list); + result.SetNeedCycleCheck(true); //can't count on that due to things written in the write listener + result->SetIsIdempotent(false); } if(_label_profiling_enabled) PerformanceProfiler::EndOperation(evaluableNodeManager->GetNumberOfUsedNodes()); - return retval; + return result; } EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_CONTAINER(EvaluableNode *en, bool immediate_result) @@ -631,7 +635,7 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_CONTAINER(EvaluableNo ExecutionCycleCount num_steps_executed = 0; size_t num_nodes_allocated = 0; - EvaluableNodeReference retval = container->Execute(num_steps_allowed, num_steps_executed, num_nodes_allowed, num_nodes_allocated, + EvaluableNodeReference result = container->Execute(num_steps_allowed, num_steps_executed, num_nodes_allowed, num_nodes_allocated, container_label_sid, call_stack, false, this, writeListeners, printListener #ifdef MULTITHREAD_SUPPORT , &container.lock @@ -642,8 +646,12 @@ EvaluableNodeReference Interpreter::InterpretNode_ENT_CALL_CONTAINER(EvaluableNo curExecutionStep += num_steps_executed; curNumExecutionNodesAllocatedToEntities += num_nodes_allocated; - EvaluableNodeReference copied_result = evaluableNodeManager->DeepAllocCopy(retval); - container->evaluableNodeManager.FreeNodeTreeIfPossible(retval); + //call opcodes should consume the outer return opcode if there is one + if(result.IsNonNullNodeReference() && result->GetType() == ENT_RETURN) + result = RemoveTopConcludeOrReturnNode(result, &container->evaluableNodeManager); + + EvaluableNodeReference copied_result = evaluableNodeManager->DeepAllocCopy(result); + container->evaluableNodeManager.FreeNodeTreeIfPossible(result); if(_label_profiling_enabled) PerformanceProfiler::EndOperation(evaluableNodeManager->GetNumberOfUsedNodes()); diff --git a/src/Amalgam/out.txt b/src/Amalgam/out.txt index e8372bd0..a00f487e 100644 --- a/src/Amalgam/out.txt +++ b/src/Amalgam/out.txt @@ -171,6 +171,7 @@ notakeyword retrieve 0.1 retrieve_entity_root 0.01 retrieve_from_entity 0.5 + return 0.05 reverse 0.4 rewrite 0.1 round 0.6 @@ -234,11 +235,11 @@ notakeyword (print "hello") (list .nan .nan .infinity -.infinity) -(assoc b 2 a 1 c (list "alpha" "beta" "gamma")) +(assoc a 1 c (list "alpha" "beta" "gamma") b 2) (assoc - b 2 a 1 c (list "alpha" "beta" "gamma") + b 2 ) --if-- @@ -277,6 +278,8 @@ while1 success let1 success declare1 success 142 +--return-- +3 --declare-- 7 7 @@ -598,7 +601,7 @@ abcdef 0.14384103622589045 --first-- 4 -2 +1 1 0 a @@ -614,12 +617,12 @@ a (list) (assoc a 1 - b 2 + c 3 d 4 e 5 f 6 ) -(assoc d 4 e 5) +(assoc d 4 f 6) (assoc a 1 d 4 @@ -647,7 +650,7 @@ abcdef .nas --last-- this -2 +1 1 0 c @@ -663,12 +666,12 @@ c (list) (assoc a 1 - b 2 + c 3 d 4 e 5 f 6 ) -(assoc d 4 e 5) +(assoc d 4 f 6) (assoc a 1 d 4 @@ -1023,7 +1026,7 @@ abcdef (list 1 3) (list 9 5) --indices-- -(list "b" "a" "4" "c") +(list "a" "4" "c" "b") (list 0 1 @@ -1035,7 +1038,7 @@ abcdef 7 ) --values-- -(list 2 1 "d" 3) +(list 1 "d" 3 2) (list "a" 1 @@ -1056,7 +1059,7 @@ abcdef 4 "d" ) -(list 3 2 1 "d" 0) +(list 2 1 0 "d" 3) (list 1 2 @@ -1269,7 +1272,7 @@ current_index: 2 interpreter "C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" raaa 2 rwww 1 - start_time 1717624408.34827 + start_time 1717681823.48538 www 1 x 12 zz 10 @@ -1312,7 +1315,7 @@ current_index: 2 interpreter "C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" raaa 2 rwww 1 - start_time 1717624408.34827 + start_time 1717681823.48538 www 1 x 12 zz 10 @@ -1354,7 +1357,7 @@ current_index: 2 interpreter "C:\\Users\\ChristopherHazard\\Desktop\\Howso_repos\\amalgam\\x64\\MT_Release_EXE\\Amalgam.exe" raaa 2 rwww 1 - start_time 1717624408.34827 + start_time 1717681823.48538 www 1 x 12 zz 10 @@ -1487,22 +1490,22 @@ true --weighted_rand-- b -(list "b" "b" "b" "b") +(list "b" "b" "a" "b") b (list "a" "b" @(get (target 0) 0) @(get (target 0) 1)) (list "a" @(get (target 0) 0) "b" @(get (target 0) 2)) -infinity test c or d: (list "d" "d" "d" "c") +infinity test c or d: (list "c" "c" "c" "d") infinity test c or d: (list "c" @(get (target 0) 0) "d" @(get (target 0) 0)) -(assoc a 30 b 46 c 24) +(assoc a 25 b 45 c 30) (assoc a 29 b 44 c 27) -(list "3" "1" "10") +(list "6" "2" "1") --get_rand_seed-- °³È¼¿\¨KOaVÆT zÿ @@ -1549,8 +1552,8 @@ infinity test c or d: (list "c" @(get (target 0) 0) "d" @(get (target 0) 0)) string --set_type-- (- 3 4) -(list "b" 3 "a" 4) -(list "b" 3 "a" 4) +(list "a" 4 "b" 3) +(list "a" 4 "b" 3) (assoc a 4 b 3) 8.7 (parallel @@ -1601,8 +1604,7 @@ string ) 21: [{"b":4,"a":3},{"c":"c","d":null}] 22: [{"a":3,"b":4},{"c":"c","d":null}] -23: c: 3 -b: 2 +23: b: 2 a: 1 e: - a @@ -1610,6 +1612,7 @@ e: - .nan - .inf d: 4 +c: 3 24: a: 1 b: 2 @@ -1622,7 +1625,7 @@ e: - .inf 25: (assoc a 1) -current date-time in epoch: 2024-06-05-17.53.28.4507410 +current date-time in epoch: 2024-06-06-09.50.23.5360690 2020-06-07 00:22:59 1391230800 1391230800 @@ -1898,33 +1901,30 @@ decrypted: hello --mutate-- (list 1 - (parallel) - (+) + (floor) + (parse) 4 - (clone_entities) + (query_select) 6 7 8 9 10 11 - (if) - -3.6673445641690456 - 14 - (associate) + b + a + (declare) + (associate "a" 1) ) (list - 1 + (*) 2 - (+) - (+) - (associate) + 3 + (*) + (associate "alpha" 5 "beta" 6) (associate "nest" - (associate - "count" - (list 7 8 9) - ) + (associate "count" (list)) "end" (list 10 11 12) ) @@ -2167,16 +2167,6 @@ decrypted: hello (assoc _ (null)) (replace _ - (list) - (lambda - (assoc - a 2 - g (get - (current_value 1) - "g" - ) - ) - ) (list "g") (lambda (list @@ -2187,6 +2177,16 @@ decrypted: hello 4 ) ) + (list) + (lambda + (assoc + a 2 + g (get + (current_value 1) + "g" + ) + ) + ) ) ) (declare @@ -2361,15 +2361,7 @@ decrypted: hello ) ) --mix-- -(list - 2 - 3.5 - 5 - 7.5 - 9.5 - 11.5 - 13.5 -) +(list 3.5 5.5 7.5 9.5 11.5 13.5) (list ;comment 1 @@ -2377,9 +2369,9 @@ decrypted: hello ;comment 3 ;comment 4 1 - 4 - 5.5 - 7.5 + 3.5 + 5 + 8 9.5 11.5 13.5 @@ -2395,8 +2387,11 @@ decrypted: hello 1 (parallel (get_entity_comments) - 1 - (lambda (print)) + (lambda + (print + (list 2) + ) + ) ) ) ) @@ -2404,33 +2399,45 @@ decrypted: hello ) (list 1 + 5 2.5 (associate "a" 3 "b" 4) (lambda (if true 1 - (seq - (get_entity_comments) - (lambda - (print - (list 2 9) - ) - ) - 1 - ) + (seq (get_entity_comments) 1) ) ) + (list 5 6) +) +(list + 2 + 3.5 + 5.5 + 7.5 + 9.5 + 11.5 + 13.5 +) +(list + (true) + 4 + 5 + 8 + 7 + 10 + 11 + 14 + 13 ) -(list 3.5 5.5 7.5 9.5 11.5 13.5) -(list 5 8 10 12 11 13) -4 4 +1 2.5 2.5 -abcmxyz -abcmxyz abcdmxyz +abcemxyz +abcomxyz --mix_labels-- (list 1 @@ -2695,56 +2702,56 @@ flatten restore with parallel --mutate_entity-- (list 1 - 2 + (mix_labels) 3 + (acos) + a + (contains_label) 4 5 - a - 7 - 8 - (query_within_generalized_distance) - 10 - 11 + 9 + (<) + (abs) 12 - "b" - 14 - (associate "a" 1 (round) a) + 13 + 0.06646554813776002 + (associate "a" (get) "b" 2) ) (list - 1 - 2 - 3 - (abs) + (or) + 14 + b + (and) 5 - (log) - (values) - 17 - 9 + (query_sample) + 7 + 8 + (sin) 10 - (total_size) + 11 12 - "b" - (and) - (associate (let) 1 0.14034045403278178 (call)) + 13 + (zip) + (associate "a" (map) "b" (assign)) ) (list 1 - (*) - 3 (-) + 3 + 4 5 - 6 (+) + 7 8 - 9 - 10 (+) - 12 - 13 (+) - (associate "a" (*) "b" 2 (+)) + 11 + (-) + 13 + 14 + (associate "a" (*) "b" 2) ) --commonality_entities-- @@ -3153,14 +3160,8 @@ _432807187 (list) (lambda (assoc - E (get - (current_value 1) - "E" - ) - F (get - (current_value 1) - "F" - ) + E 3 + F 4 G 5 H 6 ) @@ -3185,16 +3186,7 @@ _432807187 _ (list) (lambda - (assoc - e (get - (current_value 1) - "e" - ) - f (get - (current_value 1) - "f" - ) - ) + (assoc e 3 f 4) ) ) ) @@ -3293,8 +3285,14 @@ _41032496 (list) (lambda (assoc - E 3 - F 4 + E (get + (current_value 1) + "E" + ) + F (get + (current_value 1) + "F" + ) G 5 H 6 ) @@ -3319,7 +3317,16 @@ _41032496 _ (list) (lambda - (assoc e 3 f 4) + (assoc + e (get + (current_value 1) + "e" + ) + f (get + (current_value 1) + "f" + ) + ) ) ) ) @@ -3349,34 +3356,12 @@ DiffContainerReconstructed (associate "b" 4 "a" 3) MergeEntityChild1 (associate "x" 3 "y" 4 "z" 5) -_523256902 -(null) +MergeEntityChild2 +(associate "p" 3 "q" 4 "u" 5) _3895405527 (associate "f" 4) -MergeEntityChild2 -(associate - "p" - 3 - "q" - 4 - "v" - 6 - "w" - 7 -) -_2280722175 -(associate "F" 4) -_2169689611 -(associate - "e" - 3 - "f" - 4 - "g" - 5 - "h" - 6 -) +_523256902 +(associate "E" 3 "H" 6) --get_entity_comments-- Full test This is a suite of unit tests. @@ -3454,7 +3439,7 @@ deep sets --set_entity_root_permission-- RootTest -1717624408.778388 +1717681823.823989 (true) RootTest @@ -3857,70 +3842,70 @@ store to .json normally (list "Child2" "Child7") (list "Child1" "Child5") (list "Child3" "Child4") -(list "Child1" "Child2" "Child3" "Child7") -(list "Child1" "Child2" "Child3" "Child4") +(list "Child2" "Child3" "Child4" "Child5") +(list "Child2" "Child3" "Child4" "Child7") (list "Child4" "Child6") --query_sample-- -(list "Child1") -(list "Child1" "Child5") -(list "Child2") +(list "Child4") +(list "Child1" "Child1") +(list "Child5") (list "Child1") --query_weighted_sample-- +(list "Child7") (list "Child1") -(list "Child2") (list - "Child1" - "Child2" - "Child2" "Child2" "Child1" "Child2" "Child1" "Child1" - "Child2" "Child1" - "Child2" - "Child2" + "Child5" + "Child1" + "Child1" "Child1" "Child1" "Child2" + "Child1" + "Child1" "Child2" "Child1" "Child2" "Child1" - "Child6" + "Child1" + "Child1" ) (list "Child2" "Child2" "Child2" "Child2" - "Child1" "Child2" - "Child7" - "Child1" - "Child1" + "Child6" "Child1" "Child2" - "Child1" - "Child1" - "Child3" + "Child4" + "Child2" + "Child2" "Child2" "Child1" + "Child4" + "Child2" "Child1" "Child2" + "Child1" "Child2" "Child1" ) (list - "Child2" - "Child3" "Child2" "Child2" + "Child3" "Child2" "Child2" - "Child4" + "Child5" "Child2" + "Child7" "Child2" "Child2" ) @@ -3972,19 +3957,19 @@ cascading query_not_in_entity_list: (list "Child6" "Child7") unweighted query: (assoc Child1 4 Child2 1 - Child4 100 + Child3 100 Child6 2 Child7 10 ) weighted query: (assoc Child1 1.8 Child2 0.45 - Child3 2 + Child4 2 Child6 0.04 Child7 0.2 ) weighted query list of lists: (list - (list "Child6" "Child7" "Child2" "Child1" "Child4") + (list "Child6" "Child7" "Child2" "Child1" "Child3") (list 0.04 0.2 0.45 1.8 2) ) weighted query list of lists: (list @@ -3993,7 +3978,7 @@ weighted query list of lists: (list (list -1 2 4 10 100) ) weighted query list of lists with multiple values: (list - (list "Child2" "Child6" "Child1" "Child7" "Child3") + (list "Child2" "Child6" "Child1" "Child7" "Child4") (list 1 2 4 10 100) (list -1 2 4 10 100) (list -1 1 3 0 100) @@ -4463,7 +4448,7 @@ a (list "hello" "!") (assoc a1 1.4142135623730951 a2 2 a3 1.4142135623730951) (assoc a1 1.4142135623730951 a3 1.4142135623730951) -(assoc a3 1.4142135623730951) +(assoc a1 1.4142135623730951) (assoc a1 5.0990195135927845 a2 2 a3 5.0990195135927845) (assoc a1 1 a3 1 a4 0) --accuracy tests-- @@ -4475,12 +4460,12 @@ distance symmetry tests (list (list "B" - "D" "C" - "I" - "F" "A" - "G" + "F" + "I" + "D" + "E" "H" ) (list @@ -4497,13 +4482,13 @@ distance symmetry tests (list (list "B" - "D" - "C" - "A" "I" + "A" + "D" "F" - "G" - "E" + "C" + "J" + "H" ) (list 0 @@ -4697,4 +4682,4 @@ concurrent entity writes successful: (true) --clean-up test files-- --total execution time-- -2.151479959487915 +1.9889349937438965