Преглед изворни кода

Added sample code to show how to execute c methods in a c class from within Gravity.

Marco Bambini пре 8 година
родитељ
комит
e198a3561f
3 измењених фајлова са 306 додато и 3 уклоњено
  1. 7 3
      api/Makefile
  2. 110 0
      api/api.xcodeproj/project.pbxproj
  3. 189 0
      api/exec_c.c

+ 7 - 3
api/Makefile

@@ -3,6 +3,7 @@ RUNTIME_DIR = ../src/runtime/
 SHARED_DIR = ../src/shared/
 UTILS_DIR = ../src/utils/
 EXEC_GRAVITY_SRC = exec_gravity.c
+EXEC_C_SRC = exec_c.c
 
 SRC = $(wildcard $(COMPILER_DIR)*.c) \
       $(wildcard $(RUNTIME_DIR)/*.c) \
@@ -27,12 +28,15 @@ else
 	endif
 endif
 
-all: exec_gravity
+all: exec_gravity exec_c
 
 exec_gravity:	$(OBJ) $(EXEC_GRAVITY_SRC)
 	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+	
+exec_c:	$(OBJ) $(EXEC_C_SRC)
+	$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
 
-.PHONY: all clean exec_gravity
+.PHONY: all clean exec_gravity exec_c
 
 clean:
-	rm -f $(OBJ) exec_gravity
+	rm -f $(OBJ) exec_gravity exec_c

+ 110 - 0
api/api.xcodeproj/project.pbxproj

@@ -28,6 +28,27 @@
 		A922BB061E6E0F5C00D9FAD0 /* gravity_json.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAEE1E6E0F5C00D9FAD0 /* gravity_json.c */; };
 		A922BB071E6E0F5C00D9FAD0 /* gravity_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAF01E6E0F5C00D9FAD0 /* gravity_utils.c */; };
 		A9BA7D451E74180100259798 /* exec_gravity.c in Sources */ = {isa = PBXBuildFile; fileRef = A9BA7D441E74180100259798 /* exec_gravity.c */; };
+		A9FE6A1A1E753077007FC86B /* gravity_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAE31E6E0F5C00D9FAD0 /* gravity_hash.c */; };
+		A9FE6A1B1E753077007FC86B /* exec_c.c in Sources */ = {isa = PBXBuildFile; fileRef = A9FE6A151E753041007FC86B /* exec_c.c */; };
+		A9FE6A1C1E753077007FC86B /* gravity_value.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAE91E6E0F5C00D9FAD0 /* gravity_value.c */; };
+		A9FE6A1D1E753077007FC86B /* gravity_token.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAD61E6E0F5C00D9FAD0 /* gravity_token.c */; };
+		A9FE6A1E1E753077007FC86B /* gravity_visitor.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAD81E6E0F5C00D9FAD0 /* gravity_visitor.c */; };
+		A9FE6A1F1E753077007FC86B /* gravity_optimizer.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BACC1E6E0F5C00D9FAD0 /* gravity_optimizer.c */; };
+		A9FE6A201E753077007FC86B /* gravity_ircode.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAC81E6E0F5C00D9FAD0 /* gravity_ircode.c */; };
+		A9FE6A211E753077007FC86B /* gravity_ast.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAC21E6E0F5C00D9FAD0 /* gravity_ast.c */; };
+		A9FE6A221E753077007FC86B /* gravity_lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BACA1E6E0F5C00D9FAD0 /* gravity_lexer.c */; };
+		A9FE6A231E753077007FC86B /* gravity_symboltable.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAD41E6E0F5C00D9FAD0 /* gravity_symboltable.c */; };
+		A9FE6A241E753077007FC86B /* gravity_json.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAEE1E6E0F5C00D9FAD0 /* gravity_json.c */; };
+		A9FE6A251E753077007FC86B /* gravity_parser.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BACE1E6E0F5C00D9FAD0 /* gravity_parser.c */; };
+		A9FE6A261E753077007FC86B /* gravity_semacheck2.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAD21E6E0F5C00D9FAD0 /* gravity_semacheck2.c */; };
+		A9FE6A271E753077007FC86B /* gravity_debug.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAEC1E6E0F5C00D9FAD0 /* gravity_debug.c */; };
+		A9FE6A281E753077007FC86B /* gravity_semacheck1.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAD01E6E0F5C00D9FAD0 /* gravity_semacheck1.c */; };
+		A9FE6A291E753077007FC86B /* gravity_core.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BADB1E6E0F5C00D9FAD0 /* gravity_core.c */; };
+		A9FE6A2A1E753077007FC86B /* gravity_vm.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BADD1E6E0F5C00D9FAD0 /* gravity_vm.c */; };
+		A9FE6A2B1E753077007FC86B /* gravity_codegen.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAC41E6E0F5C00D9FAD0 /* gravity_codegen.c */; };
+		A9FE6A2C1E753077007FC86B /* gravity_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAE61E6E0F5C00D9FAD0 /* gravity_memory.c */; };
+		A9FE6A2D1E753077007FC86B /* gravity_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAF01E6E0F5C00D9FAD0 /* gravity_utils.c */; };
+		A9FE6A2E1E753077007FC86B /* gravity_compiler.c in Sources */ = {isa = PBXBuildFile; fileRef = A922BAC61E6E0F5C00D9FAD0 /* gravity_compiler.c */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -40,6 +61,15 @@
 			);
 			runOnlyForDeploymentPostprocessing = 1;
 		};
