void for_loop_finish_iteration(Stack* context) { Frame* frame = top_frame(context); Branch* contents = frame->branch; // Find list length caValue* listInput = get_frame_register(frame, 0); // Increment the loop index caValue* index = get_frame_register(frame, for_loop_find_index(contents)->index); set_int(index, as_int(index) + 1); // Check if we are finished if (as_int(index) >= list_length(listInput)) { frame->loop = false; finish_frame(context); return; } // If we're not finished yet, copy rebound outputs back to inputs. for (int i=1;; i++) { Term* input = get_input_placeholder(contents, i); if (input == NULL) break; Term* output = get_output_placeholder(contents, i); copy(get_frame_register(frame, output->index), get_frame_register(frame, input->index)); } // Return to start of loop body frame->pc = 0; frame->nextPc = 0; }
void index_func_postCompile(Term* term) { Term* enclosingLoop = find_enclosing_for_loop(term); if (enclosingLoop == NULL) return; Term* loop_index = for_loop_find_index(nested_contents(enclosingLoop)); if (loop_index == NULL) return; set_input(term, 0, loop_index); set_input_hidden(term, 0, true); }
void for_loop_fix_state_input(Branch* contents) { // This function will look at the state access inside for-loop contents. // If there's state, the default building functions will have created // terms that look like this: // // input() :state -> unpack_state -> pack_state -> output() :state // // We want each loop iteration to have its own state container. So we'll // insert pack/unpack_state_list_n terms so that each iteration accesses // state from a list. The result will look like: // // input() :state -> unpack_state_list_n(index) -> unpack_state -> pack_state // -> pack_state_list_n(index) -> output() :state // First insert the unpack_state_list_n call Term* stateInput = find_state_input(contents); // Nothing to do if there's no state input if (stateInput == NULL) return; // Nothing to do if unpack_state_list_n term already exists if (find_user_with_function(stateInput, FUNCS.unpack_state_list_n) != NULL) return; Term* unpackState = find_user_with_function(stateInput, FUNCS.unpack_state); ca_assert(unpackState != NULL); Term* index = for_loop_find_index(contents); Term* unpackStateList = apply(contents, FUNCS.unpack_state_list_n, TermList(stateInput, index)); transfer_users(stateInput, unpackStateList); move_before(unpackStateList, unpackState); set_input(unpackState, 0, unpackStateList); // Now insert the pack_state_list_n call Term* stateResult = find_open_state_result(contents, contents->length()); Term* packStateList = apply(contents, FUNCS.pack_state_list_n, TermList(stateInput, stateResult, index)); packStateList->setBoolProp("final", true); move_after(packStateList, stateResult); // Make sure the state output uses this result Term* stateOutput = append_state_output(contents); set_input(stateOutput, 0, packStateList); }
void start_for_loop(caStack* stack, bool enableLoopOutput) { Frame* frame = top_frame(stack); Branch* contents = frame->branch; // Check if top frame actually contains a for-loop (it might be using the #zero branch) if (!is_for_loop(contents)) return; // Initialize the loop index set_int(get_frame_register(frame, for_loop_find_index(contents)), 0); if (enableLoopOutput) { // Initialize output value set_int(get_frame_register(frame, for_loop_find_output_index(contents)), 0); caValue* listInput = circa_input(stack, 0); set_list(get_frame_register_from_end(frame, 0), list_length(listInput)); } // Interpreter will run the contents of the branch }
void for_loop_finish_iteration(Stack* stack, bool enableLoopOutput) { INCREMENT_STAT(LoopFinishIteration); Frame* frame = top_frame(stack); Branch* contents = frame->branch; // Find list length caValue* listInput = get_frame_register(frame, 0); // Increment the loop index caValue* index = get_top_register(stack, for_loop_find_index(contents)); set_int(index, as_int(index) + 1); // Preserve list output if (enableLoopOutput && frame->exitType != name_Discard) { caValue* outputIndex = get_frame_register(frame, for_loop_find_output_index(contents)); Term* outputPlaceholder = get_output_placeholder(contents, 0); caValue* outputList = get_frame_register(frame, outputPlaceholder); caValue* outputValue = find_stack_value_for_term(stack, outputPlaceholder->input(0), 0); if (!is_list(outputList)) set_list(outputList); list_touch(outputList); copy(outputValue, list_get(outputList, as_int(outputIndex))); INCREMENT_STAT(LoopWriteOutput); // Advance output index set_int(outputIndex, as_int(outputIndex) + 1); } // Check if we are finished if (as_int(index) >= list_length(listInput) || frame->exitType == name_Break || frame->exitType == name_Return) { // Possibly truncate output list, in case any elements were discarded. if (enableLoopOutput) { caValue* outputIndex = get_frame_register(frame, for_loop_find_output_index(contents)); Term* outputPlaceholder = get_output_placeholder(contents, 0); caValue* outputList = get_frame_register(frame, outputPlaceholder); list_resize(outputList, as_int(outputIndex)); } else { Term* outputPlaceholder = get_output_placeholder(contents, 0); caValue* outputList = get_frame_register(frame, outputPlaceholder); set_list(outputList, 0); } finish_frame(stack); return; } // If we're not finished yet, copy rebound outputs back to inputs. for (int i=1;; i++) { Term* input = get_input_placeholder(contents, i); if (input == NULL) break; Term* output = get_output_placeholder(contents, i); copy(get_frame_register(frame, output), get_frame_register(frame, input)); INCREMENT_STAT(Copy_LoopCopyRebound); } // Return to start of loop body frame->pc = 0; frame->nextPc = 0; frame->exitType = name_None; }