194 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			194 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | #ifndef GROUND_LIB_H
 | ||
|  | #define GROUND_LIB_H
 | ||
|  | 
 | ||
|  | #include <cstring>
 | ||
|  | #include <string>
 | ||
|  | #include <vector>
 | ||
|  | #include <iostream>
 | ||
|  | 
 | ||
|  | // Ground types - must match the interpreter
 | ||
|  | typedef enum { | ||
|  |     GROUND_INT, | ||
|  |     GROUND_DOUBLE,  | ||
|  |     GROUND_BOOL, | ||
|  |     GROUND_STRING, | ||
|  |     GROUND_CHAR | ||
|  | } GroundType; | ||
|  | 
 | ||
|  | typedef struct { | ||
|  |     GroundType type; | ||
|  |     union { | ||
|  |         int int_val; | ||
|  |         double double_val; | ||
|  |         int bool_val; | ||
|  |         char* string_val; | ||
|  |         char char_val; | ||
|  |     } data; | ||
|  | } GroundValue; | ||
|  | 
 | ||
|  | // Helper macros for creating GroundValue objects
 | ||
|  | #define GROUND_INT_VAL(x) ({ GroundValue v; v.type = GROUND_INT; v.data.int_val = (x); v; })
 | ||
|  | #define GROUND_DOUBLE_VAL(x) ({ GroundValue v; v.type = GROUND_DOUBLE; v.data.double_val = (x); v; })
 | ||
|  | #define GROUND_BOOL_VAL(x) ({ GroundValue v; v.type = GROUND_BOOL; v.data.bool_val = (x) ? 1 : 0; v; })
 | ||
|  | #define GROUND_CHAR_VAL(x) ({ GroundValue v; v.type = GROUND_CHAR; v.data.char_val = (x); v; })
 | ||
|  | 
 | ||
|  | // Helper function for creating string values
 | ||
|  | inline GroundValue ground_string_val(const std::string& str) { | ||
|  |     GroundValue v; | ||
|  |     v.type = GROUND_STRING; | ||
|  |     char* result_str = new char[str.length() + 1]; | ||
|  |     std::strcpy(result_str, str.c_str()); | ||
|  |     v.data.string_val = result_str; | ||
|  |     return v; | ||
|  | } | ||
|  | 
 | ||
|  | // Helper function for creating string values from C strings
 | ||
|  | inline GroundValue ground_cstring_val(const char* str) { | ||
|  |     GroundValue v; | ||
|  |     v.type = GROUND_STRING; | ||
|  |     if (str) { | ||
|  |         size_t len = std::strlen(str); | ||
|  |         char* result_str = new char[len + 1]; | ||
|  |         std::strcpy(result_str, str); | ||
|  |         v.data.string_val = result_str; | ||
|  |     } else { | ||
|  |         v.data.string_val = nullptr; | ||
|  |     } | ||
|  |     return v; | ||
|  | } | ||
|  | 
 | ||
|  | // Helper macros for type checking
 | ||
|  | #define IS_INT(v) ((v).type == GROUND_INT)
 | ||
|  | #define IS_DOUBLE(v) ((v).type == GROUND_DOUBLE)
 | ||
|  | #define IS_BOOL(v) ((v).type == GROUND_BOOL)
 | ||
|  | #define IS_STRING(v) ((v).type == GROUND_STRING)
 | ||
|  | #define IS_CHAR(v) ((v).type == GROUND_CHAR)
 | ||
|  | 
 | ||
|  | // Helper macros for extracting values
 | ||
|  | #define GET_INT(v) ((v).data.int_val)
 | ||
|  | #define GET_DOUBLE(v) ((v).data.double_val)
 | ||
|  | #define GET_BOOL(v) ((v).data.bool_val != 0)
 | ||
|  | #define GET_STRING(v) ((v).data.string_val)
 | ||
|  | #define GET_CHAR(v) ((v).data.char_val)
 | ||
|  | 
 | ||
|  | // Helper macros for argument validation
 | ||
|  | #define REQUIRE_ARGS(count) \
 | ||
|  |     if (arg_count < (count)) { \ | ||
|  |         std::cerr << "Error: Expected at least " << (count) << " arguments, got " << arg_count << std::endl; \ | ||
|  |         return GROUND_BOOL_VAL(false); \ | ||
|  |     } | ||
|  | 
 | ||
|  | #define REQUIRE_TYPE(arg_index, expected_type) \
 | ||
|  |     if (args[arg_index].type != expected_type) { \ | ||
|  |         std::cerr << "Error: Argument " << (arg_index + 1) << " must be of type " << #expected_type << std::endl; \ | ||
|  |         return GROUND_BOOL_VAL(false); \ | ||
|  |     } | ||
|  | 
 | ||
|  | // Convenience macro for checking both arg count and types
 | ||
|  | #define VALIDATE_ARGS_1(type1) \
 | ||
