Block* find_block_that_exit_point_will_reach(Term* term) { ca_assert(is_exit_point(term)); Block* block = term->owningBlock; // 'return' exits to nearest major block. if (term->function == FUNCS.return_func) { while (is_minor_block(block)) { Block* parent = get_parent_block(block); if (parent == NULL) return block; block = parent; } return block; } // 'case_condition_bool' exits the current if-block. if (term->function == FUNCS.case_condition_bool) return get_parent_block(term->owningBlock); // Otherwise, exit to nearest for-loop. while (!is_for_loop(block) && !is_while_loop(block)) { Block* parent = get_parent_block(block); if (parent == NULL) return block; block = parent; } return block; }
void MinorBlockIterator::advance() { Block* nextNested = current()->nestedContents; if (nextNested != NULL && !is_minor_block(nextNested)) it.advanceSkippingBlock(); else it.advance(); }
void create_output_from_minor_block(Block* block, Value* description) { if (is_case_block(block)) { Block* ifBlock = get_parent_block(block); if_block_append_output(ifBlock, description); } else if (is_minor_block(block)) { append_output_placeholder_with_description(block, description); } }
Block* static_dispatch_block(Term* term) { if (term->nestedContents != NULL && is_minor_block(term->nestedContents)) return term->nestedContents; if (term->function == NULL || !is_function(term->function)) return NULL; ca_assert(term->function->nestedContents != NULL); return term->function->nestedContents; }
void block_update_pack_state_calls(Block* block) { if (block->stateType == NULL) { // No state type, make sure there's no pack_state call. // TODO: Handle this case properly (should search and destroy an existing pack_state call) return; } int stateOutputIndex = block->length() - 1 - find_state_output(block)->index; for (int i=0; i < block->length(); i++) { Term* term = block->get(i); if (term == NULL) continue; if (term->function == FUNCS.pack_state) { // Update the inputs for this pack_state call TermList inputs; list_inputs_to_pack_state(block, i, &inputs); set_inputs(term, inputs); } else if (should_have_preceeding_pack_state(term)) { // Check if we need to insert a pack_state call Term* existing = term->input(stateOutputIndex); if (existing == NULL || existing->function != FUNCS.pack_state) { TermList inputs; list_inputs_to_pack_state(block, i, &inputs); if (inputs.length() != 0) { Term* pack_state = apply(block, FUNCS.pack_state, inputs); move_before(pack_state, term); // Only set as an input for a non-minor block. if (term->nestedContents == NULL || !is_minor_block(term->nestedContents)) { set_input(term, stateOutputIndex, pack_state); set_input_hidden(term, stateOutputIndex, true); set_input_implicit(term, stateOutputIndex, true); } // Advance i to compensate for the term just added i++; } } } } }
void controlFlow_postCompile(Term* term) { // Mark the owning block, and all parent minor blocks, as hasControlFlow. Block* block = term->owningBlock; while (true) { set_bool(block_insert_property(block, s_HasControlFlow), true); if (!is_minor_block(block)) break; block = get_parent_block(block); if (block == NULL) break; } }
void update_for_control_flow(Block* block) { if (!block_get_bool_prop(block, s_HasControlFlow, false)) return; for (int i=0; i < block->length(); i++) { Term* term = block->get(i); if (term == NULL) continue; if (is_exit_point_that_handles_rebinding(term)) update_derived_inputs_for_exit_point(term); Block* nestedBlock = term->nestedContents; if (nestedBlock != NULL && is_minor_block(nestedBlock)) update_for_control_flow(nestedBlock); } }