+		A9FE6A301E753077007FC86B /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
@@ -91,6 +121,8 @@
 		A922BAF01E6E0F5C00D9FAD0 /* gravity_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gravity_utils.c; sourceTree = "<group>"; };
 		A922BAF11E6E0F5C00D9FAD0 /* gravity_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gravity_utils.h; sourceTree = "<group>"; };
 		A9BA7D441E74180100259798 /* exec_gravity.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exec_gravity.c; sourceTree = "<group>"; };
+		A9FE6A151E753041007FC86B /* exec_c.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exec_c.c; sourceTree = "<group>"; };
+		A9FE6A341E753077007FC86B /* exec_c */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = exec_c; sourceTree = BUILT_PRODUCTS_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -101,6 +133,13 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		A9FE6A2F1E753077007FC86B /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
@@ -108,6 +147,7 @@
 			isa = PBXGroup;
 			children = (
 				A9BA7D441E74180100259798 /* exec_gravity.c */,
+				A9FE6A151E753041007FC86B /* exec_c.c */,
 				A922BABC1E6E0F5C00D9FAD0 /* gravity */,
 				A922BAB11E6E0F2600D9FAD0 /* Products */,
 			);
@@ -117,6 +157,7 @@
 			isa = PBXGroup;
 			children = (
 				A922BAB01E6E0F2600D9FAD0 /* exec_gravity */,
+				A9FE6A341E753077007FC86B /* exec_c */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -227,6 +268,23 @@
 			productReference = A922BAB01E6E0F2600D9FAD0 /* exec_gravity */;
 			productType = "com.apple.product-type.tool";
 		};
+		A9FE6A171E753077007FC86B /* exec_c */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = A9FE6A311E753077007FC86B /* Build configuration list for PBXNativeTarget "exec_c" */;
+			buildPhases = (
+				A9FE6A181E753077007FC86B /* Sources */,
+				A9FE6A2F1E753077007FC86B /* Frameworks */,
+				A9FE6A301E753077007FC86B /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = exec_c;
+			productName = api;
+			productReference = A9FE6A341E753077007FC86B /* exec_c */;
+			productType = "com.apple.product-type.tool";
+		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
@@ -255,6 +313,7 @@
 			projectRoot = "";
 			targets = (
 				A922BAAF1E6E0F2600D9FAD0 /* exec_gravity */,
+				A9FE6A171E753077007FC86B /* exec_c */,
 			);
 		};
 /* End PBXProject section */
