Beispiel #1
0
/* This creates a new class entity. This entity is used for, well, more than it
   should be. The entity is going to be either an enum, a variant, or a
   user-defined class. The class is assumed to be refcounted, because it usually
   is.
   The new class is automatically linked up to the current module. No default
   type is created, in case the newly-made class ends up needing generics. */
lily_class *lily_new_class(lily_symtab *symtab, const char *name)
{
    lily_class *new_class = lily_malloc(sizeof(lily_class));
    char *name_copy = lily_malloc(strlen(name) + 1);

    strcpy(name_copy, name);

    new_class->item_kind = 0;
    new_class->flags = 0;
    new_class->type = NULL;
    new_class->parent = NULL;
    new_class->shorthash = shorthash_for_name(name);
    new_class->name = name_copy;
    new_class->generic_count = 0;
    new_class->prop_count = 0;
    new_class->variant_members = NULL;
    new_class->members = NULL;
    new_class->module = symtab->active_module;
    new_class->all_subtypes = NULL;
    new_class->move_flags = VAL_IS_INSTANCE;
    new_class->dyna_start = 0;

    new_class->id = symtab->next_class_id;
    symtab->next_class_id++;

    new_class->next = symtab->active_module->class_chain;
    symtab->active_module->class_chain = new_class;

    return new_class;
}
Beispiel #2
0
/* Create a new property and add it into the class. As a convenience, the
   newly-made property is also returned. */
lily_prop_entry *lily_add_class_property(lily_symtab *symtab, lily_class *cls,
        lily_type *type, const char *name, int flags)
{
    lily_prop_entry *entry = lily_malloc(sizeof(lily_prop_entry));
    char *entry_name = lily_malloc(strlen(name) + 1);

    strcpy(entry_name, name);

    entry->item_kind = ITEM_TYPE_PROPERTY;
    entry->flags = flags;
    entry->name = entry_name;
    entry->type = type;
    entry->name_shorthash = shorthash_for_name(entry_name);
    entry->next = NULL;
    entry->id = cls->prop_count;
    entry->cls = cls;
    cls->prop_count++;

    /* It's REALLY important that properties be linked this way, because it
       allows the vm to walk from a derived class up through the superclasses
       when setting property types in instance creation.
       It goes like this:

        Animal        >  Bird          >  Falcon
       [3 => 2 => 1] => [6 => 5 => 4] => [9 => 8 => 7] */
    entry->next = cls->properties;
    cls->properties = entry;

    return entry;
}
Beispiel #3
0
/* Try to find a class. If 'module' is NULL, then search through both the
   current module AND the builtin module. In all other cases, search just the
   module given. */
lily_class *lily_find_class(lily_symtab *symtab, lily_module_entry *module,
        const char *name)
{
    uint64_t shorthash = shorthash_for_name(name);
    lily_class *result;

    if (module == NULL) {
        if (name[1] != '\0') {
            result = find_class(symtab->builtin_module->class_chain, name,
                    shorthash);
            if (result == NULL)
                result = find_class(symtab->active_module->class_chain, name,
                        shorthash);
        }
        else {
            lily_type *generic_type = lookup_generic(symtab, name);
            if (generic_type) {
                /* It's rather silly to make a different class for each generic
                   type. Instead, write out whatever generic type was found as
                   the default type. The generic class is written to have no
                   subtypes, so this is okay.
                   ts and other modules always special case the generic class,
                   and won't be bothered by this little trick. */
                result = symtab->generic_class;
                result->type = generic_type;
            }
            else
                result = NULL;
        }
    }
    else
        result = find_class(module->class_chain, name, shorthash);

    return result;
}
Beispiel #4
0
/* lily_keyword_by_name
   Attempt to lookup a keyword based on 64-bit short hash, then on a name if
   necessary. Keywords are in a static list, (via lily_seed_symtab.h), so this
   doesn't require a symtab. */
int lily_keyword_by_name(char *name)
{
    int i;
    uint64_t shorthash = shorthash_for_name(name);

    for (i = 0;i <= KEY_LAST_ID;i++) {
        if (keywords[i].shorthash == shorthash &&
            strcmp(keywords[i].name, name) == 0)
            return i;
    }

    return -1;
}
Beispiel #5
0
/* lily_class_by_name
   This function returns a class for a given name, or NULL. This doesn't
   take a name, because all class names are <= 8 bytes in name length. */
