Пример #1
0
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;
}
Пример #2
0
// Returns true iff the given identifier corresponds to a fragment that is
// ready to be bound and hasn't already been bound.
static bool should_fragment_be_bound(binding_context_t *context, value_t schedule,
    value_t ident) {
  // This fragment is already scheduled so we definitely don't want to bind it
  // again.
  if (is_fragment_scheduled(schedule, ident))
    return false;
  // Grab the information we hold about the fragment.
  value_t path = get_identifier_path(ident);
  value_t stage = get_identifier_stage(ident);
  value_t module = get_id_hash_map_at(context->fragment_entry_map, path);
  value_t entry = get_id_hash_map_at(module, stage);
  value_t imports = get_fragment_entry_imports(entry);
  // Check whether all its explicit dependencies are satisfied.
  for (size_t i = 0; i < get_array_buffer_length(imports); i++) {
    value_t import = get_array_buffer_at(imports, i);
    if (!is_fragment_scheduled(schedule, import))
      return false;
  }
  // Check if there is a preceding fragment and whether it has been bound.
  value_t entry_before = get_fragment_entry_before(module, stage);
  if (in_condition_cause(ccNotFound, entry_before)) {
    return true;
  } else {
    value_t before_ident = get_fragment_entry_identifier(entry_before);
    return is_fragment_scheduled(schedule, before_ident);
  }
}
Пример #3
0
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;
}
Пример #4
0
// Creates and binds modules and fragments according to the given schedule.
static value_t execute_binding_schedule(binding_context_t *context, value_t schedule) {
  runtime_t *runtime = get_ambience_runtime(context->ambience);
  for (size_t i = 0; i < get_array_buffer_length(schedule); i++) {
    value_t next = get_array_buffer_at(schedule, i);
    TOPIC_INFO(Library, "About to bind %v", next);
    value_t path = get_identifier_path(next);
    value_t stage = get_identifier_stage(next);
    // Create the bound module if it doesn't already exist.
    value_t bound_module = get_id_hash_map_at(context->bound_module_map, path);
    if (in_condition_cause(ccNotFound, bound_module)) {
      TRY_SET(bound_module, new_heap_empty_module(runtime, path));
      TRY(set_id_hash_map_at(runtime, context->bound_module_map, path,
          bound_module));
    }
    // Create the bound fragment.
    value_t bound_fragment = get_module_fragment_at(bound_module, stage);
    if (in_condition_cause(ccNotFound, bound_fragment)) {
      TRY_SET(bound_fragment, new_empty_module_fragment(runtime, stage,
          bound_module));
      TRY(add_module_fragment(runtime, bound_module, bound_fragment));
    } else {
      // An earlier phase needed a reference to this fragment so it has already
      // been created but not initialized yet.
      CHECK_EQ("Unexpected phase", get_module_fragment_epoch(bound_fragment),
          feUninitialized);
      TRY(init_empty_module_fragment(runtime, bound_fragment));
      set_module_fragment_epoch(bound_fragment, feUnbound);
    }
    if (is_present_core(runtime, next)) {
      // TODO: this is a hack, there should be some other mechanism for
      //   identifying the core module. This way of binding it also means it
      //   gets bound at a time that's not particularly well-defined which is
      //   also an issue.
      TOPIC_INFO(Library, "Binding present core to %v", bound_fragment);
      set_ambience_present_core_fragment(context->ambience, bound_fragment);
    }
    // Grab the unbound fragment we'll use to create the bound fragment.
    value_t module_entries = get_id_hash_map_at(context->fragment_entry_map, path);
    value_t fragment_entry = get_id_hash_map_at(module_entries, stage);
    // Bind the fragment based on the data from the entry.
    TRY(bind_module_fragment(context, fragment_entry, bound_fragment));
    TOPIC_INFO(Library, "Done binding %v", next);
  }
  return success();
}
Пример #5
0
static value_t find_best_match(runtime_t *runtime, value_t current,
    value_t target, value_t current_score, value_t space, value_t *score_out) {
  if (value_identity_compare(current, target)) {
    *score_out = current_score;
    return success();
  } else {
    TRY_DEF(parents, get_type_parents(runtime, space, current));
    int64_t length = get_array_buffer_length(parents);
    value_t score = new_no_match_score();
    for (int64_t i = 0; i < length; i++) {
      value_t parent = get_array_buffer_at(parents, i);
      value_t next_score = whatever();
      TRY(find_best_match(runtime, parent, target, get_score_successor(current_score),
          space, &next_score));
      score = best_score(score, next_score);
    }
    *score_out = score;
    return success();
  }
}
Пример #6
0
// Adds mappings in the namespace and imports in the methodspace for everything
// imported by the given fragment.
static value_t bind_module_fragment_imports(binding_context_t *context,
    value_t imports, value_t bound_fragment) {
  // Import the modules spaces into this fragment and create bindings in the
  // importspace.
  value_t methodspace = get_module_fragment_methodspace(bound_fragment);
  value_t importspace = get_module_fragment_imports(bound_fragment);
  runtime_t *runtime = get_ambience_runtime(context->ambience);
  for (size_t i = 0; i < get_array_buffer_length(imports); i++) {
    // Look up the imported module.
    value_t import_ident = get_array_buffer_at(imports, i);
    value_t import_path = get_identifier_path(import_ident);
    value_t import_head = get_path_head(import_path);
    value_t import_stage = get_identifier_stage(import_ident);
    value_t import_module = get_id_hash_map_at(context->bound_module_map, import_path);
    value_t import_fragment = get_module_fragment_at(import_module, import_stage);
    CHECK_TRUE("import not bound", is_module_fragment_bound(import_fragment));
    value_t import_methods = get_module_fragment_methodspace(import_fragment);
    TRY(add_methodspace_import(runtime, methodspace, import_methods));
    TRY(set_id_hash_map_at(runtime, importspace, import_head,
        import_fragment));
  }
  return success();
}
Пример #7
0
// Given an array of modules map builds a two-level map from paths to stages to
// fragment entries.
static value_t build_real_fragment_entries(binding_context_t *context,
    value_t modules) {
  runtime_t *runtime = get_ambience_runtime(context->ambience);
  for (size_t mi = 0; mi < get_array_buffer_length(modules); mi++) {
    value_t module = get_array_buffer_at(modules, mi);
    value_t path = get_unbound_module_path(module);
    value_t fragments = get_unbound_module_fragments(module);
    for (size_t fi = 0; fi < get_array_length(fragments); fi++) {
      value_t fragment = get_array_at(fragments, fi);
      value_t stage = get_unbound_module_fragment_stage(fragment);
      bool dummy = false;
      TRY_DEF(entry, binding_context_ensure_fragment_entry(context, stage,
          path, fragment, &dummy));
      value_t imports = get_fragment_entry_imports(entry);
      value_t fragment_imports = get_unbound_module_fragment_imports(fragment);
      for (size_t ii = 0; ii < get_array_length(fragment_imports); ii++) {
        value_t import = get_array_at(fragment_imports, ii);
        TRY_DEF(ident, new_heap_identifier(runtime, present_stage(), import));
        TRY(ensure_array_buffer_contains(runtime, imports, ident));
      }
    }
  }
  return success();
}
Пример #8
0
// Add synthetic fragment entries corresponding to imported fragments where
// there is no real fragment to import the fragment into.
static value_t build_synthetic_fragment_entries(binding_context_t *context) {
  // Keep adding synthetic modules as long as changes are being made to the
  // map. We'll scan through the fragments currently in the map, then scan
  // through their imports, and for each check that the fragment that should
  // receive the import exists. If it doesn't it is created.
  loop: do {
    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 unbound_fragment = get_fragment_entry_fragment(entry);
        // If there is no fragment associated with this entry it is synthetic
        // and hence we're done.
        if (is_nothing(unbound_fragment))
          continue;
        // Scan through the fragment's imports and ensure that their import
        // targets have been created.
        value_t imports = get_fragment_entry_imports(entry);
        for (size_t i = 0; i < get_array_buffer_length(imports); i++) {
          value_t import = get_array_buffer_at(imports, i);
          value_t import_fragment_stage = get_identifier_stage(import);
          if (!value_identity_compare(import_fragment_stage, present_stage()))
            // We'll record past imports but ignore them for the purposes of
            // closing the import map since they're redundant.
            continue;
          value_t import_module_path = get_identifier_path(import);
          value_t import_module = get_id_hash_map_at(context->fragment_entry_map,
              import_module_path);
          // Scan through the fragments of the imported module.
          id_hash_map_iter_t imported_fragment_iter;
          id_hash_map_iter_init(&imported_fragment_iter, import_module);
          bool has_changed_anything = false;
          while (id_hash_map_iter_advance(&imported_fragment_iter)) {
            value_t import_stage;
            value_t import_entry;
            id_hash_map_iter_get_current(&imported_fragment_iter,
                &import_stage, &import_entry);
            value_t target_stage = add_stage_offsets(import_stage, stage);
            // Ensure that there is a target entry to add the import to. If it
            // already exists this is a no-op, if it doesn't a synthetic entry
            // is created.
            TRY_DEF(target_entry, binding_context_ensure_fragment_entry(
                context, target_stage, module_path, nothing(),
                &has_changed_anything));
           value_t target_imports = get_fragment_entry_imports(target_entry);
           value_t import_ident = get_fragment_entry_identifier(import_entry);
            if (!in_array_buffer(target_imports, import_ident)) {
              has_changed_anything = true;
              TRY(add_to_array_buffer(get_ambience_runtime(context->ambience),
                  target_imports, import_ident));
            }
          }
          // If any changes were made we have to start over.
          if (has_changed_anything)
            goto loop;
        }
      }
    }
  } while (false);
  return success();
}