@@ -288,6 +347,34 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		A9FE6A181E753077007FC86B /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				A9FE6A1A1E753077007FC86B /* gravity_hash.c in Sources */,
+				A9FE6A1B1E753077007FC86B /* exec_c.c in Sources */,
+				A9FE6A1C1E753077007FC86B /* gravity_value.c in Sources */,
+				A9FE6A1D1E753077007FC86B /* gravity_token.c in Sources */,
+				A9FE6A1E1E753077007FC86B /* gravity_visitor.c in Sources */,
+				A9FE6A1F1E753077007FC86B /* gravity_optimizer.c in Sources */,
+				A9FE6A201E753077007FC86B /* gravity_ircode.c in Sources */,
+				A9FE6A211E753077007FC86B /* gravity_ast.c in Sources */,
+				A9FE6A221E753077007FC86B /* gravity_lexer.c in Sources */,
+				A9FE6A231E753077007FC86B /* gravity_symboltable.c in Sources */,
+				A9FE6A241E753077007FC86B /* gravity_json.c in Sources */,
+				A9FE6A251E753077007FC86B /* gravity_parser.c in Sources */,
+				A9FE6A261E753077007FC86B /* gravity_semacheck2.c in Sources */,
+				A9FE6A271E753077007FC86B /* gravity_debug.c in Sources */,
+				A9FE6A281E753077007FC86B /* gravity_semacheck1.c in Sources */,
+				A9FE6A291E753077007FC86B /* gravity_core.c in Sources */,
+				A9FE6A2A1E753077007FC86B /* gravity_vm.c in Sources */,
+				A9FE6A2B1E753077007FC86B /* gravity_codegen.c in Sources */,
+				A9FE6A2C1E753077007FC86B /* gravity_memory.c in Sources */,
+				A9FE6A2D1E753077007FC86B /* gravity_utils.c in Sources */,
+				A9FE6A2E1E753077007FC86B /* gravity_compiler.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
@@ -392,6 +479,20 @@
 			};
 			name = Release;
 		};
+		A9FE6A321E753077007FC86B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		A9FE6A331E753077007FC86B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
@@ -413,6 +514,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		A9FE6A311E753077007FC86B /* Build configuration list for PBXNativeTarget "exec_c" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				A9FE6A321E753077007FC86B /* Debug */,
+				A9FE6A331E753077007FC86B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
 	};
 	rootObject = A922BAA81E6E0F2600D9FAD0 /* Project object */;

+ 189 - 0
api/exec_c.c