|  |     REQUIRE_ARGS(1); \ | ||
|  |     REQUIRE_TYPE(0, type1); | ||
|  | 
 | ||
|  | #define VALIDATE_ARGS_2(type1, type2) \
 | ||
|  |     REQUIRE_ARGS(2); \ | ||
|  |     REQUIRE_TYPE(0, type1); \ | ||
|  |     REQUIRE_TYPE(1, type2); | ||
|  | 
 | ||
|  | #define VALIDATE_ARGS_3(type1, type2, type3) \
 | ||
|  |     REQUIRE_ARGS(3); \ | ||
|  |     REQUIRE_TYPE(0, type1); \ | ||
|  |     REQUIRE_TYPE(1, type2); \ | ||
|  |     REQUIRE_TYPE(2, type3); | ||
|  | 
 | ||
|  | // Function registration helpers
 | ||
|  | class GroundLibrary { | ||
|  | private: | ||
|  |     std::vector<std::string> function_names; | ||
|  |     std::vector<void*> function_pointers; | ||
|  |      | ||
|  | public: | ||
|  |     void register_function(const std::string& name, void* ptr) { | ||
|  |         function_names.push_back(name); | ||
|  |         function_pointers.push_back(ptr); | ||
|  |     } | ||
|  |      | ||
|  |     const char** get_function_names() { | ||
|  |         static std::vector<const char*> names; | ||
|  |         names.clear(); | ||
|  |         for (const auto& name : function_names) { | ||
|  |             names.push_back(name.c_str()); | ||
|  |         } | ||
|  |         names.push_back(nullptr);  // Null terminator
 | ||
|  |         return names.data(); | ||
|  |     } | ||
|  |      | ||
|  |     void* get_function(const char* name) { | ||
|  |         for (size_t i = 0; i < function_names.size(); i++) { | ||
|  |             if (function_names[i] == name) { | ||
|  |                 return function_pointers[i]; | ||
|  |             } | ||
|  |         } | ||
|  |         return nullptr; | ||
|  |     } | ||
|  | }; | ||
|  | 
 | ||
|  | // Global library instance
 | ||
|  | extern GroundLibrary ground_lib_registry; | ||
|  | 
 | ||
|  | // Macro to register functions easily
 | ||
|  | #define REGISTER_GROUND_FUNCTION(func_name) \
 | ||
|  |     ground_lib_registry.register_function(#func_name, (void*)func_name) | ||
|  | 
 | ||
|  | // Macro to define the library interface
 | ||
|  | #define GROUND_LIBRARY_INTERFACE() \
 | ||
|  |     GroundLibrary ground_lib_registry; \ | ||
|  |     extern "C" { \ | ||
|  |         const char** ground_get_functions() { \ | ||
|  |             return ground_lib_registry.get_function_names(); \ | ||
|  |         } \ | ||
|  |         void* ground_get_function(const char* name) { \ | ||
|  |             return ground_lib_registry.get_function(name); \ | ||
|  |         } \ | ||
|  |     } | ||
|  | 
 | ||
|  | // Optional initialization macro
 | ||
|  | #define GROUND_LIBRARY_INIT() \
 | ||
|  |     extern "C" { \ | ||
|  |         void ground_lib_init() { | ||
|  | 
 | ||
|  | #define GROUND_LIBRARY_INIT_END() \
 | ||
|  |         } \ | ||
|  |     } | ||
|  | 
 | ||
|  | // Optional cleanup macro
 | ||
|  | #define GROUND_LIBRARY_CLEANUP() \
 | ||
|  |     extern "C" { \ | ||
|  |         void ground_lib_cleanup() { | ||
|  | 
 | ||
|  | #define GROUND_LIBRARY_CLEANUP_END() \
 | ||
|  |         } \ | ||
|  |     } | ||
|  | 
 | ||
|  | // Utility function to print GroundValue for debugging
 | ||
|  | inline void debug_print_ground_value(const GroundValue& v) { | ||
|  |     switch (v.type) { | ||
|  |         case GROUND_INT: | ||
|  |             std::cout << "INT: " << v.data.int_val << std::endl; | ||
|  |             break; | ||
|  |         case GROUND_DOUBLE: | ||
|  |             std::cout << "DOUBLE: " << v.data.double_val << std::endl; | ||
|  |             break; | ||
|  |         case GROUND_BOOL: | ||
|  |             std::cout << "BOOL: " << (v.data.bool_val ? "true" : "false") << std::endl; | ||
|  |             break; | ||
|  |         case GROUND_STRING: | ||
|  |             std::cout << "STRING: " << (v.data.string_val ? v.data.string_val : "(null)") << std::endl; | ||
|  |             break; | ||
|  |         case GROUND_CHAR: | ||
|  |             std::cout << "CHAR: '" << v.data.char_val << "'" << std::endl; | ||
|  |             break; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | #endif // GROUND_LIB_H
 |