lily_class *lily_class_by_name(lily_symtab *symtab, char *name)
{
    int i;
    lily_class **classes = symtab->classes;
    uint64_t shorthash = shorthash_for_name(name);

    for (i = 0;i <= symtab->class_pos;i++) {
        if (classes[i]->shorthash == shorthash &&
            strcmp(classes[i]->name, name) == 0)
            return classes[i];
    }

    return NULL;
}
Beispiel #6
0
/* Try to find a method within the class given. The given class is search first,
   then any parents of the class. */
lily_var *lily_find_method(lily_class *cls, const char *name)
{
    lily_var *iter;
    uint64_t shorthash = shorthash_for_name(name);

    for (iter = cls->call_chain;iter != NULL;iter = iter->next) {
        if (iter->shorthash == shorthash && strcmp(iter->name, name) == 0)
            break;
    }

    if (iter == NULL && cls->parent)
        iter = lily_find_method(cls->parent, name);

    return iter;
}
Beispiel #7
0
/* lily_var_by_name
   Search the symtab for a var with a name of 'name'. This will return the var
   or NULL. */
lily_var *lily_var_by_name(lily_symtab *symtab, char *name)
{
    lily_var *var = symtab->var_start;
    uint64_t shorthash = shorthash_for_name(name);

    while (var != NULL) {
        if (var->shorthash == shorthash &&
            ((var->flags & SYM_OUT_OF_SCOPE) == 0) &&
            strcmp(var->name, name) == 0)
            return var;
        var = var->next;
    }

    return NULL;
}
Beispiel #8
0
/* lily_find_class_callable
   This function will see if a given clas has a function with the given name.
   NULL is returned on failure. */
lily_var *lily_find_class_callable(lily_symtab *symtab, lily_class *cls,
        char *name)
{
    lily_var *iter;
    uint64_t shorthash = shorthash_for_name(name);

    for (iter = cls->call_start;iter != NULL;iter = iter->next) {
        if (iter->shorthash == shorthash && strcmp(iter->name, name) == 0)
            break;
    }

    /* Maybe it's something that hasn't been loaded in the symtab yet. */
    if (iter == NULL && cls->seed_table != NULL) {
        const lily_func_seed *seed = cls->seed_table;
        while (seed) {
            if (strcmp(seed->name, name) == 0) {
                lily_var *save_top = symtab->var_top;

                iter = init_func_seed(symtab, cls, seed);
                if (iter == NULL)
                    lily_raise_nomem(symtab->raiser);
                else {
                    /* The new var is added to symtab's vars. Take it off of
                       there since this var shouldn't be globally reachable.
                       __main__ is the first var, so this shouldn't have to
                       check for var_top == var_start. */
                    if (cls->call_start == NULL)
                        cls->call_start = iter;

                    if (cls->call_top != NULL)
                        cls->call_top->next = iter;

                    cls->call_top = iter;

                    /* This is a builtin, so fix the line number to 0. */
                    iter->line_num = 0;
                    symtab->var_top = save_top;
                    symtab->var_top->next = NULL;
                }
                break;
            }
            seed = seed->next;
        }
    }

    return iter;
}
Beispiel #9
0
/* Scoped variants are stored within the enum they're part of. This will try to
   find a variant stored within 'enum_cls'. */
lily_variant_class *lily_find_scoped_variant(lily_class *enum_cls,
        const char *name)
{
    int i;
    uint64_t shorthash = shorthash_for_name(name);
    lily_variant_class *ret = NULL;

    for (i = 0;i < enum_cls->variant_size;i++) {
        lily_variant_class *cls = enum_cls->variant_members[i];
        if (cls->shorthash == shorthash &&
            strcmp(cls->name, name) == 0) {
            ret = cls;
        }
    }

    return ret;
}
Beispiel #10
0
/* Try to find a var. If the given module is NULL, then search through both the
   current and builtin modules. For everything else, just search through the
   module given. */
lily_var *lily_find_var(lily_symtab *symtab, lily_module_entry *module,
        const char *name)
{
    uint64_t shorthash = shorthash_for_name(name);
    lily_var *result;

    if (module == NULL) {
        result = find_var(symtab->builtin_module->var_chain, name,
                    shorthash);
        if (result == NULL)
            result = find_var(symtab->active_module->var_chain, name, shorthash);
    }
    else
        result = find_var(module->var_chain, name, shorthash);

    return result;
}
Beispiel #11
0
/* Try to find a var. If the given import is NULL, then search through both the
   current and builtin imports. For everything else, just search through the
   import given. */
