gravity_compiler.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // gravity_compiler.c
  3. // gravity
  4. //
  5. // Created by Marco Bambini on 29/08/14.
  6. // Copyright (c) 2014 CreoLabs. All rights reserved.
  7. //
  8. #include "gravity_compiler.h"
  9. #include "gravity_parser.h"
  10. #include "gravity_token.h"
  11. #include "gravity_utils.h"
  12. #include "gravity_semacheck1.h"
  13. #include "gravity_semacheck2.h"
  14. #include "gravity_optimizer.h"
  15. #include "gravity_codegen.h"
  16. #include "gravity_array.h"
  17. #include "gravity_hash.h"
  18. #include "gravity_core.h"
  19. struct gravity_compiler_t {
  20. gravity_parser_t *parser;
  21. gravity_delegate_t *delegate;
  22. cstring_r *storage;
  23. gravity_vm *vm;
  24. gnode_t *ast;
  25. void_r *objects;
  26. };
  27. static void internal_vm_transfer (gravity_vm *vm, gravity_object_t *obj) {
  28. gravity_compiler_t *compiler = (gravity_compiler_t *)gravity_vm_getdata(vm);
  29. marray_push(void*, *compiler->objects, obj);
  30. }
  31. static void internal_free_class (gravity_hash_t *hashtable, gravity_value_t key, gravity_value_t value, void *data) {
  32. #pragma unused (hashtable, data)
  33. // sanity checks
  34. if (!VALUE_ISA_FUNCTION(value)) return;
  35. if (!VALUE_ISA_STRING(key)) return;
  36. // check for special function
  37. gravity_function_t *f = VALUE_AS_FUNCTION(value);
  38. if (f->tag == EXEC_TYPE_SPECIAL) {
  39. if (f->special[0]) gravity_function_free(NULL, (gravity_function_t *)f->special[0]);
  40. if (f->special[1]) gravity_function_free(NULL, (gravity_function_t *)f->special[1]);
  41. }
  42. // a super special init constructor is a string that begins with $init AND it is longer than strlen($init)
  43. gravity_string_t *s = VALUE_AS_STRING(key);
  44. bool is_super_function = ((s->len > 5) && (string_casencmp(s->s, CLASS_INTERNAL_INIT_NAME, 5) == 0));
  45. if (!is_super_function) gravity_function_free(NULL, VALUE_AS_FUNCTION(value));
  46. }
  47. static void internal_vm_cleanup (gravity_vm *vm) {
  48. gravity_compiler_t *compiler = (gravity_compiler_t *)gravity_vm_getdata(vm);
  49. size_t count = marray_size(*compiler->objects);
  50. for (size_t i=0; i<count; ++i) {
  51. gravity_object_t *obj = marray_pop(*compiler->objects);
  52. if (OBJECT_ISA_CLASS(obj)) {
  53. gravity_class_t *c = (gravity_class_t *)obj;
  54. gravity_hash_iterate(c->htable, internal_free_class, NULL);
  55. }
  56. gravity_object_free(vm, obj);
  57. }
  58. }
  59. // MARK: -
  60. gravity_compiler_t *gravity_compiler_create (gravity_delegate_t *delegate) {
  61. gravity_compiler_t *compiler = mem_alloc(sizeof(gravity_compiler_t));
  62. if (!compiler) return NULL;
  63. compiler->ast = NULL;
  64. compiler->objects = void_array_create();
  65. compiler->delegate = delegate;
  66. return compiler;
  67. }
  68. static void gravity_compiler_reset (gravity_compiler_t *compiler, bool free_core) {
  69. // free memory for array of strings storage
  70. if (compiler->storage) {
  71. cstring_array_each(compiler->storage, {mem_free((void *)val);});
  72. gnode_array_free(compiler->storage);
  73. }
  74. // first ast then parser, don't change the release order
  75. if (compiler->ast) gnode_free(compiler->ast);
  76. if (compiler->parser) gravity_parser_free(compiler->parser);
  77. // at the end free mini VM and objects array
  78. if (compiler->vm) gravity_vm_free(compiler->vm);
  79. if (compiler->objects) {
  80. marray_destroy(*compiler->objects);
  81. mem_free((void*)compiler->objects);
  82. }
  83. // feel free to free core if someone requires it
  84. if (free_core) gravity_core_free();
  85. // reset internal pointers
  86. compiler->vm = NULL;
  87. compiler->ast = NULL;
  88. compiler->parser = NULL;
  89. compiler->objects = NULL;
  90. compiler->storage = NULL;
  91. }
  92. void gravity_compiler_free (gravity_compiler_t *compiler) {
  93. gravity_compiler_reset(compiler, true);
  94. mem_free(compiler);
  95. }
  96. gnode_t *gravity_compiler_ast (gravity_compiler_t *compiler) {
  97. return compiler->ast;
  98. }
  99. void gravity_compiler_transfer(gravity_compiler_t *compiler, gravity_vm *vm) {
  100. if (!compiler->objects) return;
  101. // transfer each object from compiler mini VM to exec VM
  102. gravity_gc_setenabled(vm, false);
  103. size_t count = marray_size(*compiler->objects);
  104. for (size_t i=0; i<count; ++i) {
  105. gravity_object_t *obj = marray_pop(*compiler->objects);
  106. gravity_vm_transfer(vm, obj);
  107. if (!OBJECT_ISA_CLOSURE(obj)) continue;
  108. // $moduleinit closure needs to be explicitly initialized
  109. gravity_closure_t *closure = (gravity_closure_t *)obj;
  110. if ((closure->f->identifier) && strcmp(closure->f->identifier, INITMODULE_NAME) == 0) {
  111. // code is here because it does not make sense to add this overhead (that needs to be executed only once)
  112. // inside the gravity_vm_transfer callback which is called for each allocated object inside the VM
  113. gravity_vm_initmodule(vm, closure->f);
  114. }
  115. }
  116. gravity_gc_setenabled(vm, true);
  117. }
  118. // MARK: -
  119. gravity_closure_t *gravity_compiler_run (gravity_compiler_t *compiler, const char *source, size_t len, uint32_t fileid, bool is_static) {
  120. if ((source == NULL) || (len == 0)) return NULL;
  121. // CHECK cleanup first
  122. if (compiler->ast) gnode_free(compiler->ast);
  123. if (!compiler->objects) compiler->objects = void_array_create();
  124. // CODEGEN requires a mini vm in order to be able to handle garbage collector
  125. compiler->vm = gravity_vm_newmini();
  126. gravity_vm_setdata(compiler->vm, (void *)compiler);
  127. gravity_vm_set_callbacks(compiler->vm, internal_vm_transfer, internal_vm_cleanup);
  128. gravity_core_register(compiler->vm);
  129. // STEP 0: CREATE PARSER
  130. compiler->parser = gravity_parser_create(source, len, fileid, is_static);
  131. if (!compiler->parser) return NULL;
  132. // STEP 1: SYNTAX CHECK
  133. compiler->ast = gravity_parser_run(compiler->parser, compiler->delegate);
  134. if (!compiler->ast) goto abort_compilation;
  135. gravity_parser_free(compiler->parser);
  136. compiler->parser = NULL;
  137. // STEP 2a: SEMANTIC CHECK (NON-LOCAL DECLARATIONS)
  138. bool b1 = gravity_semacheck1(compiler->ast, compiler->delegate);
  139. if (!b1) goto abort_compilation;
  140. // STEP 2b: SEMANTIC CHECK (LOCAL DECLARATIONS)
  141. bool b2 = gravity_semacheck2(compiler->ast, compiler->delegate);
  142. if (!b2) goto abort_compilation;
  143. // STEP 3: INTERMEDIATE CODE GENERATION (stack based VM)
  144. gravity_function_t *f = gravity_codegen(compiler->ast, compiler->delegate, compiler->vm);
  145. if (!f) goto abort_compilation;
  146. // STEP 4: CODE GENERATION (register based VM)
  147. f = gravity_optimizer(f);
  148. if (f) return gravity_closure_new(compiler->vm, f);
  149. abort_compilation:
  150. gravity_compiler_reset(compiler, false);
  151. return NULL;
  152. }
  153. json_t *gravity_compiler_serialize (gravity_compiler_t *compiler, gravity_closure_t *closure) {
  154. #pragma unused(compiler)
  155. json_t *json = json_new();
  156. json_begin_object(json, NULL);
  157. gravity_function_serialize(closure->f, json);
  158. json_end_object(json);
  159. return json;
  160. }
  161. bool gravity_compiler_serialize_infile (gravity_compiler_t *compiler, gravity_closure_t *closure, const char *path) {
  162. if (!closure) return false;
  163. json_t *json = gravity_compiler_serialize(compiler, closure);
  164. if (!json) return false;
  165. json_write_file(json, path);
  166. json_free(json);
  167. return true;
  168. }