static value_t lambda_scope_lookup(lambda_scope_o *self, value_t symbol, binding_info_t *info_out) { size_t capture_count_before = get_array_buffer_length(self->captures); // See if we've captured this variable before. for (size_t i = 0; i < capture_count_before; i++) { value_t captured = get_array_buffer_at(self->captures, i); if (value_identity_compare(captured, symbol)) { // Found it. Record that we did if necessary and return success. if (info_out != NULL) binding_info_set(info_out, btLambdaCaptured, i, 0); return success(); } } // We haven't seen this one before so look it up outside. value_t value = scope_lookup(self->outer, symbol, info_out); if (info_out != NULL && !in_condition_cause(ccNotFound, value)) { // We found something and this is a read. Add it to the list of captures. runtime_t *runtime = self->assembler->runtime; if (get_array_buffer_length(self->captures) == 0) { // The first time we add something we have to create a new array buffer // since all empty capture scopes share the singleton empty buffer. TRY_SET(self->captures, new_heap_array_buffer(runtime, 2)); } TRY(add_to_array_buffer(runtime, self->captures, symbol)); binding_info_set(info_out, btLambdaCaptured, capture_count_before, 0); } return value; }
// Builds an array buffer containing all the modules that are needed to load // the given unbound module (which is itself added to the array too). static value_t build_transitive_module_array(runtime_t *runtime, value_t unbound_module) { CHECK_FAMILY(ofUnboundModule, unbound_module); TRY_DEF(result, new_heap_array_buffer(runtime, 16)); TRY(ensure_module_in_array(runtime, result, unbound_module)); return result; }
value_t build_binding_schedule(binding_context_t *context) { runtime_t *runtime = get_ambience_runtime(context->ambience); TRY_DEF(schedule, new_heap_array_buffer(runtime, 16)); TRY_DEF(all_fragments, build_fragment_identifier_array(context)); loop: do { for (size_t i = 0; i < get_array_buffer_length(all_fragments); i++) { value_t ident = get_array_buffer_at(all_fragments, i); if (should_fragment_be_bound(context, schedule, ident)) { TRY(add_to_array_buffer(runtime, schedule, ident)); goto loop; } } } while (false); return schedule; }
value_t add_methodspace_inheritance(runtime_t *runtime, value_t self, value_t subtype, value_t supertype) { CHECK_FAMILY(ofMethodspace, self); CHECK_MUTABLE(self); CHECK_FAMILY(ofType, subtype); CHECK_FAMILY(ofType, supertype); value_t inheritance = get_methodspace_inheritance(self); value_t parents = get_id_hash_map_at(inheritance, subtype); if (in_condition_cause(ccNotFound, parents)) { // Make the parents buffer small since most types don't have many direct // parents. If this fails nothing has happened. TRY_SET(parents, new_heap_array_buffer(runtime, 4)); // If this fails we've wasted some space allocating the parents array but // otherwise nothing has happened. TRY(set_id_hash_map_at(runtime, inheritance, subtype, parents)); } // If this fails we may have set the parents array of the subtype to an empty // array which is awkward but okay. invalidate_methodspace_caches(self); return add_to_array_buffer(runtime, parents, supertype); }
// Checks whether a fragment entry for the given stage and path already exists // and if not creates it. static value_t binding_context_ensure_fragment_entry(binding_context_t *context, value_t stage, value_t path, value_t fragment, bool *created) { CHECK_PHYLUM(tpStageOffset, stage); CHECK_FAMILY(ofPath, path); CHECK_FAMILY_OPT(ofUnboundModuleFragment, fragment); value_t path_map = context->fragment_entry_map; runtime_t *runtime = get_ambience_runtime(context->ambience); if (!has_id_hash_map_at(path_map, path)) { TRY_DEF(stage_map, new_heap_id_hash_map(runtime, 16)); TRY(set_id_hash_map_at(runtime, path_map, path, stage_map)); } value_t stage_map = get_id_hash_map_at(path_map, path); if (!has_id_hash_map_at(stage_map, stage)) { TRY_DEF(imports, new_heap_array_buffer(runtime, 4)); TRY_DEF(ident, new_heap_identifier(runtime, stage, path)); TRY_DEF(entry, new_heap_triple(runtime, fragment, imports, ident)); TRY(set_id_hash_map_at(runtime, stage_map, stage, entry)); *created = true; } return get_id_hash_map_at(stage_map, stage); }
// Uses the fragment entry map to create an array of identifiers for all the // fragments, synthetic and real. static value_t build_fragment_identifier_array(binding_context_t *context) { runtime_t *runtime = get_ambience_runtime(context->ambience); TRY_DEF(result, new_heap_array_buffer(runtime, 16)); id_hash_map_iter_t module_iter; id_hash_map_iter_init(&module_iter, context->fragment_entry_map); while (id_hash_map_iter_advance(&module_iter)) { value_t module_path; value_t module_fragments; // Scan through the fragments. id_hash_map_iter_get_current(&module_iter, &module_path, &module_fragments); id_hash_map_iter_t fragment_iter; id_hash_map_iter_init(&fragment_iter, module_fragments); while (id_hash_map_iter_advance(&fragment_iter)) { value_t stage; value_t entry; id_hash_map_iter_get_current(&fragment_iter, &stage, &entry); value_t ident = get_fragment_entry_identifier(entry); TRY(add_to_array_buffer(runtime, result, ident)); } } sort_array_buffer(result); return result; }