/* 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; }
/* 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; }
static void bind_httpmethod(int *count, lily_parse_state *parser, request_rec *r) { if (*count == -1) return; lily_class *string_cls = lily_class_by_id(parser->symtab, SYM_CLASS_STRING); lily_sig *string_sig = string_cls->sig; lily_var *var = lily_try_new_var(parser->symtab, string_sig, "httpmethod", 0); lily_string_val *sv = lily_malloc(sizeof(lily_string_val)); char *sv_buffer = lily_malloc(strlen(r->method) + 1); if (var == NULL || sv == NULL || sv_buffer == NULL) { lily_free(sv); lily_free(sv_buffer); *count = -1; return; } strcpy(sv_buffer, r->method); sv->string = sv_buffer; sv->refcount = 1; sv->size = strlen(r->method); var->value.string = sv; var->flags &= ~VAL_IS_NIL; (*count)++; }
static void make_package(int *ok, lily_parse_state *parser, lily_var *package_var, int var_count, int register_save, lily_var *var_save) { lily_symtab *symtab = parser->symtab; lily_package_val *pval = lily_malloc(sizeof(lily_package_val)); lily_var **package_vars = lily_malloc(var_count * sizeof(lily_var *)); if (pval == NULL || package_vars == NULL) { lily_free(pval); lily_free(package_vars); *ok = 0; } else { int i = 0; lily_var *var_iter = var_save->next; while (var_iter) { package_vars[i] = var_iter; i++; var_iter = var_iter->next; } symtab->var_top = var_save; var_save->next = NULL; symtab->next_register_spot = register_save; pval->refcount = 1; pval->name = package_var->name; pval->gc_entry = NULL; pval->var_count = i; pval->vars = package_vars; package_var->flags &= ~VAL_IS_NIL; package_var->value.package = pval; } }
/* lily_try_new_hash_elem This attempts to create a new hash element for storing a key and a value. The caller is responsible for adding this element to a hash value. Note: 'try' means this call returns NULL on failure. */ lily_hash_elem *lily_try_new_hash_elem() { lily_hash_elem *elem = lily_malloc(sizeof(lily_hash_elem)); if (elem == NULL) return NULL; elem->elem_key = lily_malloc(sizeof(lily_value)); elem->elem_value = lily_malloc(sizeof(lily_value)); if (elem->elem_key == NULL || elem->elem_value == NULL) { lily_free(elem->elem_key); lily_free(elem->elem_value); lily_free(elem); return NULL; } /* Hash lookup does not take into account or allow nil keys. So this should be set to a non-nil value as soon as possible. */ elem->elem_key->flags = VAL_IS_NIL; elem->elem_key->value.integer = 0; elem->elem_value->flags = VAL_IS_NIL; elem->elem_value->value.integer = 0; elem->next = NULL; return elem; }
/* bind_string_and_buffer string_sig: The signature representing a string, for the new value. buffer: A malloc'd buffer holding a \0 terminated string. On success: A proper value is returned containing a string using the buffer. The buffer is taken over by the newly-created string value. On failure: NULL is returned, and the buffer given is free'd. */ static lily_value *bind_string_and_buffer(lily_sig *string_sig, char *buffer) { lily_value *new_value = lily_malloc(sizeof(lily_value)); lily_string_val *sv = lily_malloc(sizeof(lily_string_val)); int string_size = strlen(buffer); if (sv == NULL || new_value == NULL) { lily_free(sv); /* This function takes over the buffer on success, so make sure if there is an error that it destroys the buffer. */ lily_free(buffer); lily_free(new_value); return NULL; } sv->refcount = 1; sv->string = buffer; sv->size = string_size; new_value->value.string = sv; new_value->flags = 0; new_value->sig = string_sig; return new_value; }
lily_buffer_u16 *lily_new_buffer_u16(uint32_t start) { lily_buffer_u16 *b = lily_malloc(sizeof(lily_buffer_u16)); b->data = lily_malloc(start * sizeof(uint16_t)); b->pos = 0; b->size = start; return b; }
/* Create a new Dynamic value. The contents of the Dynamic are set to an empty raw value that is ready to be moved in. */ lily_dynamic_val *lily_new_dynamic(void) { lily_dynamic_val *d = lily_malloc(sizeof(lily_dynamic_val)); lily_value *v = lily_malloc(sizeof(lily_value)); v->flags = 0; d->inner_value = v; d->gc_entry = NULL; d->refcount = 0; return d; }
lily_any_val *lily_new_any_val() { lily_any_val *a = lily_malloc(sizeof(lily_any_val)); a->inner_value = lily_malloc(sizeof(lily_value)); a->inner_value->flags = VAL_IS_NIL; a->inner_value->type = NULL; a->inner_value->value.integer = 0; a->gc_entry = NULL; a->refcount = 1; return a; }
/* init_lily_main Symtab init, stage 4 This creates __main__, which is a function that holds all code that is not put inside of a lily function. This is outside of read_seeds since it makes a native function instead of a foreign one. __main__ is always the first var, and thus can always be found at the symtab's var_start. */ static int init_lily_main(lily_symtab *symtab) { lily_class *cls = lily_class_by_id(symtab, SYM_CLASS_FUNCTION); lily_sig *new_sig = lily_try_sig_for_class(symtab, cls); if (new_sig == NULL) return 0; new_sig->siglist = lily_malloc(2 * sizeof(lily_sig)); if (new_sig->siglist == NULL) return 0; new_sig->siglist[0] = NULL; new_sig->siglist[1] = NULL; new_sig->siglist_size = 2; new_sig->flags = 0; lily_var *var = lily_try_new_var(symtab, new_sig, "__main__", 0); if (var == NULL) return 0; /* The emitter will mark __main__ as non-nil when it's entered. Until then, leave it alone because it doesn't have a value. */ return 1; }
/* init_literals Symtab init, stage 3 This function creates literals 0 and 1, and always in that order. These are used so that and/or ops can be a combo of 'jump_if_true' and 'assign', instead of creating a special op for them. */ static int init_literals(lily_symtab *symtab) { int i, ret; lily_class *cls = lily_class_by_id(symtab, SYM_CLASS_INTEGER); lily_literal *lit; ret = 1; for (i = 0;i < 2;i++) { lit = lily_malloc(sizeof(lily_literal)); if (lit != NULL) { lit->flags = SYM_TYPE_LITERAL; lit->sig = cls->sig; lit->value.integer = i; lit->next = NULL; if (symtab->lit_start == NULL) symtab->lit_start = lit; else symtab->lit_top->next = lit; symtab->lit_top = lit; } else ret = 0; } return ret; }
/* lily_new_literal This adds a new literal to the given symtab. The literal will be of the class 'cls', and be given the value 'value'. The symbol created does not have VAL_IS_NIL set, because the literal is assumed to never be nil. This function currently handles only integer, number, and string values. Warning: This function calls lily_raise_nomem instead of returning NULL. */ lily_literal *lily_new_literal(lily_symtab *symtab, lily_class *cls, lily_raw_value value) { lily_literal *lit = lily_malloc(sizeof(lily_literal)); if (lit == NULL) { /* Make sure any string sent will be properly free'd. */ if (cls->id == SYM_CLASS_STRING) { lily_string_val *sv = value.string; lily_free(sv->string); lily_free(sv); } lily_raise_nomem(symtab->raiser); } /* Literals are either a string, integer, or number, so this is safe. */ lit->sig = cls->sig; lit->flags = SYM_TYPE_LITERAL; lit->next = NULL; lit->value = value; /* Literals are never saved to a register. */ lit->reg_spot = -1; if (symtab->lit_top == NULL) symtab->lit_start = lit; else symtab->lit_top->next = lit; symtab->lit_top = lit; return lit; }
lily_value *lily_new_value_of_integer(int64_t i) { lily_value *v = lily_malloc(sizeof(lily_value)); v->flags = LILY_INTEGER_ID; v->value.integer = i; return v; }
lily_list_val *lily_new_list(int initial) { lily_list_val *lv = lily_malloc(sizeof(lily_list_val)); lv->elems = lily_malloc(initial * sizeof(lily_value *)); lv->refcount = 0; lv->num_values = initial; lv->extra_space = 0; int i; for (i = 0;i < initial;i++) { lily_value *elem = lily_malloc(sizeof(lily_value)); elem->flags = 0; lv->elems[i] = elem; } return lv; }
/* Create a new RAW lily_string_val. The newly-made string will hold 'size' bytes of 'source'. 'source' is expected to NOT be \0 terminated, and thus 'size' SHOULD NOT include any \0 termination. Instead, the \0 termination will */ lily_string_val *lily_new_string_sized(const char *source, int len) { char *buffer = lily_malloc(len + 1); memcpy(buffer, source, len); buffer[len] = '\0'; return new_sv(buffer, len); }
static lily_string_val *new_sv(char *buffer, int size) { lily_string_val *sv = lily_malloc(sizeof(lily_string_val)); sv->refcount = 0; sv->string = buffer; sv->size = size; return sv; }
lily_value *lily_new_value_of_byte(uint8_t byte) { lily_value *v = lily_malloc(sizeof(lily_value)); v->flags = LILY_BYTE_ID | VAL_IS_DEREFABLE; v->value.integer = byte; return v; }
/* Create a new RAW lily_string_val. The newly-made string shall contain a copy of what is inside 'source'. The source is expected to be \0 terminated. */ lily_string_val *lily_new_string(const char *source) { int len = strlen(source); char *buffer = lily_malloc(len + 1); strcpy(buffer, source); return new_sv(buffer, len); }
lily_value *lily_new_value_of_double(double d) { lily_value *v = lily_malloc(sizeof(lily_value)); v->flags = LILY_DOUBLE_ID; v->value.doubleval = d; return v; }
lily_value *lily_new_value_of_enum(uint16_t id, lily_instance_val *iv) { lily_value *v = lily_malloc(sizeof(lily_value)); iv->refcount++; v->flags = id | VAL_IS_ENUM | VAL_IS_DEREFABLE; v->value.instance = iv; return v; }
lily_value *lily_new_value_of_file(lily_file_val *fv) { lily_value *v = lily_malloc(sizeof(lily_value)); fv->refcount++; v->flags = LILY_FILE_ID | VAL_IS_DEREFABLE; v->value.file = fv; return v; }
lily_value *lily_new_value_of_hash(lily_hash_val *hv) { lily_value *v = lily_malloc(sizeof(lily_value)); hv->refcount++; v->flags = LILY_HASH_ID | VAL_IS_DEREFABLE | VAL_IS_GC_SPECULATIVE; v->value.hash = hv; return v; }
lily_variant_val *lily_new_variant(int size) { lily_variant_val *ival = lily_malloc(sizeof(lily_variant_val)); ival->values = lily_malloc(size * sizeof(lily_value *)); ival->refcount = 0; ival->gc_entry = NULL; ival->num_values = size; int i; for (i = 0;i < size;i++) { lily_value *v = lily_malloc(sizeof(lily_value)); v->flags = 0; ival->values[i] = v; } return ival; }
/* 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; }
lily_value *lily_new_value_of_instance(uint16_t id, lily_instance_val *iv) { lily_value *v = lily_malloc(sizeof(lily_value)); iv->refcount++; v->flags = id | VAL_IS_INSTANCE | VAL_IS_DEREFABLE | VAL_IS_GC_SPECULATIVE; v->value.instance = iv; return v; }
/* bind_string string_sig: The signature representing a string, for the new value. str: A \0 terminated string. On success: A lily_value is returned that holds a lily_string_value which holds the given string. On failure: NULL is returned. The buffer is not free'd. This function creates a copy of the given str, instead of taking ownership of it. */ static lily_value *bind_string(lily_sig *string_sig, const char *string) { char *buffer = lily_malloc(strlen(string) + 1); if (buffer == NULL) return NULL; strcpy(buffer, string); return bind_string_and_buffer(string_sig, buffer); }
lily_value *lily_new_value_of_list(lily_list_val *lv) { lily_value *v = lily_malloc(sizeof(lily_value)); lv->refcount++; v->flags = LILY_LIST_ID | VAL_IS_DEREFABLE | VAL_IS_GC_SPECULATIVE; v->value.list = lv; return v; }
lily_value *lily_new_value_of_string(lily_string_val *sv) { lily_value *v = lily_malloc(sizeof(lily_value)); sv->refcount++; v->flags = LILY_STRING_ID | VAL_IS_DEREFABLE; v->value.string = sv; return v; }
lily_value *lily_new_value_of_bytestring(lily_bytestring_val *bv) { lily_value *v = lily_malloc(sizeof(lily_value)); bv->refcount++; v->flags = LILY_BYTESTRING_ID | VAL_IS_DEREFABLE; v->value.string = (lily_string_val *)bv; return v; }
lily_literal *lily_get_string_literal(lily_symtab *symtab, char *want_string) { /* The length is given because this can come from a user-defined string, or from something like __file__ or __function__. In the first case, the user may have added \0's, which is why a size requirement was added. */ lily_literal *lit, *ret; ret = NULL; int want_string_len = strlen(want_string); for (lit = symtab->lit_start;lit;lit = lit->next) { if (lit->sig->cls->id == SYM_CLASS_STRING) { if (lit->value.string->size == want_string_len && strcmp(lit->value.string->string, want_string) == 0) { ret = lit; break; } } } if (ret == NULL) { lily_class *cls = lily_class_by_id(symtab, SYM_CLASS_STRING); /* lily_new_literal is guaranteed to work or raise nomem, so this is safe. */ char *string_buffer = lily_malloc((want_string_len + 1) * sizeof(char)); lily_string_val *sv = lily_malloc(sizeof(lily_string_val)); if (sv == NULL || string_buffer == NULL) { lily_free(sv); lily_free(string_buffer); lily_raise_nomem(symtab->raiser); } strcpy(string_buffer, want_string); sv->string = string_buffer; sv->size = want_string_len; sv->refcount = 1; lily_raw_value v; v.string = sv; ret = lily_new_literal(symtab, cls, v); } return ret; }