Exemplo n.º 1
0
static char*
S_full_method_sym(CFCMethod *self, CFCClass *invoker, const char *postfix) {
    const char *PREFIX;
    const char *cnick;
    if (invoker) {
        PREFIX = CFCClass_get_PREFIX(invoker);
        cnick  = CFCClass_get_cnick(invoker);
    }
    else {
        PREFIX = CFCMethod_get_PREFIX(self);
        cnick  = CFCMethod_get_class_cnick(self);
    }
    return CFCUtil_sprintf("%s%s_%s%s", PREFIX, cnick, self->macro_sym,
                           postfix);
}
Exemplo n.º 2
0
static char*
S_virtual_method_def(CFCMethod *method, CFCClass *klass) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *PREFIX         = CFCClass_get_PREFIX(klass);
    const char *invoker_struct = CFCClass_full_struct_sym(klass);

    char *full_meth_sym   = CFCMethod_full_method_sym(method, klass);
    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
    char *full_typedef    = CFCMethod_full_typedef(method, klass);

    // Prepare parameter lists, minus invoker.  The invoker gets forced to
    // "self" later.
    if (CFCParamList_variadic(param_list)) {
        CFCUtil_die("Variadic methods not supported");
    }
    const char *arg_names_minus_invoker = CFCParamList_name_list(param_list);
    const char *params_minus_invoker    = CFCParamList_to_c(param_list);
    while (*arg_names_minus_invoker && *arg_names_minus_invoker != ',') {
        arg_names_minus_invoker++;
    }
    while (*params_minus_invoker && *params_minus_invoker != ',') {
        params_minus_invoker++;
    }

    // Prepare a return statement... or not.
    CFCType *return_type = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *maybe_return = CFCType_is_void(return_type) ? "" : "return ";

    const char pattern[] =
        "extern %sVISIBLE size_t %s;\n"
        "static CFISH_INLINE %s\n"
        "%s(%s *self%s) {\n"
        "    const %s method = (%s)cfish_obj_method(self, %s);\n"
        "    %smethod(self%s);\n"
        "}\n";
    char *method_def
        = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str,
                          full_meth_sym, invoker_struct, params_minus_invoker,
                          full_typedef, full_typedef, full_offset_sym,
                          maybe_return, arg_names_minus_invoker);

    FREEMEM(full_offset_sym);
    FREEMEM(full_meth_sym);
    FREEMEM(full_typedef);
    return method_def;
}
Exemplo n.º 3
0
static char*
S_method_def(CFCMethod *method, CFCClass *klass, int optimized_final_meth) {
    CFCParamList *param_list = CFCMethod_get_param_list(method);
    const char *PREFIX         = CFCClass_get_PREFIX(klass);
    const char *invoker_struct = CFCClass_full_struct_sym(klass);
    const char *self_name      = CFCParamList_param_name(param_list, 0);

    char *full_meth_sym   = CFCMethod_full_method_sym(method, klass);
    char *full_offset_sym = CFCMethod_full_offset_sym(method, klass);
    char *full_typedef    = CFCMethod_full_typedef(method, klass);
    char *full_imp_sym    = CFCMethod_imp_func(method, klass);

    // Prepare parameter lists, minus the type of the invoker.
    if (CFCParamList_variadic(param_list)) {
        CFCUtil_die("Variadic methods not supported");
    }
    const char *arg_names  = CFCParamList_name_list(param_list);
    const char *params_end = CFCParamList_to_c(param_list);
    while (*params_end && *params_end != '*') {
        params_end++;
    }

    // Prepare a return statement... or not.
    CFCType *return_type = CFCMethod_get_return_type(method);
    const char *ret_type_str = CFCType_to_c(return_type);
    const char *maybe_return = CFCType_is_void(return_type) ? "" : "return ";

    const char innards_pattern[] =
        "    const %s method = (%s)cfish_obj_method(%s, %s);\n"
        "    %smethod(%s);\n"
        ;
    char *innards = CFCUtil_sprintf(innards_pattern, full_typedef,
                                    full_typedef, self_name, full_offset_sym,
                                    maybe_return, arg_names);
    if (optimized_final_meth) {
        CFCParcel  *parcel = CFCClass_get_parcel(klass);
        const char *privacy_sym = CFCParcel_get_privacy_sym(parcel);
        char *invoker_cast = CFCUtil_strdup("");
        if (!CFCMethod_is_fresh(method, klass)) {
            CFCType *self_type = CFCMethod_self_type(method);
            invoker_cast = CFCUtil_cat(invoker_cast, "(",
                                       CFCType_to_c(self_type), ")", NULL);
        }
        const char pattern[] =
            "#ifdef %s\n"
            "    %s%s(%s%s);\n"
            "#else\n"
            "%s"
            "#endif\n"
            ;
        char *temp = CFCUtil_sprintf(pattern, privacy_sym,
                                     maybe_return, full_imp_sym,
                                     invoker_cast, arg_names, innards);
        FREEMEM(innards);
        innards = temp;
        FREEMEM(invoker_cast);
    }

    const char pattern[] =
        "extern %sVISIBLE uint32_t %s;\n"
        "static CFISH_INLINE %s\n"
        "%s(%s%s) {\n"
        "%s"
        "}\n";
    char *method_def
        = CFCUtil_sprintf(pattern, PREFIX, full_offset_sym, ret_type_str,
                          full_meth_sym, invoker_struct, params_end, innards);

    FREEMEM(innards);
    FREEMEM(full_imp_sym);
    FREEMEM(full_offset_sym);
    FREEMEM(full_meth_sym);
    FREEMEM(full_typedef);
    return method_def;
}
Exemplo n.º 4
0
CFCClass*
CFCClass_do_create(CFCClass *self, struct CFCParcel *parcel,
                   const char *exposure, const char *name,
                   const char *nickname, CFCDocuComment *docucomment,
                   CFCFileSpec *file_spec, const char *parent_class_name,
                   int is_final, int is_inert, int is_abstract) {
    CFCUTIL_NULL_CHECK(parcel);
    CFCUTIL_NULL_CHECK(name);
    exposure = exposure ? exposure  : "parcel";

    // Validate.
    if (!S_validate_exposure(exposure)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid exposure: '%s'", exposure);
    }
    if (!CFCClass_validate_class_name(name)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid name: '%s'", name);
    }

    const char *last_colon = strrchr(name, ':');
    const char *struct_sym = last_colon ? last_colon + 1 : name;

    // Derive nickname if necessary, then validate.
    const char *real_nickname = NULL;
    if (nickname) {
        real_nickname = nickname;
    }
    else {
        real_nickname = struct_sym;
    }
    if (!S_validate_nickname(real_nickname)) {
        CFCBase_decref((CFCBase*)self);
        CFCUtil_die("Invalid nickname: '%s'", real_nickname);
    }

    // Default parent class name is "Clownfish::Obj".
    if (!is_inert
        && !parent_class_name
        && strcmp(name, "Clownfish::Obj") != 0
       ) {
        parent_class_name = "Clownfish::Obj";
    }

    // Assign.
    self->parcel          = (CFCParcel*)CFCBase_incref((CFCBase*)parcel);
    self->exposure        = CFCUtil_strdup(exposure);
    self->name            = CFCUtil_strdup(name);
    self->nickname        = CFCUtil_strdup(real_nickname);
    self->tree_grown      = false;
    self->parent          = NULL;
    self->children        = (CFCClass**)CALLOCATE(1, sizeof(CFCClass*));
    self->num_kids        = 0;
    self->functions       = (CFCFunction**)CALLOCATE(1, sizeof(CFCFunction*));
    self->num_functions   = 0;
    self->fresh_methods   = (CFCMethod**)CALLOCATE(1, sizeof(CFCMethod*));
    self->num_fresh_meths = 0;
    self->methods         = NULL;
    self->num_methods     = 0;
    self->fresh_vars      = (CFCVariable**)CALLOCATE(1, sizeof(CFCVariable*));
    self->num_fresh_vars  = 0;
    self->member_vars     = NULL;
    self->num_member_vars = 0;
    self->inert_vars      = (CFCVariable**)CALLOCATE(1, sizeof(CFCVariable*));
    self->num_inert_vars  = 0;
    self->parent_class_name = CFCUtil_strdup(parent_class_name);
    self->docucomment
        = (CFCDocuComment*)CFCBase_incref((CFCBase*)docucomment);
    self->file_spec = (CFCFileSpec*)CFCBase_incref((CFCBase*)file_spec);

    // Cache several derived symbols.

    const char *prefix = CFCClass_get_prefix(self);
    self->struct_sym        = CFCUtil_strdup(struct_sym);
    self->full_struct_sym   = CFCUtil_sprintf("%s%s", prefix, struct_sym);
    self->ivars_struct      = CFCUtil_sprintf("%sIVARS", struct_sym);
    self->full_ivars_struct = CFCUtil_sprintf("%s%s", prefix,
                                              self->ivars_struct);
    self->ivars_func        = CFCUtil_sprintf("%s_IVARS", self->nickname);
    self->full_ivars_func   = CFCUtil_sprintf("%s%s", prefix,
                                              self->ivars_func);
    self->full_ivars_offset = CFCUtil_sprintf("%s_OFFSET",
                                              self->full_ivars_func);

    const char *PREFIX = CFCClass_get_PREFIX(self);
    size_t struct_sym_len = strlen(struct_sym);
    char *short_class_var = (char*)MALLOCATE(struct_sym_len + 1);
    size_t i;
    for (i = 0; i < struct_sym_len; i++) {
        short_class_var[i] = toupper(struct_sym[i]);
    }
    short_class_var[struct_sym_len] = '\0';
    self->short_class_var = short_class_var;
    self->full_class_var  = CFCUtil_sprintf("%s%s", PREFIX, short_class_var);
    self->privacy_symbol  = CFCUtil_sprintf("C_%s", self->full_class_var);

    // Build the relative path to the autogenerated C header file.
    if (file_spec) {
        const char *path_part = CFCFileSpec_get_path_part(self->file_spec);
        self->include_h = CFCUtil_sprintf("%s.h", path_part);
    }
    else {
        self->include_h = CFCUtil_strdup("class.h");
    }

    self->is_final    = !!is_final;
    self->is_inert    = !!is_inert;
    self->is_abstract = !!is_abstract;

    // Check for include flag mismatch.
    if (!CFCClass_included(self) && CFCParcel_included(parcel)) {
        CFCUtil_die("Class %s from source dir found in parcel %s from"
                    " include dir",
                    name, CFCParcel_get_name(parcel));
    }

    // Skip class if it's from an include dir and the parcel was already
    // processed in another source or include dir.
    const char *class_source_dir  = CFCClass_get_source_dir(self);
    const char *parcel_source_dir = CFCParcel_get_source_dir(parcel);
    if (!CFCClass_included(self)
        || !class_source_dir
        || !parcel_source_dir
        || strcmp(class_source_dir, parcel_source_dir) == 0
    ) {
        char *error;

        CFCUTIL_TRY {
            // Store in registry.
            S_register(self);
        }
        CFCUTIL_CATCH(error);

        if (error) {
            CFCBase_decref((CFCBase*)self);
            CFCUtil_rethrow(error);
        }

        CFCParcel_add_struct_sym(parcel, self->struct_sym);
    }