lily_var *lily_find_var(lily_symtab *symtab, lily_import_entry *import,
        const char *name)
{
    uint64_t shorthash = shorthash_for_name(name);
    lily_var *result;

    if (import == NULL) {
        result = find_var(symtab->builtin_import->var_chain, name,
                    shorthash);
        if (result == NULL)
            result = find_var(symtab->active_import->var_chain, name, shorthash);
    }
    else
        result = find_var(import->var_chain, name, shorthash);

    return result;
}
Beispiel #12
0
/* Create a new var, but leave it to the caller to link it somewhere. */
lily_var *lily_new_raw_unlinked_var(lily_symtab *symtab, lily_type *type,
        const char *name)
{
    lily_var *var = lily_malloc(sizeof(lily_var));

    var->name = lily_malloc(strlen(name) + 1);
    var->item_kind = ITEM_TYPE_VAR;
    var->flags = 0;
    strcpy(var->name, name);
    var->line_num = *symtab->lex_linenum;

    var->shorthash = shorthash_for_name(name);
    var->type = type;
    var->next = NULL;
    var->parent = NULL;

    return var;
}
Beispiel #13
0
/* lily_try_new_var
   This creates a new var using the signature given, and copying the name.
   It is okay to pass a sig without list element/call info, since
   lily_try_sig_for_class ensures that important parts are set to NULL.
   This function will add the var to the symtab on success.
   Note: 'try' means this call returns NULL on failure. */
lily_var *lily_try_new_var(lily_symtab *symtab, lily_sig *sig, char *name,
        int flags)
{
    lily_var *var = lily_malloc(sizeof(lily_var));
    if (var == NULL)
        return NULL;

    var->name = lily_malloc(strlen(name) + 1);
    if (var->name == NULL) {
        lily_free(var);
        return NULL;
    }

    var->flags = VAL_IS_NIL | SYM_TYPE_VAR | flags;
    strcpy(var->name, name);
    var->line_num = *symtab->lex_linenum;

    var->shorthash = shorthash_for_name(name);
    var->sig = sig;
    var->next = NULL;
    var->parent = NULL;

    if ((flags & VAR_IS_READONLY) == 0) {
        var->reg_spot = symtab->next_register_spot;
        symtab->next_register_spot++;
        var->function_depth = symtab->function_depth;
    }
    else {
        /* Vars that are never intended to be assigned to (like functions) are
           not placed in a register. */
        var->reg_spot = -1;
        var->function_depth = -1;
    }

    if (symtab->var_start == NULL)
        symtab->var_start = var;
    else
        symtab->var_top->next = var;

    symtab->var_top = var;

    return var;
}
Beispiel #14
0
/* This creates a new variant called 'name' and installs it into 'enum_cls'. */
lily_variant_class *lily_new_variant(lily_symtab *symtab, lily_class *enum_cls,
        const char *name, int variant_id)
{
    lily_variant_class *variant = lily_malloc(sizeof(lily_variant_class));

    variant->item_kind = ITEM_TYPE_VARIANT;
    variant->flags = CLS_IS_VARIANT | CLS_EMPTY_VARIANT;
    variant->variant_id = variant_id;
    variant->parent = enum_cls;
    variant->build_type = NULL;
    variant->shorthash = shorthash_for_name(name);
    variant->name = lily_malloc(strlen(name) + 1);
    strcpy(variant->name, name);

    variant->next = symtab->active_module->class_chain;
    symtab->active_module->class_chain = (lily_class *)variant;

    /* Variant classes do not need a unique class id because they are not
       compared in ts. In vm, they're always accessed through their enum. */

    return variant;
}
Beispiel #15
0
/* Create a new property and add it into the class. As a convenience, the
   newly-made property is also returned. */
lily_prop_entry *lily_add_class_property(lily_symtab *symtab, lily_class *cls,
        lily_type *type, const char *name, int flags)
{
    lily_prop_entry *entry = lily_malloc(sizeof(lily_prop_entry));
    char *entry_name = lily_malloc(strlen(name) + 1);

    strcpy(entry_name, name);

    entry->item_kind = ITEM_TYPE_PROPERTY;
    entry->flags = flags;
    entry->name = entry_name;
    entry->type = type;
    entry->name_shorthash = shorthash_for_name(entry_name);
    entry->next = NULL;
    entry->id = cls->prop_count;
    entry->cls = cls;
    cls->prop_count++;

    entry->next = (lily_prop_entry *)cls->members;
    cls->members = (lily_named_sym *)entry;

    return entry;
}
Beispiel #16
0
/* Does 'name' exist within 'cls' as either a var or a name? If so, return it.
   If not, then return NULL. */
