コード例 #1
0
ファイル: bind.c プロジェクト: plesner/neutrino
// 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);
  }
}
コード例 #2
0
ファイル: bind.c プロジェクト: plesner/neutrino
value_t module_loader_lookup_module(value_t self, value_t path) {
  value_t modules = get_module_loader_modules(self);
  value_t result = get_id_hash_map_at(modules, path);
  if (in_condition_cause(ccNotFound, result))
    WARN("Module %v not found.", path);
  return result;
}
コード例 #3
0
ファイル: bind.c プロジェクト: plesner/neutrino
// 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();
}
コード例 #4
0
ファイル: method.c プロジェクト: tundra/neutrino
value_t get_type_parents(runtime_t *runtime, value_t space, value_t type) {
  value_t inheritance = get_methodspace_inheritance(space);
  value_t parents = get_id_hash_map_at(inheritance, type);
  if (in_condition_cause(ccNotFound, parents)) {
    return ROOT(runtime, empty_array_buffer);
  } else {
    return parents;
  }
}
コード例 #5
0
ファイル: behavior.c プロジェクト: tundra/neutrino
static value_t new_instance_of_string(runtime_t *runtime, value_t type) {
  value_t factories = ROOT(runtime, plankton_factories);
  value_t factory = get_id_hash_map_at(factories, type);
  if (in_family(ofFactory, factory)) {
    value_t new_instance_wrapper = get_factory_new_instance(factory);
    void *new_instance_ptr = get_void_p_value(new_instance_wrapper);
    factory_new_instance_t *new_instance = (factory_new_instance_t*) (intptr_t) new_instance_ptr;
    return new_instance(runtime);
  } else {
    return new_heap_seed(runtime, type, nothing());
  }
}
コード例 #6
0
ファイル: bind.c プロジェクト: plesner/neutrino
// 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);
}
コード例 #7
0
ファイル: behavior.c プロジェクト: tundra/neutrino
static value_t set_heap_object_contents_with_utf8_type(runtime_t *runtime,
    value_t object, value_t header, value_t payload) {
  value_t factories = ROOT(runtime, plankton_factories);
  value_t factory = get_id_hash_map_at(factories, header);
  if (in_family(ofFactory, factory)) {
    value_t set_contents_wrapper = get_factory_set_contents(factory);
    void *set_contents_ptr = get_void_p_value(set_contents_wrapper);
    factory_set_contents_t *set_contents = (factory_set_contents_t*) (intptr_t) set_contents_ptr;
    return set_contents(object, runtime, payload);
  } else {
    set_seed_payload(object, payload);
    return success();
  }
}
コード例 #8
0
ファイル: codegen.c プロジェクト: plesner/neutrino
// Performs a lookup for a single symbol scope.
static value_t map_scope_lookup(map_scope_o *self, value_t symbol,
    binding_info_t *info_out) {
  value_t value = get_id_hash_map_at(self->map, symbol);
  if (in_condition_cause(ccNotFound, value)) {
    return scope_lookup(self->outer, symbol, info_out);
  } else {
    if (info_out != NULL) {
      binding_info_codec_t codec;
      codec.encoded = get_integer_value(value);
      *info_out = codec.decoded;
    }
    return success();
  }
}
コード例 #9
0
ファイル: bind.c プロジェクト: plesner/neutrino
value_t build_bound_module(value_t ambience, value_t unbound_module) {
  runtime_t *runtime = get_ambience_runtime(ambience);
  binding_context_t context;
  binding_context_init(&context, ambience);
  TRY_SET(context.bound_module_map, new_heap_id_hash_map(runtime, 16));
  TRY_DEF(modules, build_transitive_module_array(runtime, unbound_module));
  TRY(build_fragment_entry_map(&context, modules));
  TRY_DEF(schedule, build_binding_schedule(&context));
  TRY(execute_binding_schedule(&context, schedule));
  value_t path = get_unbound_module_path(unbound_module);
  value_t result = get_id_hash_map_at(context.bound_module_map, path);
  CHECK_FALSE("module missing", in_condition_cause(ccNotFound, result));
  return result;
}
コード例 #10
0
ファイル: method.c プロジェクト: tundra/neutrino
value_t get_or_create_methodspace_selector_slice(runtime_t *runtime, value_t self,
    value_t selector) {
  value_t cache_ptr = get_methodspace_cache_ptr(self);
  value_t cache = get_freeze_cheat_value(cache_ptr);
  // Create the cache if it doesn't exist.
  if (is_nothing(cache)) {
    TRY_SET(cache, new_heap_id_hash_map(runtime, 128));
    set_freeze_cheat_value(cache_ptr, cache);
  }
  // Create the selector-specific cache if it doesn't exits.
  value_t slice = get_id_hash_map_at(cache, selector);
  if (in_condition_cause(ccNotFound, slice)) {
    TRY_SET(slice, create_methodspace_selector_slice(runtime, self, selector));
    TRY(set_id_hash_map_at(runtime, cache, selector, slice));
  }
  return slice;
}
コード例 #11
0
ファイル: method.c プロジェクト: tundra/neutrino
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);
}
コード例 #12
0
ファイル: bind.c プロジェクト: plesner/neutrino
// 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();
}
コード例 #13
0
ファイル: bind.c プロジェクト: plesner/neutrino
// 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();
}