#include "gravity_compiler.h"
#include "gravity_parser.h"
#include "gravity_token.h"
#include "gravity_utils.h"
#include "gravity_semacheck1.h"
#include "gravity_semacheck2.h"
#include "gravity_optimizer.h"
#include "gravity_codegen.h"
#include "gravity_array.h"
#include "gravity_hash.h"
#include "gravity_core.h"
struct gravity_compiler_t {
gravity_parser_t *parser;
gravity_delegate_t *delegate;
cstring_r *storage;
gravity_vm *vm;
gnode_t *ast;
void_r *objects;
};
static void internal_vm_transfer (gravity_vm *vm, gravity_object_t *obj) {
gravity_compiler_t *compiler = (gravity_compiler_t *)gravity_vm_getdata(vm);
marray_push(void*, *compiler->objects, obj);
}
static void internal_free_class (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
#pragma unused (hashtable, data)
if (!VALUE_ISA_FUNCTION(value)) return;
if (!VALUE_ISA_STRING(key)) return;
gravity_function_t *f = VALUE_AS_FUNCTION(value);
if (f->tag == EXEC_TYPE_SPECIAL) {
if (f->special[0]) gravity_function_free(NULL, (gravity_function_t *)f->special[0]);
if (f->special[1]) gravity_function_free(NULL, (gravity_function_t *)f->special[1]);
}
gravity_string_t *s = VALUE_AS_STRING(key);
bool is_super_function = ((s->len > 5) && (string_casencmp(s->s, CLASS_INTERNAL_INIT_NAME, 5) == 0));
if (!is_super_function) gravity_function_free(NULL, VALUE_AS_FUNCTION(value));
}
static void internal_vm_cleanup (gravity_vm *vm) {
gravity_compiler_t *compiler = (gravity_compiler_t *)gravity_vm_getdata(vm);
size_t count = marray_size(*compiler->objects);
for (size_t i=0; i<count; ++i) {
gravity_object_t *obj = marray_pop(*compiler->objects);
if (OBJECT_ISA_CLASS(obj)) {
gravity_class_t *c = (gravity_class_t *)obj;
gravity_hash_iterate(c->htable, internal_free_class, NULL);
}
gravity_object_free(vm, obj);
}
}
gravity_compiler_t *gravity_compiler_create (gravity_delegate_t *delegate) {
gravity_compiler_t *compiler = mem_alloc(sizeof(gravity_compiler_t));
if (!compiler) return NULL;
compiler->ast = NULL;
compiler->objects = void_array_create();
compiler->delegate = delegate;
return compiler;
}
static void gravity_compiler_reset (gravity_compiler_t *compiler, bool free_core) {
if (compiler->storage) {
cstring_array_each(compiler->storage, {mem_free((void *)val);});
gnode_array_free(compiler->storage);
}
if (compiler->ast) gnode_free(compiler->ast);
if (compiler->parser) gravity_parser_free(compiler->parser);
if (compiler->vm) gravity_vm_free(compiler->vm);
if (compiler->objects) {
marray_destroy(*compiler->objects);
mem_free((void*)compiler->objects);
}
if (free_core) gravity_core_free();
compiler->vm = NULL;
compiler->ast = NULL;
compiler->parser = NULL;
compiler->objects = NULL;
compiler->storage = NULL;
}
void gravity_compiler_free (gravity_compiler_t *compiler) {
gravity_compiler_reset(compiler, true);
mem_free(compiler);
}
gnode_t *gravity_compiler_ast (gravity_compiler_t *compiler) {
return compiler->ast;
}
void gravity_compiler_transfer(gravity_compiler_t *compiler, gravity_vm *vm) {
if (!compiler->objects) return;
gravity_gc_setenabled(vm, false);
size_t count = marray_size(*compiler->objects);
for (size_t i=0; i<count; ++i) {
gravity_object_t *obj = marray_pop(*compiler->objects);
gravity_vm_transfer(vm, obj);
if (!OBJECT_ISA_CLOSURE(obj)) continue;
gravity_closure_t *closure = (gravity_closure_t *)obj;
if ((closure->f->identifier) && strcmp(closure->f->identifier, INITMODULE_NAME) == 0) {
gravity_vm_initmodule(vm, closure->f);
}
}
gravity_gc_setenabled(vm, true);
}
gravity_closure_t *gravity_compiler_run (gravity_compiler_t *compiler, const char *source, size_t len, uint32_t fileid, bool is_static) {
if ((source == NULL) || (len == 0)) return NULL;
if (compiler->ast) gnode_free(compiler->ast);
if (!compiler->objects) compiler->objects = void_array_create();
compiler->vm = gravity_vm_newmini();
gravity_vm_setdata(compiler->vm, (void *)compiler);
gravity_vm_set_callbacks(compiler->vm, internal_vm_transfer, internal_vm_cleanup);
gravity_core_register(compiler->vm);
compiler->parser = gravity_parser_create(source, len, fileid, is_static);
if (!compiler->parser) return NULL;
compiler->ast = gravity_parser_run(compiler->parser, compiler->delegate);
if (!compiler->ast) goto abort_compilation;
gravity_parser_free(compiler->parser);
compiler->parser = NULL;
bool b1 = gravity_semacheck1(compiler->ast, compiler->delegate);
if (!b1) goto abort_compilation;
bool b2 = gravity_semacheck2(compiler->ast, compiler->delegate);
if (!b2) goto abort_compilation;
gravity_function_t *f = gravity_codegen(compiler->ast, compiler->delegate, compiler->vm);
if (!f) goto abort_compilation;
f = gravity_optimizer(f);
if (f) return gravity_closure_new(compiler->vm, f);
abort_compilation:
gravity_compiler_reset(compiler, false);
return NULL;
}
json_t *gravity_compiler_serialize (gravity_compiler_t *compiler, gravity_closure_t *closure) {
#pragma unused(compiler)
json_t *json = json_new();
json_begin_object(json, NULL);
gravity_function_serialize(closure->f, json);
json_end_object(json);
return json;
}
bool gravity_compiler_serialize_infile (gravity_compiler_t *compiler, gravity_closure_t *closure, const char *path) {
if (!closure) return false;
json_t *json = gravity_compiler_serialize(compiler, closure);
if (!json) return false;
json_write_file(json, path);
json_free(json);
return true;
}