lily_named_sym *lily_find_member(lily_class *cls, const char *name)
{
    lily_named_sym *ret = NULL;

    if (cls->members != NULL) {
        uint64_t shorthash = shorthash_for_name(name);
        lily_named_sym *sym_iter = cls->members;
        while (sym_iter) {
            if (sym_iter->name_shorthash == shorthash &&
                strcmp(sym_iter->name, name) == 0) {
                ret = (lily_named_sym *)sym_iter;
                break;
            }

            sym_iter = sym_iter->next;
        }
    }

    if (ret == NULL && cls->parent != NULL)
        ret = lily_find_member(cls->parent, name);

    return ret;
}
Beispiel #17
0
/* Try to find a property with a name in a class. The parent class(es), if any,
   are tries as a fallback if unable to find it in the given class. */
lily_prop_entry *lily_find_property(lily_class *cls, const char *name)
{
    lily_prop_entry *ret = NULL;

    if (cls->properties != NULL) {
        uint64_t shorthash = shorthash_for_name(name);
        lily_prop_entry *prop_iter = cls->properties;
        while (prop_iter) {
            if (prop_iter->name_shorthash == shorthash &&
                strcmp(prop_iter->name, name) == 0) {
                ret = prop_iter;
                break;
            }

            prop_iter = prop_iter->next;
        }
    }

    if (ret == NULL && cls->parent != NULL)
        ret = lily_find_property(cls->parent, name);

    return ret;
}
Beispiel #18
0
/* init_classes
   Symtab init, stage 2
   This function initializes the classes of a symtab, as well as their
   signatures. All classes are given a signature so that signatures which don't
   require extra call/internal element info (integer and number, for example),
   can be shared. All a symbol needs to do is sym->sig to get the common
   signature. */
static int init_classes(lily_symtab *symtab)
{
    int i, class_count, ret;
    lily_class **classes;

    classes = lily_malloc(sizeof(lily_class *) * INITIAL_CLASS_SIZE);
    if (classes == NULL)
        return 0;

    symtab->classes = classes;
    class_count = sizeof(class_seeds) / sizeof(class_seeds[0]);
    ret = 1;

    for (i = 0;i < class_count;i++) {
        lily_class *new_class = lily_malloc(sizeof(lily_class));

        if (new_class != NULL) {
            lily_sig *sig;

            /* If a class doesn't take templates (or isn't template), then
               it can have a default sig that lily_try_sig_for_class can yield.
               This saves memory, and is necessary now that sig comparison is
               by pointer. */
            if (class_seeds[i].template_count != 0 ||
                i == SYM_CLASS_TEMPLATE) {
                sig = NULL;
            }
            else {
                /* A basic class? Make a quick default sig for it. */
                sig = lily_malloc(sizeof(lily_sig));
                if (sig != NULL) {
                    sig->cls = new_class;
                    /* Make sure this is null so any attempt to free it won't
                       cause a problem. */
                    sig->siglist = NULL;
                    sig->siglist_size = 0;
                    sig->flags = 0;
                    /* Non-template signatures use this to mean that this sig
                       does not have templates inside. */
                    sig->template_pos = 0;
                    if (i == SYM_CLASS_ANY)
                        sig->flags |= SIG_MAYBE_CIRCULAR;

                    sig->next = symtab->root_sig;
                    symtab->root_sig = sig;
                }
                else
                    ret = 0;
            }

            new_class->name = class_seeds[i].name;
            new_class->call_start = NULL;
            new_class->call_top = NULL;
            new_class->sig = sig;
            new_class->id = i;
            new_class->template_count = class_seeds[i].template_count;
            new_class->shorthash = shorthash_for_name(new_class->name);
            new_class->gc_marker = class_seeds[i].gc_marker;
            new_class->flags = class_seeds[i].flags;
            new_class->is_refcounted = class_seeds[i].is_refcounted;
            new_class->seed_table = NULL;
            new_class->setup_func = class_seeds[i].setup_func;
            new_class->eq_func = class_seeds[i].eq_func;
        }
        else
            ret = 0;

        classes[i] = new_class;
    }

    /* Packages are a bit too complicated for the parser now, so make them
       where the user can't declare them. */
    if (ret == 1)
        classes[SYM_CLASS_PACKAGE]->shorthash = 0;

    /* This is so symtab cleanup catches all of the builtin classes, regardless
       of what parts were initialized. */
    symtab->class_pos = SYM_LAST_CLASS;
    return ret;
}