Compare commits
14 Commits
09c2773a7a
...
math-branc
| Author | SHA1 | Date | |
|---|---|---|---|
| f2968f74b3 | |||
| 86096d6113 | |||
| 054af1631c | |||
| 754b63fb75 | |||
| 72162a7410 | |||
| fb4ded3f9e | |||
| 549eaedc04 | |||
| 6b719dccbe | |||
| 52e1e8d3d4 | |||
| 46bfa7fbf0 | |||
| 1c5300d27e | |||
| 100944cc1e | |||
| 96d7d9470a | |||
| c51bb82f62 |
@@ -7,10 +7,30 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Macro for easily returning errors
|
||||||
|
#define ERROR(what, type) return createErrorGroundValue(createGroundError(what, type, NULL, NULL))
|
||||||
|
|
||||||
// Forward declaration of the scope structure used in interpreter
|
// Forward declaration of the scope structure used in interpreter
|
||||||
struct GroundScope;
|
struct GroundScope;
|
||||||
typedef struct GroundScope GroundScope;
|
typedef struct GroundScope GroundScope;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stores data associated with an error thrown during Ground execution.
|
||||||
|
*/
|
||||||
|
typedef struct GroundError {
|
||||||
|
char* what;
|
||||||
|
char* type;
|
||||||
|
struct GroundInstruction* where;
|
||||||
|
size_t line;
|
||||||
|
bool hasLine;
|
||||||
|
} GroundError;
|
||||||
|
|
||||||
|
// Creates a GroundValue containing (in), with type ERROR.
|
||||||
|
GroundValue createErrorGroundValue(GroundError in);
|
||||||
|
|
||||||
|
// Creates a GroundError.
|
||||||
|
GroundError createGroundError(char* what, char* type, GroundInstruction* where, size_t* line);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function pointer type for native functions.
|
* Function pointer type for native functions.
|
||||||
* scope: The current execution scope (opaque).
|
* scope: The current execution scope (opaque).
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ GroundValue native_file_read(GroundScope* scope, List args) {
|
|||||||
char* path = args.values[0].data.stringVal;
|
char* path = args.values[0].data.stringVal;
|
||||||
FILE* f = fopen(path, "r");
|
FILE* f = fopen(path, "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return groundCreateValue(NONE);
|
ERROR("Failed to open file for reading", "FileError");
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
@@ -20,7 +20,7 @@ GroundValue native_file_read(GroundScope* scope, List args) {
|
|||||||
char* content = malloc(fsize + 1);
|
char* content = malloc(fsize + 1);
|
||||||
if (!content) {
|
if (!content) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return groundCreateValue(NONE);
|
ERROR("Failed to allocate memory for file reading", "FileError");
|
||||||
}
|
}
|
||||||
|
|
||||||
fread(content, 1, fsize, f);
|
fread(content, 1, fsize, f);
|
||||||
@@ -42,7 +42,7 @@ GroundValue native_file_write(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
FILE* f = fopen(path, "w");
|
FILE* f = fopen(path, "w");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return groundCreateValue(BOOL, 0);
|
ERROR("Failed to open file for writing", "FileError");
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(f, "%s", content);
|
fprintf(f, "%s", content);
|
||||||
|
|||||||
77
libs/math/math.c
Normal file
77
libs/math/math.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include <groundext.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
GroundValue ground_sin(GroundScope* scope, List args) {
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
sin(args.values[0].data.doubleVal)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GroundValue ground_cos(GroundScope* scope, List args) {
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
cos(args.values[0].data.doubleVal)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GroundValue ground_tan(GroundScope* scope, List args) {
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
tan(args.values[0].data.doubleVal)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue rad_to_deg(GroundScope* scope, List args) {
|
||||||
|
double radians = args.values[0].data.doubleVal;
|
||||||
|
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
radians * (180.0 / M_PI)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GroundValue deg_to_rad(GroundScope* scope, List args) {
|
||||||
|
double deg = args.values[0].data.doubleVal;
|
||||||
|
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
deg * (M_PI / 180.0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue ground_modulos(GroundScope* scope, List args) {
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
fmod(args.values[0].data.doubleVal, args.values[1].data.doubleVal)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GroundValue ground_pow(GroundScope* scope, List args) {
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
pow(args.values[0].data.doubleVal, args.values[1].data.doubleVal)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GroundValue ground_sqrt(GroundScope* scope, List args) {
|
||||||
|
double value = args.values[0].data.doubleVal;
|
||||||
|
|
||||||
|
if (value < 0) {
|
||||||
|
ERROR("Can't get square root of number less than 0.", "InvalidMath");
|
||||||
|
}
|
||||||
|
|
||||||
|
return groundCreateValue(
|
||||||
|
DOUBLE,
|
||||||
|
sqrt(value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ground_init(GroundScope* scope) {
|
||||||
|
groundAddNativeFunction(scope, "math_Sin", ground_sin, DOUBLE, 1, DOUBLE, "radians");
|
||||||
|
groundAddNativeFunction(scope, "math_Cos", ground_cos, DOUBLE, 1, DOUBLE, "radians");
|
||||||
|
groundAddNativeFunction(scope, "math_Tan", ground_tan, DOUBLE, 1, DOUBLE, "radians");
|
||||||
|
|
||||||
|
groundAddNativeFunction(scope, "math_DegreesToRadians", deg_to_rad, DOUBLE, 1, DOUBLE, "degrees");
|
||||||
|
groundAddNativeFunction(scope, "math_RadiansToDegrees", rad_to_deg, DOUBLE, 1, DOUBLE, "radians");
|
||||||
|
|
||||||
|
groundAddNativeFunction(scope, "math_Modulos", ground_modulos, DOUBLE, 2, DOUBLE, "number1", DOUBLE, "number2");
|
||||||
|
groundAddNativeFunction(scope, "math_Pow", ground_pow, DOUBLE, 2, DOUBLE, "number1", DOUBLE, "number2");
|
||||||
|
|
||||||
|
groundAddNativeFunction(scope, "math_Sqrt", ground_sqrt, DOUBLE, 1, DOUBLE, "number");
|
||||||
|
}
|
||||||
@@ -50,21 +50,11 @@ size_t write_callback(void* ptr, size_t size, size_t nmemb, void* userdata) {
|
|||||||
|
|
||||||
// GET request
|
// GET request
|
||||||
GroundValue get_request(GroundScope* scope, List args) {
|
GroundValue get_request(GroundScope* scope, List args) {
|
||||||
if (args.size < 1) {
|
|
||||||
printf("Requires a URL argument\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != STRING) {
|
|
||||||
printf("Arg 1 needs to be a string (URL)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setup();
|
curl_setup();
|
||||||
CURL* handle = curl_easy_init();
|
CURL* handle = curl_easy_init();
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("Curl failed to init\n");
|
ERROR("CURL failed to init", "GenericRequestError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseBuffer buffer = {0};
|
ResponseBuffer buffer = {0};
|
||||||
@@ -81,10 +71,9 @@ GroundValue get_request(GroundScope* scope, List args) {
|
|||||||
CURLcode result = curl_easy_perform(handle);
|
CURLcode result = curl_easy_perform(handle);
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
printf("Curl request failed: %s\n", curl_easy_strerror(result));
|
char buf[256];
|
||||||
free(buffer.data);
|
snprintf(buf, sizeof(buf) - 1, "Curl request failed: %s\n", curl_easy_strerror(result));
|
||||||
curl_easy_cleanup(handle);
|
ERROR(buf, "ActionRequestError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_cleanup(handle);
|
curl_easy_cleanup(handle);
|
||||||
@@ -95,21 +84,11 @@ GroundValue get_request(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
// POST request
|
// POST request
|
||||||
GroundValue post_request(GroundScope* scope, List args) {
|
GroundValue post_request(GroundScope* scope, List args) {
|
||||||
if (args.size < 2) {
|
|
||||||
printf("Requires URL and POST data arguments\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != STRING || args.values[1].type != STRING) {
|
|
||||||
printf("Both arguments need to be strings (URL, POST data)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setup();
|
curl_setup();
|
||||||
CURL* handle = curl_easy_init();
|
CURL* handle = curl_easy_init();
|
||||||
|
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("Curl failed to init\n");
|
ERROR("CURL failed to init", "GenericRequestError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResponseBuffer buffer = {0};
|
ResponseBuffer buffer = {0};
|
||||||
@@ -127,10 +106,11 @@ GroundValue post_request(GroundScope* scope, List args) {
|
|||||||
CURLcode result = curl_easy_perform(handle);
|
CURLcode result = curl_easy_perform(handle);
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
printf("Curl POST request failed: %s\n", curl_easy_strerror(result));
|
|
||||||
free(buffer.data);
|
free(buffer.data);
|
||||||
|
char buf[256];
|
||||||
|
snprintf(buf, sizeof(buf) - 1, "Curl request failed: %s\n", curl_easy_strerror(result));
|
||||||
curl_easy_cleanup(handle);
|
curl_easy_cleanup(handle);
|
||||||
return groundCreateValue(NONE);
|
ERROR(buf, "ActionRequestError");
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_cleanup(handle);
|
curl_easy_cleanup(handle);
|
||||||
@@ -153,27 +133,16 @@ int find_ws_slot() {
|
|||||||
|
|
||||||
// WebSocket Connect - returns connection ID as INT
|
// WebSocket Connect - returns connection ID as INT
|
||||||
GroundValue ws_connect(GroundScope* scope, List args) {
|
GroundValue ws_connect(GroundScope* scope, List args) {
|
||||||
if (args.size < 1) {
|
|
||||||
printf("Requires a WebSocket URL argument (ws:// or wss://)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != STRING) {
|
|
||||||
printf("Arg 1 needs to be a string (WebSocket URL)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_setup();
|
curl_setup();
|
||||||
|
|
||||||
int slot = find_ws_slot();
|
int slot = find_ws_slot();
|
||||||
if (slot == -1) {
|
if (slot == -1) {
|
||||||
printf("Maximum WebSocket connections reached\n");
|
ERROR("Maximum WebSocket connections reached", "OverflowError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL* handle = curl_easy_init();
|
CURL* handle = curl_easy_init();
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("Curl failed to init\n");
|
ERROR("CURL failed to init", "GenericWSError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curl_easy_setopt(handle, CURLOPT_URL, args.values[0].data.stringVal);
|
curl_easy_setopt(handle, CURLOPT_URL, args.values[0].data.stringVal);
|
||||||
@@ -183,9 +152,10 @@ GroundValue ws_connect(GroundScope* scope, List args) {
|
|||||||
CURLcode result = curl_easy_perform(handle);
|
CURLcode result = curl_easy_perform(handle);
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
printf("WebSocket connection failed: %s\n", curl_easy_strerror(result));
|
char buf[256];
|
||||||
|
snprintf(buf, sizeof(buf) - 1, "Curl WebSocket failed: %s\n", curl_easy_strerror(result));
|
||||||
curl_easy_cleanup(handle);
|
curl_easy_cleanup(handle);
|
||||||
return groundCreateValue(NONE);
|
ERROR(buf, "ActionWSError");
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_connections[slot].handle = handle;
|
ws_connections[slot].handle = handle;
|
||||||
@@ -197,19 +167,9 @@ GroundValue ws_connect(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
// WebSocket Send - sends a text message, returns bytes sent as INT
|
// WebSocket Send - sends a text message, returns bytes sent as INT
|
||||||
GroundValue ws_send(GroundScope* scope, List args) {
|
GroundValue ws_send(GroundScope* scope, List args) {
|
||||||
if (args.size < 2) {
|
|
||||||
printf("Requires connection ID and message\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != INT || args.values[1].type != STRING) {
|
|
||||||
printf("Args need to be (INT connection ID, STRING message)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_id = (int)args.values[0].data.intVal;
|
int conn_id = (int)args.values[0].data.intVal;
|
||||||
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
||||||
printf("Invalid or closed WebSocket connection\n");
|
ERROR("Invalid WebSocket connection ID", "GenericWSError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL* handle = ws_connections[conn_id].handle;
|
CURL* handle = ws_connections[conn_id].handle;
|
||||||
@@ -219,8 +179,9 @@ GroundValue ws_send(GroundScope* scope, List args) {
|
|||||||
CURLcode result = curl_ws_send(handle, message, strlen(message), &sent, 0, CURLWS_TEXT);
|
CURLcode result = curl_ws_send(handle, message, strlen(message), &sent, 0, CURLWS_TEXT);
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
printf("WebSocket send failed: %s\n", curl_easy_strerror(result));
|
char buf[256];
|
||||||
return groundCreateValue(NONE);
|
snprintf(buf, sizeof(buf) - 1, "WebSocket send failed: %s\n", curl_easy_strerror(result));
|
||||||
|
ERROR(buf, "ActionWSError");
|
||||||
}
|
}
|
||||||
|
|
||||||
return groundCreateValue(INT, (int64_t)sent);
|
return groundCreateValue(INT, (int64_t)sent);
|
||||||
@@ -228,19 +189,9 @@ GroundValue ws_send(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
// WebSocket Receive - receives a message (blocking)
|
// WebSocket Receive - receives a message (blocking)
|
||||||
GroundValue ws_receive(GroundScope* scope, List args) {
|
GroundValue ws_receive(GroundScope* scope, List args) {
|
||||||
if (args.size < 1) {
|
|
||||||
printf("Requires connection ID\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != INT) {
|
|
||||||
printf("Arg 1 needs to be an INT (connection ID)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_id = (int)args.values[0].data.intVal;
|
int conn_id = (int)args.values[0].data.intVal;
|
||||||
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
||||||
printf("Invalid or closed WebSocket connection\n");
|
ERROR("Invalid WebSocket connection ID", "GenericWSError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL* handle = ws_connections[conn_id].handle;
|
CURL* handle = ws_connections[conn_id].handle;
|
||||||
@@ -255,8 +206,9 @@ GroundValue ws_receive(GroundScope* scope, List args) {
|
|||||||
// No data available right now
|
// No data available right now
|
||||||
return groundCreateValue(STRING, "");
|
return groundCreateValue(STRING, "");
|
||||||
}
|
}
|
||||||
printf("WebSocket receive failed: %s\n", curl_easy_strerror(result));
|
char buf[256];
|
||||||
return groundCreateValue(NONE);
|
snprintf(buf, sizeof(buf) - 1, "WebSocket receive failed: %s\n", curl_easy_strerror(result));
|
||||||
|
ERROR(buf, "ActionWSError");
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[received] = '\0';
|
buffer[received] = '\0';
|
||||||
@@ -283,21 +235,11 @@ GroundValue ws_receive(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
// WebSocket Receive with timeout (non-blocking version)
|
// WebSocket Receive with timeout (non-blocking version)
|
||||||
GroundValue ws_receive_timeout(GroundScope* scope, List args) {
|
GroundValue ws_receive_timeout(GroundScope* scope, List args) {
|
||||||
if (args.size < 2) {
|
|
||||||
printf("Requires connection ID and timeout in milliseconds\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != INT || args.values[1].type != INT) {
|
|
||||||
printf("Both arguments need to be INT (connection ID, timeout_ms)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_id = (int)args.values[0].data.intVal;
|
int conn_id = (int)args.values[0].data.intVal;
|
||||||
long timeout_ms = (long)args.values[1].data.intVal;
|
long timeout_ms = (long)args.values[1].data.intVal;
|
||||||
|
|
||||||
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
||||||
printf("Invalid or closed WebSocket connection\n");
|
ERROR("Invalid WebSocket connection ID", "GenericWSError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL* handle = ws_connections[conn_id].handle;
|
CURL* handle = ws_connections[conn_id].handle;
|
||||||
@@ -316,8 +258,9 @@ GroundValue ws_receive_timeout(GroundScope* scope, List args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
printf("WebSocket receive failed: %s\n", curl_easy_strerror(result));
|
char buf[256];
|
||||||
return groundCreateValue(NONE);
|
snprintf(buf, sizeof(buf) - 1, "WebSocket receive failed: %s\n", curl_easy_strerror(result));
|
||||||
|
ERROR(buf, "ActionWSError");
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer[received] = '\0';
|
buffer[received] = '\0';
|
||||||
@@ -341,19 +284,9 @@ GroundValue ws_receive_timeout(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
// WebSocket Close - properly close a connection, returns BOOL success
|
// WebSocket Close - properly close a connection, returns BOOL success
|
||||||
GroundValue ws_close(GroundScope* scope, List args) {
|
GroundValue ws_close(GroundScope* scope, List args) {
|
||||||
if (args.size < 1) {
|
|
||||||
printf("Requires connection ID\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != INT) {
|
|
||||||
printf("Arg 1 needs to be an INT (connection ID)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_id = (int)args.values[0].data.intVal;
|
int conn_id = (int)args.values[0].data.intVal;
|
||||||
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
||||||
printf("Invalid or already closed WebSocket connection\n");
|
ERROR("Invalid or already connected websocket", "GenericWSError");
|
||||||
return groundCreateValue(BOOL, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL* handle = ws_connections[conn_id].handle;
|
CURL* handle = ws_connections[conn_id].handle;
|
||||||
@@ -374,19 +307,9 @@ GroundValue ws_close(GroundScope* scope, List args) {
|
|||||||
|
|
||||||
// WebSocket Send Binary data, returns bytes sent as INT
|
// WebSocket Send Binary data, returns bytes sent as INT
|
||||||
GroundValue ws_send_binary(GroundScope* scope, List args) {
|
GroundValue ws_send_binary(GroundScope* scope, List args) {
|
||||||
if (args.size < 2) {
|
|
||||||
printf("Requires connection ID and binary data\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
if (args.values[0].type != INT || args.values[1].type != STRING) {
|
|
||||||
printf("Args need to be (INT connection ID, STRING binary data)\n");
|
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_id = (int)args.values[0].data.intVal;
|
int conn_id = (int)args.values[0].data.intVal;
|
||||||
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
if (conn_id < 0 || conn_id >= MAX_WS_CONNECTIONS || !ws_connections[conn_id].connected) {
|
||||||
printf("Invalid or closed WebSocket connection\n");
|
ERROR("Invalid WebSocket connection ID", "GenericWSError");
|
||||||
return groundCreateValue(NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL* handle = ws_connections[conn_id].handle;
|
CURL* handle = ws_connections[conn_id].handle;
|
||||||
@@ -396,8 +319,9 @@ GroundValue ws_send_binary(GroundScope* scope, List args) {
|
|||||||
CURLcode result = curl_ws_send(handle, data, strlen(data), &sent, 0, CURLWS_BINARY);
|
CURLcode result = curl_ws_send(handle, data, strlen(data), &sent, 0, CURLWS_BINARY);
|
||||||
|
|
||||||
if (result != CURLE_OK) {
|
if (result != CURLE_OK) {
|
||||||
printf("WebSocket binary send failed: %s\n", curl_easy_strerror(result));
|
char buf[256];
|
||||||
return groundCreateValue(NONE);
|
snprintf(buf, sizeof(buf) - 1, "WebSocket binary send failed: %s\n", curl_easy_strerror(result));
|
||||||
|
ERROR(buf, "ActionWSError");
|
||||||
}
|
}
|
||||||
|
|
||||||
return groundCreateValue(INT, (int64_t)sent);
|
return groundCreateValue(INT, (int64_t)sent);
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
int currentInstruction = 0;
|
int currentInstruction = 0;
|
||||||
|
|
||||||
void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) {
|
bool isMainScopeGlobal = true;
|
||||||
|
|
||||||
|
[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) {
|
||||||
printf("Ground runtime error:\n ErrorType: ");
|
printf("Ground runtime error:\n ErrorType: ");
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case ARG_TYPE_MISMATCH: {
|
case ARG_TYPE_MISMATCH: {
|
||||||
@@ -46,6 +48,18 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where
|
|||||||
printf("MathError");
|
printf("MathError");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case RETURN_TYPE_MISMATCH: {
|
||||||
|
printf("ReturnTypeMismatch");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PREMATURE_EOF: {
|
||||||
|
printf("PrematureEof");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INVALID_INSTRUCTION: {
|
||||||
|
printf("InvalidInstruction");
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
case FIXME: {
|
case FIXME: {
|
||||||
printf("FIXME (please report issue to https://chsp.au/ground/cground)");
|
printf("FIXME (please report issue to https://chsp.au/ground/cground)");
|
||||||
@@ -66,6 +80,22 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[noreturn]] void throwError(GroundError* error) {
|
||||||
|
printf("Uncaught Ground runtime error:\n ErrorType: %s\n", error->type);
|
||||||
|
if (error->what != NULL) {
|
||||||
|
printf(" ErrorContext: %s\n", error->what);
|
||||||
|
}
|
||||||
|
if (error->where != NULL) {
|
||||||
|
printf(" ErrorInstruction: ");
|
||||||
|
printGroundInstruction(error->where);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
if (error->hasLine) {
|
||||||
|
printf(" ErrorLine: %zu\n", error->line + 1);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
GroundLabel* findLabel(GroundLabel* head, const char *id) {
|
GroundLabel* findLabel(GroundLabel* head, const char *id) {
|
||||||
GroundLabel *item;
|
GroundLabel *item;
|
||||||
HASH_FIND_STR(head, id, item);
|
HASH_FIND_STR(head, id, item);
|
||||||
@@ -173,7 +203,7 @@ GroundDebugInstruction parseDebugInstruction(char* in) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spacepos == -1) {
|
if (spacepos == (size_t) -1) {
|
||||||
spacepos = insize;
|
spacepos = insize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,6 +264,186 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio
|
|||||||
addVariable(scope->variables, name, createFunctionGroundValue(gf));
|
addVariable(scope->variables, name, createFunctionGroundValue(gf));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset) {
|
||||||
|
GroundFunction* function = createGroundFunction();
|
||||||
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
|
if (in->instructions[i].args.length < 2) {
|
||||||
|
function->returnType = NONE;
|
||||||
|
} else {
|
||||||
|
if (in->instructions[i].args.args[1].type != TYPEREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], errorOffset + i);
|
||||||
|
}
|
||||||
|
GroundArg* args = in->instructions[i].args.args;
|
||||||
|
function->returnType = stringToValueType(args[1].value.refName);
|
||||||
|
size_t length = in->instructions[i].args.length;
|
||||||
|
for (size_t j = 2; j < length; j += 2) {
|
||||||
|
if (args[j].type != TYPEREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef", &in->instructions[i], errorOffset + i);
|
||||||
|
}
|
||||||
|
if (j + 1 >= length) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting a DirectRef after a TypeRef", &in->instructions[i], errorOffset + i);
|
||||||
|
}
|
||||||
|
if (args[j + 1].type != DIRREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef after a TypeRef", &in->instructions[i], errorOffset + i);
|
||||||
|
}
|
||||||
|
addArgsToGroundFunction(function, stringToValueType(args[j].value.refName), args[j + 1].value.refName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
while (i < in->size) {
|
||||||
|
addInstructionToProgram(&function->program, in->instructions[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset) {
|
||||||
|
GroundStruct gstruct = createStruct();
|
||||||
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
|
switch (in->instructions[i].type) {
|
||||||
|
case SET: {
|
||||||
|
if (in->instructions[i].args.length < 2) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &in->instructions[i], i + errorOffset);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.length > 2) {
|
||||||
|
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &in->instructions[i], i + errorOffset);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[0].type != DIRREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &in->instructions[i], i + errorOffset);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[1].type != VALUE) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", &in->instructions[i], i + errorOffset);
|
||||||
|
}
|
||||||
|
addFieldToStruct(&gstruct, in->instructions[i].args.args[0].value.refName, in->instructions[i].args.args[1].value.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INIT: {
|
||||||
|
if (in->instructions[i].args.length < 2) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &in->instructions[i], currentInstruction);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.length > 2) {
|
||||||
|
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &in->instructions[i], currentInstruction);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[0].type != DIRREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &in->instructions[i], currentInstruction);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[1].type != TYPEREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], currentInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue gv;
|
||||||
|
|
||||||
|
switch (stringToValueType(in->instructions[i].args.args[0].value.refName)) {
|
||||||
|
case INT: {
|
||||||
|
gv = createIntGroundValue(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DOUBLE: {
|
||||||
|
gv = createDoubleGroundValue(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRING: {
|
||||||
|
gv = createStringGroundValue("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CHAR: {
|
||||||
|
gv = createCharGroundValue('\0');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BOOL: {
|
||||||
|
gv = createBoolGroundValue(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LIST: {
|
||||||
|
gv = createListGroundValue(createList());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FUNCTION: {
|
||||||
|
gv = createFunctionGroundValue(createGroundFunction());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRUCTVAL: {
|
||||||
|
gv.type = STRUCTVAL;
|
||||||
|
gv.data.structVal = malloc(sizeof(GroundStruct));
|
||||||
|
*gv.data.structVal = createStruct();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CUSTOM: {
|
||||||
|
GroundVariable* var = findVariable(*scope->variables, in->instructions[i].args.args[1].value.refName);
|
||||||
|
if (var == NULL) {
|
||||||
|
runtimeError(UNKNOWN_VARIABLE, "Couldn't find the specified type", &in->instructions[i], currentInstruction);
|
||||||
|
}
|
||||||
|
if (var->value.type != STRUCTVAL) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "TypeRef does not reference a struct", &in->instructions[i], currentInstruction);
|
||||||
|
}
|
||||||
|
GroundStruct* gstruct = var->value.data.structVal;
|
||||||
|
gv.type = CUSTOM;
|
||||||
|
gv.data.customVal = malloc(sizeof(GroundObject));
|
||||||
|
*gv.data.customVal = createObject(*gstruct);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NONE: {
|
||||||
|
gv.type = NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
runtimeError(FIXME, "Reached should-be-impossible state", &in->instructions[i], currentInstruction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addFieldToStruct(&gstruct, in->instructions[i].args.args[0].value.refName, gv);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FUN: {
|
||||||
|
if (in->instructions[i].args.length < 1) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[0].type != FNREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
||||||
|
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
||||||
|
|
||||||
|
size_t counter = 1;
|
||||||
|
GroundProgram gp = createGroundProgram();
|
||||||
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
|
size_t errorOffset = i;
|
||||||
|
i++;
|
||||||
|
while (counter > 0) {
|
||||||
|
if (i >= in->size) {
|
||||||
|
runtimeError(PREMATURE_EOF, "Reached end of scope before function definition ended", &in->instructions[i - 1], i - 1);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == FUN) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == ENDFUN) {
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundFunction* function = parseFunction(&gp, errorOffset);
|
||||||
|
function->startLine = i;
|
||||||
|
GroundValue gv = createFunctionGroundValue(function);
|
||||||
|
addFieldToStruct(&gstruct, name, gv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ENDSTRUCT: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
runtimeError(INVALID_INSTRUCTION, "Unsupported instruction while inside struct", &in->instructions[i], errorOffset + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gstruct;
|
||||||
|
}
|
||||||
|
|
||||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||||
GroundLabel* labels = NULL;
|
GroundLabel* labels = NULL;
|
||||||
GroundVariable* variables = NULL;
|
GroundVariable* variables = NULL;
|
||||||
@@ -246,52 +456,89 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
scope.labels = &labels;
|
scope.labels = &labels;
|
||||||
scope.variables = &variables;
|
scope.variables = &variables;
|
||||||
}
|
}
|
||||||
// Preprocess all labels and functions
|
scope.isMainScope = isMainScopeGlobal;
|
||||||
for (int i = 0; i < in->size; i++) {
|
isMainScopeGlobal = false;
|
||||||
|
// Preprocess all labels, structs and functions
|
||||||
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
if (in->instructions[i].type == CREATELABEL) {
|
if (in->instructions[i].type == CREATELABEL) {
|
||||||
addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i);
|
addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i);
|
||||||
}
|
}
|
||||||
if (in->instructions[i].type == FUN) {
|
if (in->instructions[i].type == FUN) {
|
||||||
GroundFunction* function = createGroundFunction();
|
|
||||||
function->startLine = i;
|
|
||||||
if (in->instructions[i].args.length < 1) {
|
if (in->instructions[i].args.length < 1) {
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i);
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i);
|
||||||
}
|
}
|
||||||
if (in->instructions[i].args.args[0].type != FNREF) {
|
if (in->instructions[i].args.args[0].type != FNREF) {
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i);
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i);
|
||||||
}
|
}
|
||||||
char* functionName = in->instructions[i].args.args[0].value.refName;
|
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
||||||
if (in->instructions[i].args.length < 2) {
|
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
||||||
function->returnType = NONE;
|
|
||||||
} else {
|
size_t counter = 1;
|
||||||
if (in->instructions[i].args.args[1].type != TYPEREF) {
|
GroundProgram gp = createGroundProgram();
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], i);
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
}
|
size_t errorOffset = i;
|
||||||
GroundArg* args = in->instructions[i].args.args;
|
|
||||||
function->returnType = stringToValueType(args[1].value.refName);
|
|
||||||
size_t length = in->instructions[i].args.length;
|
|
||||||
for (size_t j = 2; j < length; j += 2) {
|
|
||||||
if (args[j].type != TYPEREF) {
|
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
if (j + 1 >= length) {
|
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting a DirectRef after a TypeRef", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
if (args[j + 1].type != DIRREF) {
|
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef after a TypeRef", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
addArgsToGroundFunction(function, stringToValueType(args[j].value.refName), args[j + 1].value.refName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
i++;
|
||||||
while (in->instructions[i].type != ENDFUN) {
|
while (counter > 0) {
|
||||||
addInstructionToProgram(&function->program, in->instructions[i]);
|
if (i >= in->size) {
|
||||||
|
runtimeError(PREMATURE_EOF, "Reached end of scope before function definition ended", &in->instructions[i - 1], i - 1);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == FUN) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == ENDFUN) {
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
addVariable(scope.variables, functionName, createFunctionGroundValue(function));
|
|
||||||
|
GroundFunction* function = parseFunction(&gp, errorOffset);
|
||||||
|
function->startLine = i;
|
||||||
|
GroundValue gv = createFunctionGroundValue(function);
|
||||||
|
|
||||||
|
addVariable(scope.variables, name, gv);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == STRUCT) {
|
||||||
|
if (in->instructions[i].args.length < 1) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.length > 1) {
|
||||||
|
runtimeError(TOO_MANY_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[0].type != TYPEREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expected arg 1 to be a typeref", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
||||||
|
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
size_t counter = 1;
|
||||||
|
GroundProgram gp = createGroundProgram();
|
||||||
|
size_t errorOffset = i;
|
||||||
|
while (counter > 0) {
|
||||||
|
if (i >= in->size) {
|
||||||
|
runtimeError(PREMATURE_EOF, "Reached end of scope before struct definition ended", &in->instructions[i - 1], i - 1);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == STRUCT) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == ENDSTRUCT) {
|
||||||
|
counter--;
|
||||||
|
}
|
||||||
|
addInstructionToProgram(&gp, in->instructions[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue gv = {
|
||||||
|
.type = STRUCTVAL,
|
||||||
|
.data.structVal = malloc(sizeof(GroundStruct))
|
||||||
|
};
|
||||||
|
*gv.data.structVal = parseStruct(&gp, &scope, errorOffset);
|
||||||
|
|
||||||
|
addVariable(scope.variables, name, gv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < in->size; i++) {
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
if (in->instructions[i].type == FUN) {
|
if (in->instructions[i].type == FUN) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
@@ -307,6 +554,21 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in->instructions[i].type == STRUCT) {
|
||||||
|
int count = 1;
|
||||||
|
while (count > 0) {
|
||||||
|
i++;
|
||||||
|
if (i >= in->size) {
|
||||||
|
return createNoneGroundValue();
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == STRUCT) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (in->instructions[i].type == ENDSTRUCT) {
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (in->instructions[i].type == PAUSE || instructionsToPause == 0) {
|
if (in->instructions[i].type == PAUSE || instructionsToPause == 0) {
|
||||||
printf("Paused execution\n");
|
printf("Paused execution\n");
|
||||||
printf("Previous instruction: ");
|
printf("Previous instruction: ");
|
||||||
@@ -428,7 +690,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
GroundInstruction* in = &copied_inst;
|
GroundInstruction* in = &copied_inst;
|
||||||
|
|
||||||
// Insert variables prefixed with $
|
// Insert variables prefixed with $
|
||||||
for (int i = 0; i < in->args.length; i++) {
|
for (size_t i = 0; i < in->args.length; i++) {
|
||||||
if (in->args.args[i].type == VALREF) {
|
if (in->args.args[i].type == VALREF) {
|
||||||
GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName);
|
GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName);
|
||||||
if (variable) {
|
if (variable) {
|
||||||
@@ -441,9 +703,11 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (in->type) {
|
switch (in->type) {
|
||||||
// We can safely ignore any CREATELABEL, FUN, and ENDFUN instructions, these have been preprocessed
|
// We can safely ignore these instructions, as they have been preprocessed
|
||||||
case FUN:
|
case FUN:
|
||||||
case ENDFUN:
|
case ENDFUN:
|
||||||
|
case STRUCT:
|
||||||
|
case ENDSTRUCT:
|
||||||
case CREATELABEL: {
|
case CREATELABEL: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -516,7 +780,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
if (in->args.length < 1) {
|
if (in->args.length < 1) {
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction);
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < in->args.length; i++) {
|
for (size_t i = 0; i < in->args.length; i++) {
|
||||||
if (i != 0) printf(" ");
|
if (i != 0) printf(" ");
|
||||||
printGroundArg(&in->args.args[i]);
|
printGroundArg(&in->args.args[i]);
|
||||||
}
|
}
|
||||||
@@ -526,7 +790,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
if (in->args.length < 1) {
|
if (in->args.length < 1) {
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction);
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < in->args.length; i++) {
|
for (size_t i = 0; i < in->args.length; i++) {
|
||||||
if (i != 0) printf(" ");
|
if (i != 0) printf(" ");
|
||||||
printGroundArg(&in->args.args[i]);
|
printGroundArg(&in->args.args[i]);
|
||||||
}
|
}
|
||||||
@@ -618,9 +882,19 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
}
|
}
|
||||||
case FUNCTION: {
|
case FUNCTION: {
|
||||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("function"));
|
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("function"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRUCTVAL: {
|
||||||
|
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("struct"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case NONE: {
|
case NONE: {
|
||||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("none"));
|
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("none"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ERROR: {
|
||||||
|
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("error"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,7 +929,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction);
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction);
|
||||||
}
|
}
|
||||||
List newList = createList();
|
List newList = createList();
|
||||||
for (int i = 1; i < in->args.length; i++) {
|
for (size_t i = 1; i < in->args.length; i++) {
|
||||||
if (in->args.args[i].type != VALUE) {
|
if (in->args.args[i].type != VALUE) {
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for all args after arg 1", in, currentInstruction);
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for all args after arg 1", in, currentInstruction);
|
||||||
}
|
}
|
||||||
@@ -1132,7 +1406,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction);
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction);
|
||||||
}
|
}
|
||||||
char* str = in->args.args[0].value.value.data.stringVal;
|
char* str = in->args.args[0].value.value.data.stringVal;
|
||||||
int64_t idx = in->args.args[1].value.value.data.intVal;
|
size_t idx = in->args.args[1].value.value.data.intVal;
|
||||||
if (idx < strlen(str)) {
|
if (idx < strlen(str)) {
|
||||||
addVariable(scope->variables, in->args.args[2].value.refName, createCharGroundValue(str[idx]));
|
addVariable(scope->variables, in->args.args[2].value.refName, createCharGroundValue(str[idx]));
|
||||||
} else {
|
} else {
|
||||||
@@ -1487,6 +1761,15 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
|
|
||||||
if (function->nativeFn) {
|
if (function->nativeFn) {
|
||||||
GroundValue returnValue = function->nativeFn(scope, argsList);
|
GroundValue returnValue = function->nativeFn(scope, argsList);
|
||||||
|
if (returnValue.type == ERROR) {
|
||||||
|
returnValue.data.errorVal.line = currentInstruction;
|
||||||
|
returnValue.data.errorVal.hasLine = true;
|
||||||
|
returnValue.data.errorVal.where = in;
|
||||||
|
if (scope->isMainScope) {
|
||||||
|
throwError(&returnValue.data.errorVal);
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
if (returnValue.type != function->returnType) {
|
if (returnValue.type != function->returnType) {
|
||||||
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from native function", in, currentInstruction);
|
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from native function", in, currentInstruction);
|
||||||
}
|
}
|
||||||
@@ -1506,6 +1789,9 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
size_t currentCurrentInstruction = currentInstruction;
|
size_t currentCurrentInstruction = currentInstruction;
|
||||||
currentInstruction = function->startLine;
|
currentInstruction = function->startLine;
|
||||||
GroundValue returnValue = interpretGroundProgram(&function->program, &newScope);
|
GroundValue returnValue = interpretGroundProgram(&function->program, &newScope);
|
||||||
|
if (returnValue.type == ERROR) {
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
if (returnValue.type != function->returnType) {
|
if (returnValue.type != function->returnType) {
|
||||||
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from function", in, currentInstruction);
|
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from function", in, currentInstruction);
|
||||||
}
|
}
|
||||||
@@ -1628,6 +1914,87 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case INIT: {
|
||||||
|
if (in->args.length < 2) {
|
||||||
|
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction);
|
||||||
|
}
|
||||||
|
if (in->args.length > 2) {
|
||||||
|
runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction);
|
||||||
|
}
|
||||||
|
if (in->args.args[0].type != DIRREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction);
|
||||||
|
}
|
||||||
|
if (in->args.args[1].type != TYPEREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", in, currentInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
GroundValue gv;
|
||||||
|
|
||||||
|
switch (stringToValueType(in->args.args[1].value.refName)) {
|
||||||
|
case INT: {
|
||||||
|
gv = createIntGroundValue(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DOUBLE: {
|
||||||
|
gv = createDoubleGroundValue(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRING: {
|
||||||
|
gv = createStringGroundValue("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CHAR: {
|
||||||
|
gv = createCharGroundValue('\0');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BOOL: {
|
||||||
|
gv = createBoolGroundValue(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LIST: {
|
||||||
|
gv = createListGroundValue(createList());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case FUNCTION: {
|
||||||
|
GroundFunction* gf = createGroundFunction();
|
||||||
|
gf->returnType = NONE;
|
||||||
|
gv = createFunctionGroundValue(gf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STRUCTVAL: {
|
||||||
|
gv.type = STRUCTVAL;
|
||||||
|
gv.data.structVal = malloc(sizeof(GroundStruct));
|
||||||
|
*gv.data.structVal = createStruct();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CUSTOM: {
|
||||||
|
GroundVariable* var = findVariable(*scope->variables, in->args.args[1].value.refName);
|
||||||
|
if (var == NULL) {
|
||||||
|
runtimeError(UNKNOWN_VARIABLE, "Couldn't find the specified type", in, currentInstruction);
|
||||||
|
}
|
||||||
|
if (var->value.type != STRUCTVAL) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "TypeRef does not reference a struct", in, currentInstruction);
|
||||||
|
}
|
||||||
|
GroundStruct* gstruct = var->value.data.structVal;
|
||||||
|
gv.type = CUSTOM;
|
||||||
|
gv.data.customVal = malloc(sizeof(GroundObject));
|
||||||
|
*gv.data.customVal = createObject(*gstruct);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NONE: {
|
||||||
|
gv.type = NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
runtimeError(FIXME, "Reached should-be-impossible state", in, currentInstruction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addVariable(scope->variables, in->args.args[0].value.refName, gv);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case DROP: {
|
case DROP: {
|
||||||
if (in->args.length < 1) {
|
if (in->args.length < 1) {
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction);
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "include/uthash.h"
|
#include "include/uthash.h"
|
||||||
|
|
||||||
typedef enum GroundRuntimeError {
|
typedef enum GroundRuntimeError {
|
||||||
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, FIXME
|
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, PREMATURE_EOF, INVALID_INSTRUCTION, FIXME
|
||||||
} GroundRuntimeError;
|
} GroundRuntimeError;
|
||||||
|
|
||||||
typedef enum GroundDebugInstructionType {
|
typedef enum GroundDebugInstructionType {
|
||||||
@@ -29,6 +29,7 @@ typedef struct GroundVariable {
|
|||||||
typedef struct GroundScope {
|
typedef struct GroundScope {
|
||||||
GroundLabel** labels;
|
GroundLabel** labels;
|
||||||
GroundVariable** variables;
|
GroundVariable** variables;
|
||||||
|
bool isMainScope;
|
||||||
} GroundScope;
|
} GroundScope;
|
||||||
|
|
||||||
typedef struct GroundDebugInstruction {
|
typedef struct GroundDebugInstruction {
|
||||||
@@ -36,8 +37,12 @@ typedef struct GroundDebugInstruction {
|
|||||||
char* arg;
|
char* arg;
|
||||||
} GroundDebugInstruction;
|
} GroundDebugInstruction;
|
||||||
|
|
||||||
|
GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset);
|
||||||
|
GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset);
|
||||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
||||||
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
|
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
69
src/types.c
69
src/types.c
@@ -51,6 +51,13 @@ GroundValue createFunctionGroundValue(GroundFunction* in) {
|
|||||||
return gv;
|
return gv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundValue createErrorGroundValue(GroundError in) {
|
||||||
|
GroundValue gv;
|
||||||
|
gv.data.errorVal = in;
|
||||||
|
gv.type = ERROR;
|
||||||
|
return gv;
|
||||||
|
}
|
||||||
|
|
||||||
GroundValue createNoneGroundValue() {
|
GroundValue createNoneGroundValue() {
|
||||||
GroundValue gv;
|
GroundValue gv;
|
||||||
gv.type = NONE;
|
gv.type = NONE;
|
||||||
@@ -74,7 +81,7 @@ GroundValue copyGroundValue(const GroundValue* gv) {
|
|||||||
break;
|
break;
|
||||||
case LIST: {
|
case LIST: {
|
||||||
List newList = createList();
|
List newList = createList();
|
||||||
for (int i = 0; i < gv->data.listVal.size; i++) {
|
for (size_t i = 0; i < gv->data.listVal.size; i++) {
|
||||||
// Recursive call to handle nested lists and other types
|
// Recursive call to handle nested lists and other types
|
||||||
appendToList(&newList, copyGroundValue(&gv->data.listVal.values[i]));
|
appendToList(&newList, copyGroundValue(&gv->data.listVal.values[i]));
|
||||||
}
|
}
|
||||||
@@ -93,6 +100,10 @@ GroundValue copyGroundValue(const GroundValue* gv) {
|
|||||||
// FIXME
|
// FIXME
|
||||||
newGv.data.customVal = gv->data.customVal;
|
newGv.data.customVal = gv->data.customVal;
|
||||||
break;
|
break;
|
||||||
|
case NONE:
|
||||||
|
default: {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return newGv;
|
return newGv;
|
||||||
}
|
}
|
||||||
@@ -125,7 +136,7 @@ void printGroundValue(GroundValue* gv) {
|
|||||||
}
|
}
|
||||||
case LIST: {
|
case LIST: {
|
||||||
printf("[");
|
printf("[");
|
||||||
for (int i = 0; i < gv->data.listVal.size; i++) {
|
for (size_t i = 0; i < gv->data.listVal.size; i++) {
|
||||||
printGroundValue(&gv->data.listVal.values[i]);
|
printGroundValue(&gv->data.listVal.values[i]);
|
||||||
if (i < gv->data.listVal.size - 1) {
|
if (i < gv->data.listVal.size - 1) {
|
||||||
printf(", ");
|
printf(", ");
|
||||||
@@ -152,7 +163,7 @@ void freeGroundValue(GroundValue* gv) {
|
|||||||
}
|
}
|
||||||
if (gv->type == LIST && gv->data.listVal.values != NULL) {
|
if (gv->type == LIST && gv->data.listVal.values != NULL) {
|
||||||
List* list = &gv->data.listVal;
|
List* list = &gv->data.listVal;
|
||||||
for (int i = 0; i < list->size; i++) {
|
for (size_t i = 0; i < list->size; i++) {
|
||||||
freeGroundValue(&list->values[i]);
|
freeGroundValue(&list->values[i]);
|
||||||
}
|
}
|
||||||
free(list->values);
|
free(list->values);
|
||||||
@@ -164,6 +175,18 @@ void freeGroundValue(GroundValue* gv) {
|
|||||||
freeGroundStruct(gstruct);
|
freeGroundStruct(gstruct);
|
||||||
free(gstruct);
|
free(gstruct);
|
||||||
}
|
}
|
||||||
|
if (gv->type == ERROR) {
|
||||||
|
GroundError* error = &gv->data.errorVal;
|
||||||
|
if (error->type != NULL) {
|
||||||
|
free(error->type);
|
||||||
|
}
|
||||||
|
if (error->what != NULL) {
|
||||||
|
free(error->what);
|
||||||
|
}
|
||||||
|
if (error->where != NULL) {
|
||||||
|
freeGroundInstruction(error->where);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GroundArg createValueGroundArg(GroundValue value) {
|
GroundArg createValueGroundArg(GroundValue value) {
|
||||||
@@ -394,7 +417,7 @@ void printGroundInstruction(GroundInstruction* gi) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (gi->type != CREATELABEL) printf(" ");
|
if (gi->type != CREATELABEL) printf(" ");
|
||||||
for (int i = 0; i < gi->args.length; i++) {
|
for (size_t i = 0; i < gi->args.length; i++) {
|
||||||
if (gi->args.args[i].type == VALUE && gi->args.args[i].value.value.type == STRING) {
|
if (gi->args.args[i].type == VALUE && gi->args.args[i].value.value.type == STRING) {
|
||||||
printf("\"");
|
printf("\"");
|
||||||
printGroundArg(&gi->args.args[i]);
|
printGroundArg(&gi->args.args[i]);
|
||||||
@@ -428,7 +451,7 @@ void appendToList(List* list, GroundValue value) {
|
|||||||
list->values[list->size - 1] = value;
|
list->values[list->size - 1] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListAccess getListAt(List* list, int idx) {
|
ListAccess getListAt(List* list, size_t idx) {
|
||||||
if (list == NULL) {
|
if (list == NULL) {
|
||||||
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
|
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -446,7 +469,7 @@ ListAccess getListAt(List* list, int idx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListAccessStatus setListAt(List* list, int idx, GroundValue value) {
|
ListAccessStatus setListAt(List* list, size_t idx, GroundValue value) {
|
||||||
if (list == NULL) {
|
if (list == NULL) {
|
||||||
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
|
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -525,3 +548,37 @@ void freeGroundObject(GroundObject* object) {
|
|||||||
}
|
}
|
||||||
object->fields = NULL;
|
object->fields = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundError createGroundError(char* what, char* type, GroundInstruction* where, size_t* line) {
|
||||||
|
GroundError ge;
|
||||||
|
if (what != NULL) {
|
||||||
|
ge.what = malloc(strlen(what) + 1);
|
||||||
|
strcpy(ge.what, what);
|
||||||
|
} else {
|
||||||
|
ge.what = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != NULL) {
|
||||||
|
ge.type = malloc(strlen(type) + 1);
|
||||||
|
strcpy(ge.type, type);
|
||||||
|
} else {
|
||||||
|
ge.type = malloc(strlen("GenericError") + 1);
|
||||||
|
strcpy(ge.type, "GenericError");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (where != NULL) {
|
||||||
|
ge.where = malloc(sizeof(GroundInstruction));
|
||||||
|
*ge.where = copyGroundInstruction(where);
|
||||||
|
} else {
|
||||||
|
ge.where = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line != NULL) {
|
||||||
|
ge.line = *line;
|
||||||
|
} else {
|
||||||
|
ge.line = 0;
|
||||||
|
ge.hasLine = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ge;
|
||||||
|
}
|
||||||
|
|||||||
27
src/types.h
27
src/types.h
@@ -13,7 +13,7 @@ typedef enum GroundInstType {
|
|||||||
} GroundInstType;
|
} GroundInstType;
|
||||||
|
|
||||||
typedef enum GroundValueType {
|
typedef enum GroundValueType {
|
||||||
INT, DOUBLE, STRING, CHAR, BOOL, LIST, FUNCTION, STRUCTVAL, CUSTOM, NONE
|
INT, DOUBLE, STRING, CHAR, BOOL, LIST, FUNCTION, STRUCTVAL, CUSTOM, ERROR, NONE
|
||||||
} GroundValueType;
|
} GroundValueType;
|
||||||
|
|
||||||
typedef enum GroundArgType {
|
typedef enum GroundArgType {
|
||||||
@@ -29,6 +29,7 @@ struct GroundFunction;
|
|||||||
struct GroundScope;
|
struct GroundScope;
|
||||||
struct GroundStruct;
|
struct GroundStruct;
|
||||||
struct GroundObject;
|
struct GroundObject;
|
||||||
|
struct GroundInstruction;
|
||||||
|
|
||||||
struct List;
|
struct List;
|
||||||
|
|
||||||
@@ -42,6 +43,17 @@ typedef struct List {
|
|||||||
struct GroundValue* values;
|
struct GroundValue* values;
|
||||||
} List;
|
} List;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stores data associated with an error thrown during Ground execution.
|
||||||
|
*/
|
||||||
|
typedef struct GroundError {
|
||||||
|
char* what;
|
||||||
|
char* type;
|
||||||
|
struct GroundInstruction* where;
|
||||||
|
size_t line;
|
||||||
|
bool hasLine;
|
||||||
|
} GroundError;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stores literal values created in a Ground program.
|
* Stores literal values created in a Ground program.
|
||||||
* Associated functions:
|
* Associated functions:
|
||||||
@@ -57,6 +69,7 @@ typedef struct GroundValue {
|
|||||||
char charVal;
|
char charVal;
|
||||||
bool boolVal;
|
bool boolVal;
|
||||||
List listVal;
|
List listVal;
|
||||||
|
GroundError errorVal;
|
||||||
struct GroundFunction* fnVal;
|
struct GroundFunction* fnVal;
|
||||||
struct GroundStruct* structVal;
|
struct GroundStruct* structVal;
|
||||||
struct GroundObject* customVal;
|
struct GroundObject* customVal;
|
||||||
@@ -187,6 +200,9 @@ GroundValue createListGroundValue(List in);
|
|||||||
// Creates a GroundValue conatining (in), with type FUNCTION.
|
// Creates a GroundValue conatining (in), with type FUNCTION.
|
||||||
GroundValue createFunctionGroundValue(GroundFunction* in);
|
GroundValue createFunctionGroundValue(GroundFunction* in);
|
||||||
|
|
||||||
|
// Creates a GroundValue containing (in), with type ERROR.
|
||||||
|
GroundValue createErrorGroundValue(GroundError in);
|
||||||
|
|
||||||
// Creates a Groundvalue with type NONE.
|
// Creates a Groundvalue with type NONE.
|
||||||
GroundValue createNoneGroundValue();
|
GroundValue createNoneGroundValue();
|
||||||
|
|
||||||
@@ -234,10 +250,10 @@ void appendToList(List* list, GroundValue value);
|
|||||||
|
|
||||||
// Gets item at index (idx) from list (list). If there is an error, it
|
// Gets item at index (idx) from list (list). If there is an error, it
|
||||||
// will be indicated in the status field.
|
// will be indicated in the status field.
|
||||||
ListAccess getListAt(List* list, int idx);
|
ListAccess getListAt(List* list, size_t idx);
|
||||||
|
|
||||||
// Sets an item in list (list) at index (idx) to GroundValue (value).
|
// Sets an item in list (list) at index (idx) to GroundValue (value).
|
||||||
ListAccessStatus setListAt(List* list, int idx, GroundValue value);
|
ListAccessStatus setListAt(List* list, size_t idx, GroundValue value);
|
||||||
|
|
||||||
// Creates a Ground struct
|
// Creates a Ground struct
|
||||||
GroundStruct createStruct();
|
GroundStruct createStruct();
|
||||||
@@ -257,4 +273,9 @@ GroundObjectField* findField(GroundObject head, const char *id);
|
|||||||
// Frees a GroundObject
|
// Frees a GroundObject
|
||||||
void freeGroundObject(GroundObject* object);
|
void freeGroundObject(GroundObject* object);
|
||||||
|
|
||||||
|
// Creates a GroundError.
|
||||||
|
GroundError createGroundError(char* what, char* type, GroundInstruction* where, size_t* line);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user