@@ -0,0 +1,189 @@
+//
+//  Sample code to demonstrate how to execute C code from Gravity
+//  Created by Marco Bambini on 12/03/2017.
+//
+
+#include <stdio.h>
+#include <math.h>
+
+#include "gravity_compiler.h"
+#include "gravity_macros.h"
+#include "gravity_core.h"
+#include "gravity_vm.h"
+
+#define CLASS_NAME	"Math"
+
+// gravity func source code
+// Math is declared as extern because it will be later defined in C
+static const char *source =	"	extern var Math;				\
+								func main() {					\
+									var pi = Math.pi;			\
+									var n1 = Math.log(pi);		\
+									var n2 = Math.pow(pi,2.12);	\
+									return n1 + n2;				\
+								}";
+
+// error callback
+static void report_error (error_type_t error_type, const char *message,
+						  error_desc_t error_desc, void *xdata) {
+#pragma unused(xdata)
+	const char *type = "N/A";
+	switch (error_type) {
+		case GRAVITY_ERROR_NONE: type = "NONE"; break;
+		case GRAVITY_ERROR_SYNTAX: type = "SYNTAX"; break;
+		case GRAVITY_ERROR_SEMANTIC: type = "SEMANTIC"; break;
+		case GRAVITY_ERROR_RUNTIME: type = "RUNTIME"; break;
+		case GRAVITY_WARNING: type = "WARNING"; break;
+		case GRAVITY_ERROR_IO: type = "I/O"; break;
+	}
+	
+	if (error_type == GRAVITY_ERROR_RUNTIME) printf("RUNTIME ERROR: ");
+	else printf("%s ERROR on %d (%d,%d): ", type, error_desc.fileid, error_desc.lineno, error_desc.colno);
+	printf("%s\n", message);
+}
+
+// MARK: -
+
+static bool math_pi (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	#pragma unused (args, nargs)
+	gravity_vm_setslot(vm, VALUE_FROM_FLOAT(3.1315f), rindex);
+	return true;
+}
+
+static bool math_log (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	// missing parameters check here
+	// 1. number of args
+	// 2. args type
+	
+	// assuming arg of type float (in a real example there should be a conversion if not float)
+	gravity_float_t n = VALUE_AS_FLOAT(args[1]);
+	
+	// gravity can be compiled with FLOAT as 32 or 64 bit
+	#if GRAVITY_ENABLE_DOUBLE
+	gravity_float_t result = (gravity_float_t)log(n);
+	#else
+	gravity_float_t result = (gravity_float_t)logf(n);
+	#endif
+	
+	gravity_vm_setslot(vm, VALUE_FROM_FLOAT(result), rindex);
+	return true;
+}
+
+static bool math_pow (gravity_vm *vm, gravity_value_t *args, uint16_t nargs, uint32_t rindex) {
+	// missing parameters check here
+	// 1. number of args
+	// 2. args type
+	
+	// assuming arg 1 of type float (in a real example there should be a conversion if not float)
+	gravity_float_t n1 = VALUE_AS_FLOAT(args[1]);
+	
+	// assuming arg 2 of type float (in a real example there should be a conversion if not float)
+	gravity_float_t n2 = VALUE_AS_FLOAT(args[2]);
+	
+	double result = pow((double)n1, (double)n2);
+	
+	gravity_vm_setslot(vm, VALUE_FROM_FLOAT((gravity_float_t)result), rindex);
+	return true;
+}
+
+// MARK: -
+
+static void create_math_class (gravity_vm *vm) {
+	// create a new class (a pair of classes since we are creating a class and its meta-class)
+	gravity_class_t *c = gravity_class_new_pair(NULL, CLASS_NAME, NULL, 0, 0);
+	
+	// we want to register properties and methods callback to its meta-class
+	// so user can access Math.property and Math.method without the need to instantiate it
+	
+	// get its meta-class
+	gravity_class_t *meta = gravity_class_get_meta(c);
+	
+	// start binding methods and properties (special methods) to the meta class
+	
+	// *** LOG METHOD ***
+	// 1. create a gravity_function_t from the c function
+	gravity_function_t *logf = gravity_function_new_internal(NULL, NULL, math_log, 0);
+	
+	// 2. create a closure from the gravity_function_t
+	gravity_closure_t *logc = gravity_closure_new(NULL, logf);
+	
+	// 3. bind closure VALUE to meta class
+	gravity_class_bind(meta, "log", VALUE_FROM_OBJECT(logc));
+	
+	// *** POW METHOD ***
+	// 1. create a gravity_function_t from the c function
+	gravity_function_t *powf = gravity_function_new_internal(NULL, NULL, math_pow, 0);
+	
+	// 2. create a closure from the gravity_function_t
+	gravity_closure_t *powc = gravity_closure_new(NULL, powf);
+	
+	// 3. bind closure VALUE to meta class
+	gravity_class_bind(meta, "pow", VALUE_FROM_OBJECT(powc));
+	
+	// *** PI PROPERTY (getter only) ***
+	// 1. create a gravity_function_t from the c function
+	gravity_function_t *pif = gravity_function_new_internal(NULL, NULL, math_pi, 0);
+	
+	// 2. create a closure from the gravity_function_t
+	gravity_closure_t *pi_getter = gravity_closure_new(NULL, pif);
+	
+	// 3. create a new special function to represents getter and setter (NULL in this case)
+	gravity_function_t *f = gravity_function_new_special(vm, NULL, GRAVITY_COMPUTED_INDEX, pi_getter, NULL);
+	
+	// 4. create a closure for the special function
+	gravity_closure_t *closure_property = gravity_closure_new(NULL, f);
+	
+	// 5. bind closure VALUE to meta class
+	gravity_class_bind(meta, "pi", VALUE_FROM_OBJECT(closure_property));
+	
+	// LAST STEP
+	// register newly defined C class into Gravity VM
+	gravity_vm_setvalue(vm, CLASS_NAME, VALUE_FROM_OBJECT(c));
+}
+
+// MARK: -
+
+int main(int argc, const char * argv[]) {
+	
+	// setup a minimal delegate
+	gravity_delegate_t delegate = {
+		.error_callback = report_error
+	};
+	
+	// compile source into a closure
+	gravity_compiler_t *compiler = gravity_compiler_create(&delegate);
+	gravity_closure_t *closure = gravity_compiler_run(compiler, source, strlen(source), 0, true);
+	if (!closure) return -1;
+	
+	// setup a new VM and a new fiber
+	gravity_vm *vm = gravity_vm_new(&delegate);
+	
+	// transfer memory from compiler to VM and then free compiler
+	gravity_compiler_transfer(compiler, vm);
+	gravity_compiler_free(compiler);
+	
+	// create a new math class with methods and properties and register it to the VM
+	create_math_class(vm);
+	
+	// expected result: 12.387436
+	// pi = 3.1415
+	// n1 = log(pi) => 1.1447
+	// n2 = pow(pi, 2.12) => 11.3221
+	
+	// Math class is now available from Gravity code so we can start excuting previously compiled closure
+	if (gravity_vm_runmain(vm, closure)) {
+		gravity_value_t result = gravity_vm_result(vm);
+		double t = gravity_vm_time(vm);
+		
+		char buffer[512];
+		gravity_value_dump(result, buffer, sizeof(buffer));
+		printf("RESULT: %s (in %.4f ms)\n\n", buffer, t);
+	}
+	
+	// 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
+	// free class and its methods here
+	
+	// free vm and base classes
+	if (vm) gravity_vm_free(vm);
+	gravity_core_free();
+}