void module_always_has_primary_output() { test_write_fake_file("module.ca", 1, "1"); Block block; load_script(&block, "module.ca"); test_assert(get_output_placeholder(&block, 0) != NULL); test_assert(get_output_placeholder(&block, 0)->input(0) == NULL); }
void for_loop_remake_zero_branch(Branch* forContents) { Branch* zero = for_loop_get_zero_branch(forContents); clear_branch(zero); // Clone inputs for (int i=0;; i++) { Term* placeholder = get_input_placeholder(forContents, i); if (placeholder == NULL) break; Term* clone = append_input_placeholder(zero); rename(clone, placeholder->nameSymbol); } Term* loopOutput = create_list(zero); // Clone outputs for (int i=0;; i++) { Term* placeholder = get_output_placeholder(forContents, i); if (placeholder == NULL) break; // Find the appropriate connection Term* result = find_local_name(zero, placeholder->name.c_str()); if (i == 0) result = loopOutput; Term* clone = append_output_placeholder(zero, result); rename(clone, placeholder->nameSymbol); } branch_finish_changes(zero); }
void load_script(Block* block, const char* filename) { // Store the filename set_string(block_insert_property(block, s_filename), filename); // Read the text file circa::Value contents; circa_read_file(block->world, filename, &contents); if (is_null(&contents)) { Value msg; set_string(&msg, "File not found: "); string_append(&msg, filename); Term* term = create_string(block, as_cstring(&msg)); apply(block, FUNCS.error, TermList(term)); return; } parse(block, parse_statement_list, &contents); // Make sure the block has a primary output. if (get_output_placeholder(block, 0) == NULL) append_output_placeholder(block, NULL); update_static_error_list(block); return; }
void finish_if_block(Term* ifBlock) { Branch* contents = nested_contents(ifBlock); // Make sure there is a primary output if (get_output_placeholder(contents, 0) == NULL) if_block_prepend_primary_output(ifBlock); if_block_normalize_state_inputs(ifBlock); int caseIndex = 0; for (CaseIterator it(contents); it.unfinished(); it.advance()) { Term* term = it.current(); if_block_turn_outer_name_rebinds_into_outputs(ifBlock, nested_contents(term)); if_block_fix_outer_pointers(ifBlock, nested_contents(term)); modify_branch_so_that_state_access_is_indexed(nested_contents(term), caseIndex); caseIndex++; } if_block_turn_common_rebinds_into_outputs(ifBlock); if_block_update_output_placeholder_types_from_cases(ifBlock); check_to_insert_implicit_inputs(ifBlock); update_extra_outputs(ifBlock); }
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 loop_update_continue_inputs(Branch* branch, Term* continueTerm) { for (int i=0;; i++) { Term* output = get_output_placeholder(branch, i); if (output == NULL) break; set_input(continueTerm, i, find_intermediate_result_for_output(continueTerm, output)); } }
void load_script_from_text(Block* block, const char* text) { parse(block, parse_statement_list, text); // Make sure the block has a primary output. if (get_output_placeholder(block, 0) == NULL) append_output_placeholder(block, NULL); update_static_error_list(block); }
void Block__outputs(VM* vm) { Block* block = as_block(vm->input(0)); Value* output = vm->output(); set_list(output, 0); for (int i=0;; i++) { Term* term = get_output_placeholder(block, i); if (term == NULL) break; set_term_ref(list_append(output), term); } }
void Branch__outputs(caStack* stack) { Branch* branch = as_branch(circa_input(stack, 0)); caValue* output = circa_output(stack, 0); set_list(output, 0); for (int i=0;; i++) { Term* term = get_output_placeholder(branch, i); if (term == NULL) break; set_term_ref(list_append(output), term); } }
Type* get_output_type(Block* block, int index) { if (block == NULL) return TYPES.any; // If there's no output_placeholder, then we are probably still building this // function. Term* placeholder = get_output_placeholder(block, index); if (placeholder == NULL) return TYPES.any; return placeholder->type; }
void if_block_update_output_placeholder_types_from_cases(Term* ifBlock) { Branch* masterContents = nested_contents(ifBlock); for (int outputIndex=0;; outputIndex++) { Term* masterPlaceholder = get_output_placeholder(masterContents, outputIndex); if (masterPlaceholder == NULL) return; List types; // Iterate through each case, and collect the output types for (int i=0; i < masterContents->length(); i++) { Term* term = masterContents->get(i); if (term->function != FUNCS.case_func) continue; Term* placeholder = get_output_placeholder(nested_contents(term), outputIndex); set_type(types.append(), placeholder->type); } change_declared_type(masterPlaceholder, find_common_type(&types)); } }
Term* if_block_add_output_for_name(Term* ifCall, const char* name) { // Fix the new output placeholders to have the correct name and input. Branch* mainBranch = nested_contents(ifCall); int outputCount = count_output_placeholders(mainBranch); Term* outputPlaceholder = if_block_append_output(ifCall); rename(outputPlaceholder, name); for (CaseIterator it(mainBranch); it.unfinished(); it.advance()) { Branch* caseContents = nested_contents(it.current()); Term* casePlaceholder = get_output_placeholder(caseContents, outputCount); ca_assert(casePlaceholder != NULL); ca_assert(casePlaceholder->name == ""); rename(casePlaceholder, name); set_input(casePlaceholder, 0, find_name_at(casePlaceholder, name)); respecialize_type(casePlaceholder); } return outputPlaceholder; }
void update_derived_inputs_for_exit_point(Term* term) { // Make sure that this exit point includes every block output as an input. // The intermediate value might be different at this location. Block* block = find_block_that_exit_point_will_reach(term); for (int i=0;; i++) { Term* inputResult = get_output_placeholder(block, i); if (inputResult == NULL) break; // Don't touch input if it's explicit. if (i < term->numInputs() && !is_input_implicit(term, i)) continue; Term* intermediateValue = find_intermediate_result_for_output(term, inputResult); set_input(term, i, intermediateValue); set_input_implicit(term, i, true); set_input_hidden(term, i, true); } }
void if_block_post_setup(Term* ifCall) { Branch* contents = nested_contents(ifCall); if (get_output_placeholder(contents, 0) == NULL) apply(contents, FUNCS.output, TermList(NULL)); }
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; }
void Branch__output(caStack* stack) { Branch* branch = as_branch(circa_input(stack, 0)); set_term_ref(circa_output(stack, 0), get_output_placeholder(branch, circa_int_input(stack, 1))); }
void Block__output_placeholder(VM* vm) { Block* block = as_block(vm->input(0)); Term* placeholder = get_output_placeholder(block, vm->input(1)->as_i()); set_term_ref(vm->output(), placeholder); }