1 //
2 // main.cpp
3 // GravityCpp
4 //
5 // Created by Marco Bambini on 26/12/2018.
6 // Copyright © 2018 Creolabs. All rights reserved.
7 //
8
9 #include "gravity_compiler.h"
10 #include "gravity_core.h"
11 #include "gravity_vm.h"
12 #include "gravity_macros.h"
13 #include "gravity_vmmacros.h"
14 #include "gravity_opcodes.h"
15 #include <iostream>
16 using namespace std;
17
18 // MARK: - C++ code -
19
20 class Rectangle {
21 public:
22 double length;
23 double height;
24
25 // Constructor
Rectangle(double l=2.0,double h=2.0)26 Rectangle(double l = 2.0, double h = 2.0) {
27 cout << "Rectangle constructor called." << endl;
28 length = l;
29 height = h;
30 }
31
~Rectangle()32 virtual ~Rectangle() {
33 cout << "Rectangle destructor called." << endl;
34 }
35
36 // Methods
Area()37 double Area() {
38 return length * height;
39 }
40
Test(double p1,int32_t p2,string p3)41 void Test(double p1, int32_t p2, string p3) {
42 cout << "Rectangle test: " << p1 << p2 << p3 << endl;
43 }
44 };
45
46 // MARK: - Gravity Bridge -
47
rect_create(gravity_vm * vm,gravity_value_t * args,uint16_t nargs,uint32_t rindex)48 static bool rect_create (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
49 // check for optional parameters here (if you need to process a more complex constructor)
50
51 // self parameter is the rect_class create in register_cpp_classes
52 gravity_class_t *c = (gravity_class_t *)GET_VALUE(0).p;
53
54 // create Gravity instance and set its class to c
55 gravity_instance_t *instance = gravity_instance_new(vm, c);
56
57 // allocate a cpp instance of the Rectangle class on the heap
58 Rectangle *r = new Rectangle();
59
60 // set cpp instance and xdata of the gravity instance (for later used in the rect_area and rect_test functions)
61 gravity_instance_setxdata(instance, r);
62
63 // return instance
64 RETURN_VALUE(VALUE_FROM_OBJECT(instance), rindex);
65 }
66
rect_area(gravity_vm * vm,gravity_value_t * args,uint16_t nargs,uint32_t rindex)67 static bool rect_area (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
68 // get self object which is the instance created in rect_create function
69 gravity_instance_t *instance = (gravity_instance_t *)GET_VALUE(0).p;
70
71 // get xdata (which is a cpp Rectangle instance)
72 Rectangle *r = (Rectangle *)instance->xdata;
73
74 // invoke the Area method
75 double d = r->Area();
76
77 RETURN_VALUE(VALUE_FROM_FLOAT(d), rindex);
78 }
79
rect_test(gravity_vm * vm,gravity_value_t * args,uint16_t nargs,uint32_t rindex)80 static bool rect_test (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
81 // get self object which is the instance created in rect_create function
82 gravity_instance_t *instance = (gravity_instance_t *)GET_VALUE(0).p;
83
84 // get xdata (which is a cpp Rectangle instance)
85 Rectangle *r = (Rectangle *)instance->xdata;
86
87 // invoke the Test method with dummy parameters
88 // the right way to proceed here would be to check for nargs first
89 // and then check if each parameter is of the right type
90 // and then bind parameters to the cpp call (using the std::bind method)
91 r->Test(3.0, 89, "rect_test");
92
93 RETURN_NOVALUE();
94 }
95
96 // MARK: -
97
length_get(gravity_vm * vm,gravity_value_t * args,uint16_t nargs,uint32_t rindex)98 static bool length_get (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
99 // get self object which is the instance created in rect_create function
100 gravity_instance_t *instance = (gravity_instance_t *)GET_VALUE(0).p;
101
102 // get xdata (which is a cpp Rectangle instance)
103 Rectangle *r = (Rectangle *)instance->xdata;
104
105 RETURN_VALUE(VALUE_FROM_FLOAT(r->length), rindex);
106 }
107
length_set(gravity_vm * vm,gravity_value_t * args,uint16_t nargs,uint32_t rindex)108 static bool length_set (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
109 // get self object which is the instance created in rect_create function
110 gravity_instance_t *instance = (gravity_instance_t *)GET_VALUE(0).p;
111
112 // get xdata (which is a cpp Rectangle instance)
113 Rectangle *r = (Rectangle *)instance->xdata;
114
115 // read user value
116 gravity_value_t value = GET_VALUE(1);
117
118 // decode value
119 double d = 0.0f;
120 if (VALUE_ISA_FLOAT(value)) d = VALUE_AS_FLOAT(value);
121 else if (VALUE_ISA_INT(value)) d = double(VALUE_AS_INT(value));
122 // more cases here, for example VALUE_ISA_STRING
123
124 r->length = d;
125
126 RETURN_NOVALUE();
127 }
128
129 // MARK: -
130
object_free(gravity_vm * vm,gravity_object_t * obj)131 static void object_free (gravity_vm *vm, gravity_object_t *obj) {
132 gravity_instance_t *instance = (gravity_instance_t *)obj;
133
134 // get xdata (which is a cpp Rectangle instance)
135 Rectangle *r = (Rectangle *)instance->xdata;
136
137 // explicitly free memory
138 delete r;
139 }
140
register_cpp_classes(gravity_vm * vm)141 void register_cpp_classes (gravity_vm *vm) {
142 // create Rectangle class
143 gravity_class_t *rect_class = gravity_class_new_pair(vm, "Rectangle", NULL, 0, 0);
144 gravity_class_t *rect_class_meta = gravity_class_get_meta(rect_class);
145
146 gravity_class_bind(rect_class_meta, GRAVITY_INTERNAL_EXEC_NAME, NEW_CLOSURE_VALUE(rect_create));
147 gravity_class_bind(rect_class, "area", NEW_CLOSURE_VALUE(rect_area));
148 gravity_class_bind(rect_class, "test", NEW_CLOSURE_VALUE(rect_test));
149 gravity_class_bind(rect_class, "length", VALUE_FROM_OBJECT(computed_property_create(NULL, NEW_FUNCTION(length_get), NEW_FUNCTION(length_set))));
150
151 // register Rectangle class inside VM
152 gravity_vm_setvalue(vm, "Rectangle", VALUE_FROM_OBJECT(rect_class));
153 }
154
155 // MARK: - Main -
156
report_error(gravity_vm * vm,error_type_t error_type,const char * message,error_desc_t error_desc,void * xdata)157 void report_error (gravity_vm *vm, error_type_t error_type, const char *message, error_desc_t error_desc, void *xdata) {
158 #pragma unused(vm, xdata)
159
160 const char *type = "N/A";
161 switch (error_type) {
162 case GRAVITY_ERROR_NONE: type = "NONE"; break;
163 case GRAVITY_ERROR_SYNTAX: type = "SYNTAX"; break;
164 case GRAVITY_ERROR_SEMANTIC: type = "SEMANTIC"; break;
165 case GRAVITY_ERROR_RUNTIME: type = "RUNTIME"; break;
166 case GRAVITY_WARNING: type = "WARNING"; break;
167 case GRAVITY_ERROR_IO: type = "I/O"; break;
168 }
169
170 if (error_type == GRAVITY_ERROR_RUNTIME) printf("RUNTIME ERROR: ");
171 else printf("%s ERROR on %d (%d,%d): ", type, error_desc.fileid, error_desc.lineno, error_desc.colno);
172 printf("%s\n", message);
173 }
174
main(int argc,const char * argv[])175 int main(int argc, const char * argv[]) {
176 cout << "Gravity version " << GRAVITY_VERSION << endl << endl;
177
178 const char source_code[] = "extern var Rectangle;"
179 "extern var Triangle;"
180 "func main() {"
181 "var r = Rectangle();"
182 "System.print(r.area());"
183 "r.test(1.0, 32, \"Hello\");"
184 "return 1;"
185 "}";
186
187 // setup delegate
188 gravity_delegate_t delegate = {
189 .error_callback = report_error,
190 .bridge_free = object_free
191 };
192
193 // setup compiler
194 gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
195
196 // compile source code
197 gravity_closure_t *closure = gravity_compiler_run(compiler, source_code, strlen(source_code), 0, true, true);
198 if (!closure) return -1; // syntax/semantic error
199
200 // setup Gravity VM
201 gravity_vm *vm = gravity_vm_new(&delegate);
202
203 // transfer memory from compiler to VM
204 gravity_compiler_transfer(compiler, vm);
205
206 // cleanup compiler
207 gravity_compiler_free(compiler);
208
209 // register my C++ classes inside Gravity VM
210 register_cpp_classes(vm);
211
212 // run main func
213 if (gravity_vm_runmain(vm, closure)) {
214 // print result to stdout
215 gravity_value_t result = gravity_vm_result(vm);
216 gravity_value_dump(vm, result, NULL, 0);
217 }
218
219 // cleanup
220 gravity_vm_free(vm);
221 gravity_core_free();
222
223 return 0;
224 }
225