exec_c.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //
  2. // Sample code to demonstrate how to execute C code from Gravity
  3. // Created by Marco Bambini on 12/03/2017.
  4. //
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include "gravity_compiler.h"
  8. #include "gravity_macros.h"
  9. #include "gravity_core.h"
  10. #include "gravity_vm.h"
  11. #define CLASS_NAME "Math"
  12. // gravity func source code
  13. // Math is declared as extern because it will be later defined in C
  14. static const char *source = " extern var Math; \
  15. func main() { \
  16. var pi = Math.pi; \
  17. var n1 = Math.log(pi); \
  18. var n2 = Math.pow(pi,2.12); \
  19. return n1 + n2; \
  20. }";
  21. // error callback
  22. static void report_error (gravity_vm *vm, error_type_t error_type, const char *message,
  23. error_desc_t error_desc, void *xdata) {
  24. #pragma unused(vm, xdata)
  25. const char *type = "N/A";
  26. switch (error_type) {
  27. case GRAVITY_ERROR_NONE: type = "NONE"; break;
  28. case GRAVITY_ERROR_SYNTAX: type = "SYNTAX"; break;
  29. case GRAVITY_ERROR_SEMANTIC: type = "SEMANTIC"; break;
  30. case GRAVITY_ERROR_RUNTIME: type = "RUNTIME"; break;
  31. case GRAVITY_WARNING: type = "WARNING"; break;
  32. case GRAVITY_ERROR_IO: type = "I/O"; break;
  33. }
  34. if (error_type == GRAVITY_ERROR_RUNTIME) printf("RUNTIME ERROR: ");
  35. else printf("%s ERROR on %d (%d,%d): ", type, error_desc.fileid, error_desc.lineno, error_desc.colno);
  36. printf("%s\n", message);
  37. }
  38. // MARK: -
  39. static bool math_pi (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
  40. #pragma unused (args, nargs)
  41. gravity_vm_setslot(vm, VALUE_FROM_FLOAT(3.1315f), rindex);
  42. return true;
  43. }
  44. static bool math_log (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
  45. // missing parameters check here
  46. // 1. number of args
  47. // 2. args type
  48. // assuming arg of type float (in a real example there should be a conversion if not float)
  49. gravity_float_t n = VALUE_AS_FLOAT(args[1]);
  50. // gravity can be compiled with FLOAT as 32 or 64 bit
  51. #if GRAVITY_ENABLE_DOUBLE
  52. gravity_float_t result = (gravity_float_t)log(n);
  53. #else
  54. gravity_float_t result = (gravity_float_t)logf(n);
  55. #endif
  56. gravity_vm_setslot(vm, VALUE_FROM_FLOAT(result), rindex);
  57. return true;
  58. }
  59. static bool math_pow (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
  60. // missing parameters check here
  61. // 1. number of args
  62. // 2. args type
  63. // assuming arg 1 of type float (in a real example there should be a conversion if not float)
  64. gravity_float_t n1 = VALUE_AS_FLOAT(args[1]);
  65. // assuming arg 2 of type float (in a real example there should be a conversion if not float)
  66. gravity_float_t n2 = VALUE_AS_FLOAT(args[2]);
  67. double result = pow((double)n1, (double)n2);
  68. gravity_vm_setslot(vm, VALUE_FROM_FLOAT((gravity_float_t)result), rindex);
  69. return true;
  70. }
  71. // MARK: -
  72. static void create_math_class (gravity_vm *vm) {
  73. // create a new class (a pair of classes since we are creating a class and its meta-class)
  74. gravity_class_t *c = gravity_class_new_pair(NULL, CLASS_NAME, NULL, 0, 0);
  75. // we want to register properties and methods callback to its meta-class
  76. // so user can access Math.property and Math.method without the need to instantiate it
  77. // get its meta-class
  78. gravity_class_t *meta = gravity_class_get_meta(c);
  79. // start binding methods and properties (special methods) to the meta class
  80. // *** LOG METHOD ***
  81. // 1. create a gravity_function_t from the c function
  82. gravity_function_t *logf = gravity_function_new_internal(NULL, NULL, math_log, 0);
  83. // 2. create a closure from the gravity_function_t
  84. gravity_closure_t *logc = gravity_closure_new(NULL, logf);
  85. // 3. bind closure VALUE to meta class
  86. gravity_class_bind(meta, "log", VALUE_FROM_OBJECT(logc));
  87. // *** POW METHOD ***
  88. // 1. create a gravity_function_t from the c function
  89. gravity_function_t *powf = gravity_function_new_internal(NULL, NULL, math_pow, 0);
  90. // 2. create a closure from the gravity_function_t
  91. gravity_closure_t *powc = gravity_closure_new(NULL, powf);
  92. // 3. bind closure VALUE to meta class
  93. gravity_class_bind(meta, "pow", VALUE_FROM_OBJECT(powc));
  94. // *** PI PROPERTY (getter only) ***
  95. // 1. create a gravity_function_t from the c function
  96. gravity_function_t *pif = gravity_function_new_internal(NULL, NULL, math_pi, 0);
  97. // 2. create a closure from the gravity_function_t
  98. gravity_closure_t *pi_getter = gravity_closure_new(NULL, pif);
  99. // 3. create a new special function to represents getter and setter (NULL in this case)
  100. gravity_function_t *f = gravity_function_new_special(vm, NULL, GRAVITY_COMPUTED_INDEX, pi_getter, NULL);
  101. // 4. create a closure for the special function
  102. gravity_closure_t *closure_property = gravity_closure_new(NULL, f);
  103. // 5. bind closure VALUE to meta class
  104. gravity_class_bind(meta, "pi", VALUE_FROM_OBJECT(closure_property));
  105. // LAST STEP
  106. // register newly defined C class into Gravity VM
  107. gravity_vm_setvalue(vm, CLASS_NAME, VALUE_FROM_OBJECT(c));
  108. }
  109. // MARK: -
  110. int main(int argc, const char * argv[]) {
  111. // setup a minimal delegate
  112. gravity_delegate_t delegate = {
  113. .error_callback = report_error
  114. };
  115. // compile source into a closure
  116. gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
  117. gravity_closure_t *closure = gravity_compiler_run(compiler, source, strlen(source), 0, true, true);
  118. if (!closure) return -1;
  119. // setup a new VM and a new fiber
  120. gravity_vm *vm = gravity_vm_new(&delegate);
  121. // transfer memory from compiler to VM and then free compiler
  122. gravity_compiler_transfer(compiler, vm);
  123. gravity_compiler_free(compiler);
  124. // create a new math class with methods and properties and register it to the VM
  125. create_math_class(vm);
  126. // expected result: 12.387436
  127. // pi = 3.1415
  128. // n1 = log(pi) => 1.1447
  129. // n2 = pow(pi, 2.12) => 11.3221
  130. // Math class is now available from Gravity code so we can start excuting previously compiled closure
  131. if (gravity_vm_runmain(vm, closure)) {
  132. gravity_value_t result = gravity_vm_result(vm);
  133. double t = gravity_vm_time(vm);
  134. char buffer[512];
  135. gravity_value_dump(vm, result, buffer, sizeof(buffer));
  136. printf("RESULT: %s (in %.4f ms)\n\n", buffer, t);
  137. }
  138. // our Math C class was not exposed to the GC (we passed NULL as vm parameter) so we would need to manually free it here
  139. // free class and its methods here
  140. // free vm and base classes
  141. if (vm) gravity_vm_free(vm);
  142. gravity_core_free();
  143. }