Block* find_first_common_block(Term* left, Term* right) { Block* leftParent = left->owningBlock; Block* rightParent = right->owningBlock; if (leftParent == NULL) return NULL; if (rightParent == NULL) return NULL; // Walk upwards from left term. while (leftParent != NULL) { // Walk upwards from right term. while (rightParent != NULL) { if (leftParent == rightParent) return leftParent; rightParent = get_parent_block(rightParent); } leftParent = get_parent_block(leftParent); rightParent = right->owningBlock; } return NULL; }
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; }
Block* get_parent_block_stackwise(Block* block) { block = get_parent_block(block); if (block != NULL && is_switch_block(block)) block = get_parent_block(block); return block; }
void UpwardIterator2::advanceWhileInvalid() { possibly_invalid: if (finished()) return; if (index < 0) { // Stop if we've finished the lastBlock. if (block == lastBlock) { block = NULL; return; } Block* previousBlock = block; block = get_parent_block(block); Term* parentTerm = parent_term(previousBlock); if (block == NULL || parentTerm == NULL) { block = NULL; return; } index = parentTerm->index - 1; goto possibly_invalid; } }
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* find_enclosing_module(Block* block) { while (true) { if (block == NULL) return NULL; if (is_module(block)) return block; block = get_parent_block(block); } }
Block* find_common_parent(Block* a, Block* b) { Block* parent = a; Block* searchBlock = b; while (parent != NULL) { searchBlock = b; while (searchBlock != NULL) { if (parent == searchBlock) return parent; searchBlock = get_parent_block(searchBlock); } parent = get_parent_block(parent); } return NULL; }
void Block__parent(VM* vm) { Block* block = as_block(vm->input(0)); if (block == NULL) { set_block(vm->output(), NULL); return; } set_block(vm->output(), get_parent_block(block)); }
bool block_is_child_of(Block* possibleChild, Block* possibleParent) { while (true) { possibleChild = get_parent_block(possibleChild); if (possibleChild == NULL) return false; if (possibleChild == possibleParent) return true; } }
bool name_is_reachable_from(Term* term, Block* block) { if (term->owningBlock == block) return true; Block* parent = get_parent_block(block); if (parent == NULL) return false; return name_is_reachable_from(term, parent); }
void Block__source_filename(VM* vm) { Block* block = as_block(vm->input(0)); while (block != NULL) { Value* filename = block_get_source_filename(block); if (filename != NULL) { copy(filename, vm->output()); return; } block = get_parent_block(block); } set_string(vm->output(), ""); }
Block* find_enclosing_loop(Block* block) { while (true) { if (block == NULL) return NULL; if (is_while_loop(block) || is_for_loop(block)) return block; if (is_major_block(block)) return NULL; block = get_parent_block(block); } return NULL; }
void get_source_file_location(Block* block, Value* out) { // Search upwards until we find a block that has source-file defined. while (block != NULL && block_get_source_filename(block) == NULL) block = get_parent_block(block); if (block == NULL) return set_string(out, ""); Value* sourceFilename = block_get_source_filename(block); if (sourceFilename == NULL) return set_string(out, ""); get_directory_for_filename(sourceFilename, out); }
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; } }
Term* run_name_search(NameSearch* params) { stat_increment(NameSearch); if (is_null(¶ms->name) || string_equals(¶ms->name, "")) return NULL; Block* block = params->block; if (block == NULL) return NULL; int position = 0; if (is_symbol(¶ms->position) && as_symbol(¶ms->position) == s_last) position = block->length(); else position = as_int(¶ms->position); if (position > block->length()) position = block->length(); // Look for an exact match. for (int i = position - 1; i >= 0; i--) { stat_increment(NameSearchStep); Term* term = block->get(i); if (term == NULL) continue; if (equals(&term->nameValue, ¶ms->name) && fits_lookup_type(term, params->lookupType) && (params->ordinal == -1 || term->uniqueOrdinal == params->ordinal)) return term; // If this term exposes its names, then search inside the nested block. // (Deprecated, I think). if (term->nestedContents != NULL && exposes_nested_names(term)) { NameSearch nestedSearch; nestedSearch.block = term->nestedContents; set_value(&nestedSearch.name, ¶ms->name); set_symbol(&nestedSearch.position, s_last); nestedSearch.ordinal = -1; nestedSearch.lookupType = params->lookupType; nestedSearch.searchParent = false; Term* found = run_name_search(&nestedSearch); if (found != NULL) return found; } #if 0 // Check for an 'import' statement. If found, continue this search in the designated module. if (term->function == FUNCS.require && term->boolProp(s_Syntax_Import, false)) { Block* module = find_module_for_require_statement(term); if (module != NULL) { NameSearch moduleSearch; moduleSearch.block = module; set_value(&moduleSearch.name, ¶ms->name); set_symbol(&moduleSearch.position, s_last); moduleSearch.ordinal = -1; moduleSearch.lookupType = params->lookupType; moduleSearch.searchParent = false; Term* found = run_name_search(&moduleSearch); if (found != NULL) return found; } } #endif } // Did not find in the local block. Possibly continue this search upwards. if (!params->searchParent) return NULL; // Possibly take this search to the builtins block. if ((get_parent_block(block) == NULL) || is_module(block)) { NameSearch builtinsSearch; builtinsSearch.block = find_builtins_block(block); set_value(&builtinsSearch.name, ¶ms->name); set_symbol(&builtinsSearch.position, s_last); builtinsSearch.lookupType = params->lookupType; builtinsSearch.ordinal = -1; builtinsSearch.searchParent = false; return run_name_search(&builtinsSearch); } // Search parent // The choice of position is a little weird. For regular name searches, // we start at the parent term's position (ie, search all the terms that // came before the parent). // // For a LookupFunction search, start at the bottom of the branch. It's okay // for a term to use a function that occurs after the term. NameSearch parentSearch; Term* parentTerm = block->owningTerm; if (parentTerm == NULL) return NULL; parentSearch.block = parentTerm->owningBlock; if (params->lookupType == s_LookupFunction) set_symbol(&parentSearch.position, s_last); else set_int(&parentSearch.position, parentTerm->index + 1); set_value(&parentSearch.name, ¶ms->name); parentSearch.lookupType = params->lookupType; parentSearch.ordinal = -1; parentSearch.searchParent = true; return run_name_search(&parentSearch); }