forked from ground/ground
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6803b44c8 | |||
| c25df7918b | |||
| 491d6a2c71 | |||
| 3db779cb3e | |||
| ed27cb0d1b | |||
| bcbab3afb3 | |||
| 12d2ff6e24 | |||
| 7ff709f9b7 | |||
| 60054fe6f3 | |||
| 932846362d | |||
| 39b6a49a9c | |||
| 159d86b76d | |||
| a2b0924018 | |||
| 9edb6b51ec | |||
| 5f7f2ea152 | |||
| 6c293f7c3f |
@@ -3,9 +3,9 @@
|
||||
#define MAX_ID_LEN 64
|
||||
|
||||
/*
|
||||
* groundvm.h
|
||||
* groundvm.h
|
||||
* Provides an interface for external programs wanting to run Ground code.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -125,17 +125,6 @@ typedef struct GroundFunctionArgs {
|
||||
char* name;
|
||||
} GroundFunctionArgs;
|
||||
|
||||
/*
|
||||
* Represents a Ground function.
|
||||
*/
|
||||
typedef struct GroundFunction {
|
||||
GroundFunctionArgs* args;
|
||||
size_t argSize;
|
||||
GroundValueType returnType;
|
||||
GroundProgram program;
|
||||
size_t startLine;
|
||||
} GroundFunction;
|
||||
|
||||
/*
|
||||
* Field for a GroundStruct
|
||||
*/
|
||||
@@ -181,12 +170,35 @@ typedef struct GroundVariable {
|
||||
UT_hash_handle hh;
|
||||
} GroundVariable;
|
||||
|
||||
typedef struct GroundCatch {
|
||||
char id[MAX_ID_LEN];
|
||||
GroundLabel* label;
|
||||
UT_hash_handle hh;
|
||||
} GroundCatch;
|
||||
|
||||
typedef struct GroundScope {
|
||||
GroundLabel** labels;
|
||||
GroundVariable** variables;
|
||||
GroundCatch** catches;
|
||||
bool isMainScope;
|
||||
} GroundScope;
|
||||
|
||||
typedef GroundValue (*NativeGroundFunction)(struct GroundScope* scope, List args);
|
||||
|
||||
/*
|
||||
* Represents a Ground function.
|
||||
*/
|
||||
typedef struct GroundFunction {
|
||||
GroundFunctionArgs* args;
|
||||
size_t argSize;
|
||||
GroundValueType returnType;
|
||||
GroundProgram program;
|
||||
size_t startLine;
|
||||
bool isNative;
|
||||
GroundScope closure;
|
||||
NativeGroundFunction nativeFn;
|
||||
} GroundFunction;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -194,7 +206,7 @@ extern "C" {
|
||||
GroundProgram groundCreateProgram();
|
||||
void groundAddInstructionToProgram(GroundProgram* program, GroundInstruction instruction);
|
||||
GroundValue groundRunProgram(GroundProgram* program);
|
||||
void groundPrintProgram(GroundProgram* program);
|
||||
void groundPrintProgram(GroundProgram* program);
|
||||
char* groundCompileProgram(GroundProgram* program);
|
||||
|
||||
GroundInstruction groundCreateInstruction(GroundInstType type);
|
||||
|
||||
45
libs/_box/_box.c
Normal file
45
libs/_box/_box.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <groundext.h>
|
||||
#include <groundvm.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
GroundValue boxGet(GroundScope* scope, List args) {
|
||||
GroundVariable* varptr = groundFindVariable(scope, "ptr");
|
||||
GroundValue* ptr = (GroundValue*)varptr->value.data.intVal;
|
||||
if (ptr == NULL) {
|
||||
ERROR("No value in box", "ValueError");
|
||||
}
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
GroundValue boxSet(GroundScope* scope, List args) {
|
||||
GroundVariable* varptr = groundFindVariable(scope, "ptr");
|
||||
GroundValue** ptr = (GroundValue**)&varptr->value.data.intVal;
|
||||
if (*ptr == NULL) {
|
||||
*ptr = malloc(sizeof(GroundValue));
|
||||
if (*ptr == NULL) {
|
||||
ERROR("Could not allocate memory", "AllocError");
|
||||
}
|
||||
}
|
||||
**ptr = args.values[0];
|
||||
return groundCreateValue(NONE);
|
||||
}
|
||||
|
||||
GroundValue boxFree(GroundScope* scope, List args) {
|
||||
GroundVariable* varptr = groundFindVariable(scope, "ptr");
|
||||
GroundValue** ptr = (GroundValue**)&varptr->value.data.intVal;
|
||||
if (*ptr != NULL) {
|
||||
free(*ptr);
|
||||
*ptr = 0;
|
||||
}
|
||||
return groundCreateValue(NONE);
|
||||
}
|
||||
|
||||
void ground_init(GroundScope* scope) {
|
||||
GroundStruct boxStruct = groundCreateStruct();
|
||||
groundAddFieldToStruct(&boxStruct, "ptr", groundCreateValue(INT, 0));
|
||||
groundAddFunctionToStruct(&boxStruct, "get", boxGet, ANY, 0);
|
||||
groundAddFunctionToStruct(&boxStruct, "set", boxSet, ANY, 1, ANY, "item");
|
||||
groundAddFunctionToStruct(&boxStruct, "free", boxFree, ANY, 0);
|
||||
|
||||
groundAddValueToScope(scope, "_box", groundCreateValue(STRUCTVAL, boxStruct));
|
||||
}
|
||||
202
libs/allocator/allocator.c
Normal file
202
libs/allocator/allocator.c
Normal file
@@ -0,0 +1,202 @@
|
||||
// allocator.c - library to safely, dynamically allocate memory inside of Ground
|
||||
|
||||
#include <groundext.h>
|
||||
#include <groundvm.h>
|
||||
#include <stdbool.h>
|
||||
#include <uthash.h>
|
||||
|
||||
GroundStruct allocatorStruct;
|
||||
|
||||
// callmethod &allocator !allocate $size &
|
||||
GroundValue groundAllocatorAllocate(GroundScope* scope, List args) {
|
||||
int64_t size = args.values[0].data.intVal;
|
||||
if (size < 1) {
|
||||
ERROR("Cannot allocate with size of < 1", "AllocSizeError");
|
||||
}
|
||||
GroundValue* ptr = malloc(sizeof(GroundValue) * size);
|
||||
if (ptr == NULL) {
|
||||
ERROR("Failed to allocate memory", "AllocError");
|
||||
}
|
||||
|
||||
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
|
||||
if (ptrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
|
||||
ptrField->value.type = INT;
|
||||
ptrField->value.data.intVal = (int64_t)ptr;
|
||||
|
||||
GroundVariable* capacityField = groundFindVariable(scope, "capacity");
|
||||
if (capacityField == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
|
||||
capacityField->value.type = INT;
|
||||
capacityField->value.data.intVal = size;
|
||||
|
||||
return groundCreateValue(INT, 0);
|
||||
}
|
||||
|
||||
// callmethod &allocator !addCapacity $addedCapacity &
|
||||
GroundValue groundAllocatorAddCapacity(GroundScope* scope, List args) {
|
||||
int64_t addedCapacity = args.values[0].data.intVal;
|
||||
if (addedCapacity < 0) {
|
||||
ERROR("Cannot shrink capacity", "AllocSizeError");
|
||||
}
|
||||
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
|
||||
if (currentCapacity == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
if (currentCapacity->value.data.intVal < 1) {
|
||||
return groundAllocatorAllocate(scope, args);
|
||||
}
|
||||
|
||||
currentCapacity->value.data.intVal += addedCapacity;
|
||||
|
||||
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
|
||||
if (ptrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
|
||||
if (ptr == NULL) {
|
||||
return groundAllocatorAllocate(scope, args);
|
||||
}
|
||||
|
||||
GroundValue* newPtr = realloc(ptr, sizeof(GroundValue) * currentCapacity->value.data.intVal);
|
||||
if (newPtr == NULL) {
|
||||
ERROR("Failed to allocate more memory for pointer", "AllocError");
|
||||
}
|
||||
|
||||
ptrField->value.data.intVal = (int64_t)newPtr;
|
||||
return groundCreateValue(INT, 0);
|
||||
}
|
||||
|
||||
// callmethod &allocator !getAtOffset $offset &
|
||||
GroundValue groundAllocatorGetAtOffset(GroundScope* scope, List args) {
|
||||
int64_t offset = args.values[0].data.intVal;
|
||||
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
|
||||
if (currentCapacity == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
if (offset >= currentCapacity->value.data.intVal || offset < 0) {
|
||||
ERROR("Offset is out of bounds for current capacity", "OutOfBounds");
|
||||
}
|
||||
|
||||
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
|
||||
if (ptrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
|
||||
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
|
||||
if (ptr == NULL) {
|
||||
ERROR("Cannot get offset of null pointer", "NullPointerError");
|
||||
}
|
||||
return ptr[offset];
|
||||
}
|
||||
|
||||
GroundValue copyGroundValue(const GroundValue* gv);
|
||||
|
||||
// callmethod &allocator !setAtOffset $offset $value &
|
||||
GroundValue groundAllocatorSetAtOffset(GroundScope* scope, List args) {
|
||||
int64_t offset = args.values[0].data.intVal;
|
||||
GroundValue value = copyGroundValue(&args.values[1]);
|
||||
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
|
||||
if (currentCapacity == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
if (offset >= currentCapacity->value.data.intVal || offset < 0) {
|
||||
ERROR("Offset is out of bounds for current capacity", "OutOfBounds");
|
||||
}
|
||||
|
||||
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
|
||||
if (ptrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
|
||||
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
|
||||
if (ptr == NULL) {
|
||||
ERROR("Cannot set offset of null pointer", "NullPointerError");
|
||||
}
|
||||
ptr[offset] = value;
|
||||
return groundCreateValue(INT, 0);
|
||||
}
|
||||
|
||||
GroundValue groundAllocatorDestructor(GroundScope* scope, List args) {
|
||||
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
|
||||
if (ptrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
|
||||
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
|
||||
if (ptr == NULL) {
|
||||
ERROR("Cannot set offset of null pointer", "NullPointerError");
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
ptrField->value.data.intVal = 0;
|
||||
|
||||
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
|
||||
if (currentCapacity == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
currentCapacity->value.data.intVal = 0;
|
||||
return groundCreateValue(INT, 0);
|
||||
}
|
||||
|
||||
GroundValue groundAllocatorDuplicator(GroundScope* scope, List args) {
|
||||
GroundVariable* ptrField = groundFindVariable(scope, "ptr");
|
||||
if (ptrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
|
||||
GroundValue* ptr = (GroundValue*)ptrField->value.data.intVal;
|
||||
|
||||
GroundVariable* currentCapacity = groundFindVariable(scope, "capacity");
|
||||
if (currentCapacity == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
|
||||
GroundValue newAllocator = groundCreateValue(CUSTOM, &allocatorStruct);
|
||||
|
||||
GroundObjectField* newPtrField = groundFindField(*newAllocator.data.customVal, "ptr");
|
||||
if (newPtrField == NULL) {
|
||||
ERROR("Failed to find field for pointer", "ValueError");
|
||||
}
|
||||
|
||||
GroundValue* newPtr;
|
||||
if (ptr == NULL) {
|
||||
newPtr = NULL;
|
||||
} else {
|
||||
newPtr = malloc(sizeof(GroundValue) * currentCapacity->value.data.intVal);
|
||||
if (newPtr == NULL) {
|
||||
ERROR("Failed to allocate new pointer in duplicator", "AllocError");
|
||||
}
|
||||
|
||||
memcpy(newPtr, ptr, sizeof(GroundValue) * currentCapacity->value.data.intVal);
|
||||
}
|
||||
newPtrField->value.data.intVal = (int64_t)newPtr;
|
||||
|
||||
GroundObjectField* newCapacity = groundFindField(*newAllocator.data.customVal, "capacity");
|
||||
if (newCapacity == NULL) {
|
||||
ERROR("Failed to find field for capacity", "ValueError");
|
||||
}
|
||||
newCapacity->value.data.intVal = currentCapacity->value.data.intVal;
|
||||
return newAllocator;
|
||||
}
|
||||
|
||||
void ground_init(GroundScope* scope) {
|
||||
allocatorStruct = groundCreateStruct();
|
||||
groundAddFieldToStruct(&allocatorStruct, "ptr", groundCreateValue(INT, 0)); // private
|
||||
groundAddFieldToStruct(&allocatorStruct, "capacity", groundCreateValue(INT, 0)); // protected
|
||||
|
||||
groundAddFunctionToStruct(&allocatorStruct, "allocate", groundAllocatorAllocate, ANY, 1, INT, "amount");
|
||||
groundAddFunctionToStruct(&allocatorStruct, "addCapacity", groundAllocatorAddCapacity, ANY, 1, INT, "amount");
|
||||
groundAddFunctionToStruct(&allocatorStruct, "getAtOffset", groundAllocatorGetAtOffset, ANY, 1, INT, "offset");
|
||||
groundAddFunctionToStruct(&allocatorStruct, "setAtOffset", groundAllocatorSetAtOffset, ANY, 2, INT, "offset", ANY, "value");
|
||||
|
||||
groundAddFunctionToStruct(&allocatorStruct, "destructor", groundAllocatorDestructor, INT, 0);
|
||||
groundAddFunctionToStruct(&allocatorStruct, "duplicator", groundAllocatorDuplicator, CUSTOM, 1, CUSTOM, "self");
|
||||
|
||||
GroundValue structVal = groundCreateValue(STRUCTVAL, allocatorStruct);
|
||||
groundAddValueToScope(scope, "Allocator", structVal);
|
||||
}
|
||||
168
libs/socket/socket.c
Normal file
168
libs/socket/socket.c
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <groundvm.h>
|
||||
#include <groundext.h>
|
||||
|
||||
#define BACKLOG 16
|
||||
#define CHUNK_SIZE 4096
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
GroundFunction* function;
|
||||
} client_t;
|
||||
|
||||
typedef struct {
|
||||
char* data;
|
||||
size_t len;
|
||||
size_t cap;
|
||||
} buf_t;
|
||||
|
||||
static void buf_init(buf_t *b) {
|
||||
b->data = malloc(CHUNK_SIZE);
|
||||
b->len = 0;
|
||||
b->cap = CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static int buf_append(buf_t *b, const char *src, size_t n) {
|
||||
if (b->len + n > b->cap) {
|
||||
size_t new_cap = b->cap;
|
||||
while (new_cap < b->len + n) new_cap *= 2;
|
||||
char *p = realloc(b->data, new_cap);
|
||||
if (!p) return -1;
|
||||
b->data = p;
|
||||
b->cap = new_cap;
|
||||
}
|
||||
memcpy(b->data + b->len, src, n);
|
||||
b->len += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void buf_free(buf_t *b) {
|
||||
free(b->data);
|
||||
b->data = NULL;
|
||||
b->len = b->cap = 0;
|
||||
}
|
||||
|
||||
static void handle(int fd, const char *data, size_t len, GroundFunction* function) {
|
||||
GroundValue value = groundRunFunction(function, 1, groundCreateValue(STRING, data));
|
||||
if (value.type == ERROR) {
|
||||
printf(" error type: %s\n", value.data.errorVal.type);
|
||||
printf(" error what: %s\n", value.data.errorVal.what);
|
||||
send(fd, "Server Error", 12, 0);
|
||||
return;
|
||||
}
|
||||
if (value.type != STRING) {
|
||||
printf(" wrong type: %d\n", value.type);
|
||||
send(fd, "Server Error", 12, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t resplen = strlen(value.data.stringVal);
|
||||
send(fd, value.data.stringVal, resplen, 0);
|
||||
}
|
||||
|
||||
static void *client_thread(void *arg) {
|
||||
client_t *client = arg;
|
||||
int fd = client->fd;
|
||||
GroundFunction* function = client->function;
|
||||
// ...
|
||||
free(client);
|
||||
|
||||
buf_t buf;
|
||||
buf_init(&buf);
|
||||
|
||||
char chunk[CHUNK_SIZE];
|
||||
while (1) {
|
||||
ssize_t n = recv(fd, chunk, sizeof(chunk), 0);
|
||||
if (n < 0) { perror("recv"); break; }
|
||||
if (n == 0) break; // client disconnected
|
||||
|
||||
if (buf_append(&buf, chunk, n) < 0) {
|
||||
fprintf(stderr, "[fd=%d] out of memory\n", fd);
|
||||
break;
|
||||
}
|
||||
|
||||
// handle every complete line we've accumulated
|
||||
while (1) {
|
||||
char* newline = memchr(buf.data, '\n', buf.len);
|
||||
if (!newline) break;
|
||||
|
||||
size_t msg_len = newline - buf.data;
|
||||
|
||||
// null terminate and handle
|
||||
char saved = buf.data[msg_len];
|
||||
buf.data[msg_len] = '\0';
|
||||
handle(fd, buf.data, msg_len, function);
|
||||
buf.data[msg_len] = saved;
|
||||
|
||||
// shift the buffer left past the consumed message
|
||||
size_t consumed = msg_len + 1;
|
||||
memmove(buf.data, buf.data + consumed, buf.len - consumed);
|
||||
buf.len -= consumed;
|
||||
}
|
||||
}
|
||||
|
||||
buf_free(&buf);
|
||||
close(fd);
|
||||
printf("[fd=%d] disconnected\n", fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GroundValue socket_Listen(GroundScope* scope, List args) {
|
||||
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) { perror("socket"); ERROR("Failed to open socket (see above error for detail", "SocketFail"); }
|
||||
|
||||
int64_t port = args.values[1].data.intVal;
|
||||
GroundFunction* function = args.values[0].data.fnVal;
|
||||
|
||||
int opt = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
|
||||
struct sockaddr_in addr = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(port),
|
||||
.sin_addr = { .s_addr = INADDR_ANY },
|
||||
};
|
||||
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
perror("bind"); ERROR("Failed to bind to socket (see above error for detail", "SocketFail");
|
||||
}
|
||||
if (listen(listen_fd, BACKLOG) < 0) {
|
||||
perror("listen"); ERROR("Failed to listen on socket (see above error for detail)", "SocketFail");
|
||||
}
|
||||
|
||||
while (1) {
|
||||
client_t *client = malloc(sizeof(client_t));
|
||||
socklen_t addrlen = sizeof(client->addr);
|
||||
client->fd = accept(listen_fd, (struct sockaddr *)&client->addr, &addrlen);
|
||||
client->function = function;
|
||||
if (client->fd < 0) {
|
||||
perror("accept");
|
||||
free(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_t tid;
|
||||
if (pthread_create(&tid, NULL, client_thread, client) != 0) {
|
||||
perror("pthread_create");
|
||||
close(client->fd);
|
||||
free(client);
|
||||
continue;
|
||||
}
|
||||
pthread_detach(tid);
|
||||
}
|
||||
|
||||
close(listen_fd);
|
||||
return groundCreateValue(INT, 0);
|
||||
}
|
||||
|
||||
void ground_init(GroundScope* scope) {
|
||||
groundAddNativeFunction(scope, "socket_Listen", socket_Listen, ANY, 2, FUNCTION, "handler", INT, "port");
|
||||
}
|
||||
101
libs/threading/thread.c
Normal file
101
libs/threading/thread.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include "thread.h"
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <groundext.h>
|
||||
#include <groundvm.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
GroundStruct threadStruct = {};
|
||||
|
||||
typedef struct {
|
||||
GroundFunction* func;
|
||||
GroundObject* funcArgsListStruct;
|
||||
} ThreadArgs;
|
||||
|
||||
|
||||
GroundScope copyGroundScope(GroundScope* scope);
|
||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
|
||||
|
||||
void* threadMain(void* threadArgs) {
|
||||
ThreadArgs* realArgs = (ThreadArgs*)threadArgs;
|
||||
|
||||
GroundFunction func = *realArgs->func;
|
||||
|
||||
GroundObjectField* listSizeField = groundFindField(*realArgs->funcArgsListStruct, "size");
|
||||
if (listSizeField == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
int64_t listSize = listSizeField->value.data.intVal;
|
||||
|
||||
GroundValue* listPtr = (GroundValue*)groundFindField(*realArgs->funcArgsListStruct, "ptr")->value.data.intVal;
|
||||
|
||||
// put args from list into func args
|
||||
va_list list;
|
||||
GroundScope funcScope = copyGroundScope(&func.closure);
|
||||
for (int64_t i = 0; i < listSize; i++) {
|
||||
groundAddValueToScope(&funcScope, func.args[i].name, listPtr[i]);
|
||||
}
|
||||
|
||||
// run func
|
||||
free(realArgs);
|
||||
interpretGroundProgram(&func.program, &funcScope);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GroundValue threadStructStart(GroundScope* scope, List args) {
|
||||
GroundVariable* funcField = groundFindVariable(scope, "fn");
|
||||
GroundVariable* argsField = groundFindVariable(scope, "args");
|
||||
|
||||
pthread_t newThread;
|
||||
ThreadArgs *threadArgs = malloc(sizeof(ThreadArgs));
|
||||
threadArgs->func = funcField->value.data.fnVal;
|
||||
threadArgs->funcArgsListStruct = (GroundObject*)argsField->value.data.customVal;
|
||||
|
||||
pthread_create(&newThread, NULL, threadMain, threadArgs);
|
||||
|
||||
return groundCreateValue(INT, 0);
|
||||
}
|
||||
|
||||
GroundValue threadStructConstructor(GroundScope* scope, List args) {
|
||||
GroundValue value = groundCreateValue(CUSTOM, &threadStruct);
|
||||
|
||||
GroundValue function = args.values[0];
|
||||
GroundValue threadFuncArgs = args.values[1];
|
||||
|
||||
GroundObjectField* funcField = groundFindField(*value.data.customVal, "fn");
|
||||
GroundObjectField* argsField = groundFindField(*value.data.customVal, "args");
|
||||
|
||||
funcField->value = function;
|
||||
argsField->value = threadFuncArgs;
|
||||
|
||||
|
||||
|
||||
|
||||
value.type = CUSTOM;
|
||||
return value;
|
||||
}
|
||||
|
||||
void initThreadStruct(GroundScope* scope) {
|
||||
threadStruct = groundCreateStruct();
|
||||
|
||||
groundAddFieldToStruct(&threadStruct, "fn", groundCreateValue(FUNCTION, 0));
|
||||
groundAddFieldToStruct(&threadStruct, "args", groundCreateValue(INT, 0));
|
||||
groundAddFieldToStruct(&threadStruct, "pthread", groundCreateValue(INT, 0));
|
||||
|
||||
groundAddFunctionToStruct(&threadStruct, "start", threadStructStart, INT, 0);
|
||||
|
||||
groundAddNativeFunction(
|
||||
scope,
|
||||
"Thread_SOLS_CONSTRUCTOR",
|
||||
threadStructConstructor,
|
||||
CUSTOM,
|
||||
2,
|
||||
FUNCTION,
|
||||
"function",
|
||||
CUSTOM,
|
||||
"args"
|
||||
);
|
||||
}
|
||||
8
libs/threading/thread.h
Normal file
8
libs/threading/thread.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef TASK_H
|
||||
#define TASK_H
|
||||
|
||||
#include <groundext.h>
|
||||
|
||||
void initThreadStruct(GroundScope* scope);
|
||||
|
||||
#endif
|
||||
6
libs/threading/threading.c
Normal file
6
libs/threading/threading.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "thread.h"
|
||||
#include <groundext.h>
|
||||
|
||||
void ground_init(GroundScope* scope) {
|
||||
initThreadStruct(scope);
|
||||
}
|
||||
@@ -376,6 +376,34 @@ bool checkForErrors(GroundProgram* program) {
|
||||
return true;
|
||||
}
|
||||
|
||||
GroundState createGroundState() {
|
||||
GroundState state = {
|
||||
.variables = NULL,
|
||||
.labels = NULL
|
||||
};
|
||||
return state;
|
||||
}
|
||||
|
||||
GroundCompilerVariable* cFindVariable(GroundState* state, const char* id) {
|
||||
GroundCompilerVariable* var;
|
||||
HASH_FIND_STR(state->variables, id, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
void cDeleteVariable(GroundState* state, const char* id) {
|
||||
GroundCompilerVariable* var;
|
||||
HASH_FIND_STR(state->variables, id, var);
|
||||
HASH_DEL(state->variables, var);
|
||||
}
|
||||
|
||||
GroundCompilerVariable* cAddVariable(GroundState* state, const char* id, GroundValueType type) {
|
||||
GroundCompilerVariable* var = malloc(sizeof(GroundCompilerVariable));
|
||||
snprintf(var->id, MAX_ID_LEN, "%s", id);
|
||||
var->type = type;
|
||||
HASH_ADD_STR(state->variables, id, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
void compileGroundProgram(GroundProgram* program, char* name) {
|
||||
|
||||
if (!checkForErrors(program)) {
|
||||
@@ -383,13 +411,23 @@ void compileGroundProgram(GroundProgram* program, char* name) {
|
||||
return;
|
||||
}
|
||||
|
||||
GroundState state = createGroundState();
|
||||
|
||||
Tram_Program tramProgram = Tram_Program_Create();
|
||||
|
||||
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
|
||||
Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
|
||||
|
||||
// Resolve labels
|
||||
for (size_t i = 0; i < program->size; i++) {
|
||||
compileGroundInstruction(&program->instructions[i], &tramProgram);
|
||||
if (program->instructions[i].type == CREATELABEL) {
|
||||
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable(program->instructions[i].args.args[0].value.refName)});
|
||||
Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < program->size; i++) {
|
||||
compileGroundInstruction(&program->instructions[i], &tramProgram, &state);
|
||||
}
|
||||
|
||||
Tram_Compiler* compiler = Tram_Compiler_Create(tramProgram);
|
||||
@@ -406,46 +444,7 @@ void compileGroundProgram(GroundProgram* program, char* name) {
|
||||
|
||||
}
|
||||
|
||||
typedef struct GroundCompilerVariable {
|
||||
GroundValueType type;
|
||||
char id[MAX_ID_LEN];
|
||||
UT_hash_handle hh;
|
||||
} GroundCompilerVariable;
|
||||
|
||||
typedef struct GroundState {
|
||||
GroundCompilerVariable* variables;
|
||||
GroundLabel* labels;
|
||||
} GroundState;
|
||||
|
||||
GroundState createGroundState() {
|
||||
GroundState state = {
|
||||
.variables = NULL,
|
||||
.labels = NULL
|
||||
};
|
||||
return state;
|
||||
}
|
||||
|
||||
GroundCompilerVariable* cFindVariable(GroundState* state, const char* id) {
|
||||
GroundCompilerVariable* var;
|
||||
HASH_FIND_STR(state->variables, id, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
GroundCompilerVariable* cDeleteVariable(GroundState* state, const char* id) {
|
||||
GroundCompilerVariable* var;
|
||||
HASH_FIND_STR(state->variables, id, var);
|
||||
HASH_DEL(state->variables, var);
|
||||
}
|
||||
|
||||
GroundCompilerVariable* cAddVariable(GroundState* state, const char* id, GroundValueType type) {
|
||||
GroundCompilerVariable* var = malloc(sizeof(GroundCompilerVariable));
|
||||
snprintf(var->id, MAX_ID_LEN, "%s", id);
|
||||
var->type = type;
|
||||
HASH_ADD_STR(state->variables, id, var);
|
||||
return var;
|
||||
}
|
||||
|
||||
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program) {
|
||||
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program, GroundState* state) {
|
||||
switch (instruction->type) {
|
||||
case IF:
|
||||
break;
|
||||
@@ -542,7 +541,7 @@ void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* prog
|
||||
case EXTERN:
|
||||
break;
|
||||
case CREATELABEL: {
|
||||
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
|
||||
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable(instruction->args.args[0].value.refName)});
|
||||
Tram_Program_AddInstruction(program, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
|
||||
break;
|
||||
}
|
||||
@@ -557,4 +556,4 @@ void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* prog
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,18 @@
|
||||
#include <tram.h>
|
||||
#endif
|
||||
|
||||
typedef struct GroundCompilerVariable {
|
||||
GroundValueType type;
|
||||
char id[MAX_ID_LEN];
|
||||
UT_hash_handle hh;
|
||||
} GroundCompilerVariable;
|
||||
|
||||
typedef struct GroundState {
|
||||
GroundCompilerVariable* variables;
|
||||
GroundLabel* labels;
|
||||
} GroundState;
|
||||
|
||||
void compileGroundProgram(GroundProgram* program, char* name);
|
||||
#ifdef GROUND_COMPILE_WITH_TRAM
|
||||
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program);
|
||||
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program, GroundState* state);
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
char* getFileContents(const char* filename) {
|
||||
// https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c
|
||||
FILE* fp;
|
||||
@@ -125,7 +126,7 @@ GroundValue groundCreateValue(GroundValueType type, ...) {
|
||||
gv.type = CUSTOM;
|
||||
gv.data.customVal = malloc(sizeof(GroundObject));
|
||||
*gv.data.customVal = createObject(*gstruct);
|
||||
|
||||
|
||||
// Deep copy the struct definition so it stays valid
|
||||
gv.customType = malloc(sizeof(GroundStruct));
|
||||
gv.customType->size = gstruct->size;
|
||||
@@ -151,7 +152,10 @@ GroundValue groundCreateValue(GroundValueType type, ...) {
|
||||
return gv;
|
||||
}
|
||||
|
||||
void segfaultHandle(int signal);
|
||||
|
||||
GroundValue groundRunProgram(GroundProgram* program) {
|
||||
signal(SIGSEGV, segfaultHandle);
|
||||
GroundVariable* variables = NULL;
|
||||
GroundLabel* labels = NULL;
|
||||
GroundScope scope = {
|
||||
@@ -226,8 +230,7 @@ GroundValue groundRunFunction(GroundFunction* function, size_t argc, ...) {
|
||||
return createErrorGroundValue(createGroundError("Null function passed to groundRunFunction", "valueError", NULL, NULL));
|
||||
}
|
||||
|
||||
// Seems to crash some functions
|
||||
// GroundScope callScope = copyGroundScope(&function->closure);
|
||||
GroundScope callScope = copyGroundScope(&function->closure);
|
||||
|
||||
if (function->isNative) {
|
||||
List argsList = createList();
|
||||
@@ -237,14 +240,6 @@ GroundValue groundRunFunction(GroundFunction* function, size_t argc, ...) {
|
||||
return function->nativeFn(NULL, argsList);
|
||||
}
|
||||
|
||||
GroundScope callScope = {
|
||||
.labels = malloc(sizeof(GroundLabel*)),
|
||||
.variables = malloc(sizeof(GroundVariable*)),
|
||||
.isMainScope = false
|
||||
};
|
||||
*callScope.variables = NULL;
|
||||
*callScope.labels = NULL;
|
||||
|
||||
if (argc != function->argSize) {
|
||||
return createErrorGroundValue(createGroundError("Too few or too many arguments for function", "callError", NULL, NULL));
|
||||
}
|
||||
|
||||
@@ -119,6 +119,10 @@ char* getFileContents(const char* filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void segfaultHandle(int signal) {
|
||||
runtimeError(FIXME, "The Ground interpreter has crashed due to a segmentation fault. Please report this issue as soon as possible, with as much detail as possible.", NULL, currentInstruction);
|
||||
}
|
||||
|
||||
GroundLabel* findLabel(GroundLabel* head, const char *id) {
|
||||
GroundLabel *item;
|
||||
HASH_FIND_STR(head, id, item);
|
||||
@@ -157,14 +161,11 @@ void deleteVariable(GroundVariable** head, GroundVariable *item) {
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
if (strcmp(item->id, "self") == 0) {
|
||||
return;
|
||||
}
|
||||
if (item->freed) {
|
||||
return;
|
||||
}
|
||||
item->freed = true;
|
||||
if (item->value.type == CUSTOM) {
|
||||
if (strcmp(item->id, "self") != 0 && item->value.type == CUSTOM) {
|
||||
GroundObjectField* destructor = findField(*item->value.data.customVal, "destructor");
|
||||
if (destructor != NULL) {
|
||||
if (destructor->value.type == FUNCTION) {
|
||||
@@ -178,12 +179,20 @@ void deleteVariable(GroundVariable** head, GroundVariable *item) {
|
||||
runtimeError(FIXME, "Failed to allocate memory for scope variables", NULL, -1);
|
||||
}
|
||||
*scope.variables = NULL;
|
||||
*scope.catches = NULL;
|
||||
addVariable(scope.variables, "self", item->value);
|
||||
GroundInstruction instruction = createGroundInstruction(CALLMETHOD);
|
||||
addArgToInstruction(&instruction, createRefGroundArg(DIRREF, "self"));
|
||||
addArgToInstruction(&instruction, createRefGroundArg(FNREF, "destructor"));
|
||||
addArgToInstruction(&instruction, createRefGroundArg(DIRREF, ""));
|
||||
interpretGroundInstruction(instruction, &scope);
|
||||
|
||||
GroundVariable *var, *varTmp;
|
||||
HASH_ITER(hh, *scope.variables, var, varTmp) {
|
||||
deleteVariable(scope.variables, var);
|
||||
}
|
||||
free(scope.variables);
|
||||
free(scope.catches);
|
||||
} else {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Custom type destructor must be a function", NULL, -1);
|
||||
}
|
||||
@@ -206,6 +215,12 @@ void addVariable(GroundVariable **head, const char *id, GroundValue data) {
|
||||
HASH_ADD_STR(*head, id, item);
|
||||
}
|
||||
|
||||
void addVariableString(GroundScope* scope, const char* id, const char* str) {
|
||||
GroundValue tempVal = createStringGroundValue(str);
|
||||
addVariable(scope->variables, id, tempVal);
|
||||
freeGroundValue(&tempVal);
|
||||
}
|
||||
|
||||
GroundFunction* createGroundFunction() {
|
||||
GroundFunction* gf = malloc(sizeof(GroundFunction));
|
||||
gf->argSize = 0;
|
||||
@@ -318,14 +333,14 @@ GroundDebugInstruction parseDebugInstruction(char* in) {
|
||||
|
||||
free(instruction);
|
||||
return gdi;
|
||||
}
|
||||
}
|
||||
|
||||
void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunction fn, GroundValueType returnType, int argCount, ...) {
|
||||
GroundFunction* gf = createGroundFunction();
|
||||
gf->isNative = true;
|
||||
gf->nativeFn = fn;
|
||||
gf->returnType = returnType;
|
||||
|
||||
|
||||
va_list args;
|
||||
va_start(args, argCount);
|
||||
for(int i = 0; i < argCount; i++) {
|
||||
@@ -334,7 +349,7 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio
|
||||
addArgsToGroundFunction(gf, type, argName);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
addVariable(scope->variables, name, createFunctionGroundValue(gf));
|
||||
}
|
||||
|
||||
@@ -379,7 +394,10 @@ GroundValue resolveInstructionVariables(GroundInstruction* in, GroundScope* scop
|
||||
GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName);
|
||||
if (variable) {
|
||||
// If there is a duplicator, call it (except when returning and getting fields)
|
||||
if (variable->value.type == CUSTOM && in->type != RETURN && in->type != GETFIELD) {
|
||||
if ((variable->value.type == CUSTOM && in->type != RETURN && in->type != GETFIELD)
|
||||
&& (in->type == SET || in->type == SETFIELD ||
|
||||
in->type == CALL || in->type == CALLMETHOD
|
||||
)) {
|
||||
GroundObject* obj = variable->value.data.customVal;
|
||||
GroundObjectField* duplicator = findField(*obj, "duplicator");
|
||||
if (duplicator != NULL) {
|
||||
@@ -627,6 +645,9 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
GroundValue gv = createFunctionGroundValue(function);
|
||||
|
||||
addVariable(scope.variables, name, gv);
|
||||
// gp instructions are shallow copies shared with function->program; only free the array
|
||||
free(gp.instructions);
|
||||
free(name);
|
||||
}
|
||||
if (in->instructions[i].type == STRUCT) {
|
||||
if (in->instructions[i].args.length < 1) {
|
||||
@@ -669,6 +690,11 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
*gv.data.structVal = parseStruct(&gp, &scope, errorOffset);
|
||||
|
||||
addVariable(scope.variables, name, gv);
|
||||
// addVariable deep-copies gv; free the original here
|
||||
freeGroundValue(&gv);
|
||||
// struct gp instructions are deep-copied via copyGroundInstruction; safe to fully free
|
||||
freeGroundProgram(&gp);
|
||||
free(name);
|
||||
}
|
||||
if (in->instructions[i].type == PAUSE || instructionsToPause == 0) {
|
||||
printf("Paused execution\n");
|
||||
@@ -685,7 +711,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
runtimeError(FIXME, "Failed to read input from console with fgets", NULL, -1);
|
||||
}
|
||||
GroundDebugInstruction gdi = parseDebugInstruction(buffer);
|
||||
|
||||
|
||||
bool shouldBreak = false;
|
||||
switch (gdi.type) {
|
||||
case CONTINUE: {
|
||||
@@ -697,7 +723,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
break;
|
||||
}
|
||||
|
||||
case DUMP: {
|
||||
case DUMP: {
|
||||
if (scope.variables == NULL) {
|
||||
printf("Can't access variables");
|
||||
break;
|
||||
@@ -763,7 +789,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
printf("Unknown instruction (type \"help\" for help)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shouldBreak) {
|
||||
break;
|
||||
}
|
||||
@@ -822,7 +848,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
* These instructions are for controlling how the program is executed.
|
||||
* Instructions:
|
||||
* if, jump, end
|
||||
*/
|
||||
*/
|
||||
case IF: {
|
||||
if (in->args.length < 2) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 2 arguments", in, currentInstruction);
|
||||
@@ -912,7 +938,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
char buffer[256];
|
||||
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
|
||||
buffer[strcspn(buffer, "\n")] = '\0';
|
||||
addVariable(scope->variables, in->args.args[0].value.refName, createStringGroundValue(buffer));
|
||||
addVariableString(scope, in->args.args[0].value.refName, buffer);
|
||||
} else {
|
||||
runtimeError(FIXME, "Failed to read input from console with fgets", in, currentInstruction);
|
||||
}
|
||||
@@ -970,51 +996,51 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
|
||||
switch (in->args.args[0].value.value.type) {
|
||||
case INT: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("int"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "int");
|
||||
break;
|
||||
}
|
||||
case DOUBLE: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("double"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "double");
|
||||
break;
|
||||
}
|
||||
case STRING: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("string"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "string");
|
||||
break;
|
||||
}
|
||||
case CHAR: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("char"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "char");
|
||||
break;
|
||||
}
|
||||
case BOOL: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("bool"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "bool");
|
||||
break;
|
||||
}
|
||||
case LIST: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("list"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "list");
|
||||
break;
|
||||
}
|
||||
case CUSTOM: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("custom"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "custom");
|
||||
break;
|
||||
}
|
||||
case FUNCTION: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("function"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "function");
|
||||
break;
|
||||
}
|
||||
case STRUCTVAL: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("struct"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "struct");
|
||||
break;
|
||||
}
|
||||
case ANY: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("any"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "any");
|
||||
break;
|
||||
}
|
||||
case NONE: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("none"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "none");
|
||||
break;
|
||||
}
|
||||
case ERROR: {
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("error"));
|
||||
addVariableString(scope, in->args.args[1].value.refName, "error");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1058,9 +1084,11 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (in->args.args[i].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for all args after arg 1", in, currentInstruction);
|
||||
}
|
||||
appendToList(&newList, in->args.args[i].value.value);
|
||||
appendToList(&newList, copyGroundValue(&in->args.args[i].value.value));
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[0].value.refName, createListGroundValue(newList));
|
||||
GroundValue listVal = createListGroundValue(newList);
|
||||
addVariable(scope->variables, in->args.args[0].value.refName, listVal);
|
||||
freeGroundValue(&listVal);
|
||||
break;
|
||||
}
|
||||
case SETLISTAT: {
|
||||
@@ -1091,7 +1119,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (value->type != LIST) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
ListAccessStatus status = setListAt(&value->data.listVal, in->args.args[1].value.value.data.intVal, in->args.args[2].value.value);
|
||||
ListAccessStatus status = setListAt(&value->data.listVal, in->args.args[1].value.value.data.intVal, copyGroundValue(&in->args.args[2].value.value));
|
||||
switch (status) {
|
||||
case LIST_OKAY:
|
||||
break;
|
||||
@@ -1198,7 +1226,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (value->type != LIST) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
appendToList(&value->data.listVal, in->args.args[1].value.value);
|
||||
appendToList(&value->data.listVal, copyGroundValue(&in->args.args[1].value.value));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1326,7 +1354,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
|
||||
}
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue(buf));
|
||||
addVariableString(scope, in->args.args[1].value.refName, buf);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1361,11 +1389,12 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (right->type != STRING) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a String for arg 2", in, currentInstruction);
|
||||
}
|
||||
char* newString = malloc(strlen(left->data.stringVal) + strlen(right->data.stringVal));
|
||||
char* newString = malloc(strlen(left->data.stringVal) + strlen(right->data.stringVal) + 1);
|
||||
strcpy(newString, left->data.stringVal);
|
||||
strcat(newString, right->data.stringVal);
|
||||
|
||||
addVariable(scope->variables, in->args.args[2].value.refName, createStringGroundValue(newString));
|
||||
addVariableString(scope, in->args.args[2].value.refName, newString);
|
||||
free(newString);
|
||||
}
|
||||
else if (left->type == INT || left->type == DOUBLE) {
|
||||
if (right->type != INT && right->type != DOUBLE) {
|
||||
@@ -1964,6 +1993,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from native function", in, currentInstruction);
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[in->args.length - 1].value.refName, returnValue);
|
||||
freeGroundValue(&returnValue);
|
||||
}
|
||||
free(argsList.values);
|
||||
} else {
|
||||
@@ -1992,8 +2022,12 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
HASH_ITER(hh, *newScope.variables, var, tmp) {
|
||||
deleteVariable(newScope.variables, var);
|
||||
}
|
||||
free(newScope.variables);
|
||||
free(newScope.labels);
|
||||
free(newScope.catches);
|
||||
|
||||
addVariable(scope->variables, in->args.args[in->args.length - 1].value.refName, returnValue);
|
||||
freeGroundValue(&returnValue);
|
||||
currentInstruction = currentCurrentInstruction;
|
||||
}
|
||||
break;
|
||||
@@ -2005,9 +2039,6 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an object for arg 1", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[1].type != FNREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 2", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[in->args.length - 1].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef as the last arg", in, currentInstruction);
|
||||
}
|
||||
@@ -2025,32 +2056,77 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (fnvar == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "Method not found inside specified object", in, currentInstruction);
|
||||
}
|
||||
if (fnvar->value.type != FUNCTION) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "Provided reference does not reference a method", in, currentInstruction);
|
||||
|
||||
size_t fnRefPos = 0;
|
||||
if (in->args.args[1].type == FNREF) {
|
||||
if (fnvar == NULL) {
|
||||
runtimeError(FIXME, "fnvar is null (this should not happen)", in, currentInstruction);
|
||||
}
|
||||
if (fnvar->value.type != FUNCTION) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Field is not a method", in, currentInstruction);
|
||||
}
|
||||
fnRefPos = 1;
|
||||
} else for (size_t i = 2; i < in->args.length; i++) {
|
||||
if (in->args.args[i].type == FNREF) {
|
||||
if (fnvar == NULL) {
|
||||
runtimeError(FIXME, "fnvar is null (this should not happen)", in, currentInstruction);
|
||||
}
|
||||
if (fnvar->value.type != CUSTOM) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Field is not an object", in, currentInstruction);
|
||||
}
|
||||
obj = &fnvar->value;
|
||||
fnvar = findField(*fnvar->value.data.customVal, in->args.args[i].value.refName);
|
||||
if (fnvar == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
|
||||
}
|
||||
if (fnvar->value.type != FUNCTION) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Field is not a method", in, currentInstruction);
|
||||
}
|
||||
fnRefPos = i;
|
||||
break;
|
||||
} else if (in->args.args[i].type == DIRREF) {
|
||||
if (fnvar == NULL) {
|
||||
runtimeError(FIXME, "fnvar is null (this should not happen)", in, currentInstruction);
|
||||
}
|
||||
if (fnvar->value.type != CUSTOM) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Field is not an object", in, currentInstruction);
|
||||
}
|
||||
fnvar = findField(*fnvar->value.data.customVal, in->args.args[i].value.refName);
|
||||
if (fnvar == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
|
||||
}
|
||||
} else {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef or FnRef for callmethod args", in, currentInstruction);
|
||||
}
|
||||
}
|
||||
|
||||
if (fnRefPos == 0) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef after field list", in, currentInstruction);
|
||||
}
|
||||
|
||||
GroundFunction* function = fnvar->value.data.fnVal;
|
||||
if (function->argSize < in->args.length - 3) {
|
||||
if (function->argSize < in->args.length - fnRefPos - 2) {
|
||||
runtimeError(TOO_FEW_ARGS, "Incorrect amount of arguments provided for function", in, currentInstruction);
|
||||
}
|
||||
if (function->argSize > in->args.length - 3) {
|
||||
if (function->argSize > in->args.length - fnRefPos - 2) {
|
||||
runtimeError(TOO_MANY_ARGS, "Incorrect amount of arguments provided for function", in, currentInstruction);
|
||||
}
|
||||
if (function->isNative) {
|
||||
List argsList = createList();
|
||||
for (size_t i = 0; i < function->argSize; i++) {
|
||||
if (in->args.args[i + 2].type != VALUE) {
|
||||
if (in->args.args[i + fnRefPos + 1].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
|
||||
}
|
||||
if (function->nativeFn) {
|
||||
if (function->args[i].type != ANY && in->args.args[i + 2].value.value.type != function->args[i].type) {
|
||||
if (function->args[i].type != ANY && in->args.args[i + fnRefPos + 1].value.value.type != function->args[i].type) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
|
||||
}
|
||||
} else {
|
||||
if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + 2].value.value, &function->args[i])) {
|
||||
if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + fnRefPos + 1].value.value, &function->args[i])) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
|
||||
}
|
||||
}
|
||||
appendToList(&argsList, in->args.args[i + 2].value.value);
|
||||
appendToList(&argsList, in->args.args[i + fnRefPos + 1].value.value);
|
||||
}
|
||||
|
||||
GroundScope newscope = {
|
||||
@@ -2081,30 +2157,46 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (scope->isMainScope) {
|
||||
throwError(&returnValue.data.errorVal);
|
||||
}
|
||||
GroundVariable *var, *varTmp;
|
||||
HASH_ITER(hh, *newscope.variables, var, varTmp) {
|
||||
deleteVariable(newscope.variables, var);
|
||||
}
|
||||
free(newscope.variables);
|
||||
return returnValue;
|
||||
}
|
||||
if (function->returnType != ANY && returnValue.type != function->returnType) {
|
||||
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from native function", in, currentInstruction);
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[in->args.length - 1].value.refName, returnValue);
|
||||
freeGroundValue(&returnValue);
|
||||
|
||||
// Copy back modified variables
|
||||
HASH_ITER(hh, obj->data.customVal->fields, el, tmp) {
|
||||
el->value = findVariable(*newscope.variables, el->id)->value;
|
||||
GroundVariable* newscopeVar = findVariable(*newscope.variables, el->id);
|
||||
if (newscopeVar != NULL) {
|
||||
freeGroundValue(&el->value);
|
||||
el->value = copyGroundValue(&newscopeVar->value);
|
||||
}
|
||||
}
|
||||
|
||||
GroundVariable *var, *varTmp;
|
||||
HASH_ITER(hh, *newscope.variables, var, varTmp) {
|
||||
deleteVariable(newscope.variables, var);
|
||||
}
|
||||
free(newscope.variables);
|
||||
}
|
||||
free(argsList.values);
|
||||
} else {
|
||||
GroundScope newScope = copyGroundScope(&function->closure);
|
||||
for (size_t i = 0; i < function->argSize; i++) {
|
||||
if (in->args.args[i + 2].type != VALUE) {
|
||||
if (in->args.args[i + fnRefPos + 1].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
|
||||
}
|
||||
//if (in->args.args[i + 1].value.value.type != function->args[i].type) {
|
||||
if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + 2].value.value, &function->args[i])) {
|
||||
if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + fnRefPos + 1].value.value, &function->args[i])) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
|
||||
}
|
||||
addVariable(newScope.variables, function->args[i].name, in->args.args[i + 2].value.value);
|
||||
addVariable(newScope.variables, function->args[i].name, in->args.args[i + fnRefPos + 1].value.value);
|
||||
}
|
||||
// Add the object to the scope
|
||||
addVariable(newScope.variables, "self", *obj);
|
||||
@@ -2112,12 +2204,20 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
currentInstruction = function->startLine;
|
||||
GroundValue returnValue = interpretGroundProgram(&function->program, &newScope);
|
||||
if (returnValue.type == ERROR) {
|
||||
GroundVariable *var, *varTmp;
|
||||
HASH_ITER(hh, *newScope.variables, var, varTmp) {
|
||||
deleteVariable(newScope.variables, var);
|
||||
}
|
||||
free(newScope.variables);
|
||||
free(newScope.labels);
|
||||
free(newScope.catches);
|
||||
return returnValue;
|
||||
}
|
||||
if (function->returnType != ANY && returnValue.type != function->returnType) {
|
||||
runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from function", in, currentInstruction);
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[in->args.length - 1].value.refName, returnValue);
|
||||
freeGroundValue(&returnValue);
|
||||
currentInstruction = currentCurrentInstruction;
|
||||
|
||||
// Copy out the object
|
||||
@@ -2125,7 +2225,17 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (objvar == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "self not found in scope, did you drop the object?", in, currentInstruction);
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[0].value.refName, objvar->value);
|
||||
freeGroundValue(obj);
|
||||
*obj = copyGroundValue(&objvar->value);
|
||||
|
||||
// Clean up newScope variables and pointers
|
||||
GroundVariable *var, *varTmp;
|
||||
HASH_ITER(hh, *newScope.variables, var, varTmp) {
|
||||
deleteVariable(newScope.variables, var);
|
||||
}
|
||||
free(newScope.variables);
|
||||
free(newScope.labels);
|
||||
free(newScope.catches);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2325,7 +2435,10 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
}
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[0].value.refName, gv);
|
||||
|
||||
if (gv.type == CUSTOM) {
|
||||
gv.customType = NULL;
|
||||
}
|
||||
freeGroundValue(&gv);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2363,21 +2476,18 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
break;
|
||||
}
|
||||
// setfield &obj &field $value
|
||||
// also allows setting nested fields with:
|
||||
// setfield &obj &field1 &field2 &field3 ... $value
|
||||
case SETFIELD: {
|
||||
if (in->args.length < 3) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction);
|
||||
}
|
||||
if (in->args.length > 3) {
|
||||
runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction);
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 3 or more args", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[1].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[2].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 3", in, currentInstruction);
|
||||
// Check everything is a DIRREF wihle looping through the fields
|
||||
if (in->args.args[in->args.length - 1].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for last arg", in, currentInstruction);
|
||||
}
|
||||
|
||||
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
||||
@@ -2392,11 +2502,28 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
if (field == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
|
||||
}
|
||||
if (field->value.type != in->args.args[2].value.value.type) {
|
||||
|
||||
for (size_t i = 2; i < in->args.length - 1; i++) {
|
||||
if (field == NULL) {
|
||||
runtimeError(FIXME, "Field is null, this should have errored beforehand", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[i].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for field setter args", in, currentInstruction);
|
||||
}
|
||||
if (field->value.type != CUSTOM) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Field is not an object", in, currentInstruction);
|
||||
}
|
||||
field = findField(*field->value.data.customVal, in->args.args[i].value.refName);
|
||||
if (field == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
|
||||
}
|
||||
}
|
||||
|
||||
if (field->value.type != in->args.args[in->args.length - 1].value.value.type) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Field type and provided type do not match", in, currentInstruction);
|
||||
}
|
||||
|
||||
field->value = copyGroundValue(&in->args.args[2].value.value);
|
||||
field->value = copyGroundValue(&in->args.args[in->args.length - 1].value.value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
11
src/main.c
11
src/main.c
@@ -4,12 +4,16 @@
|
||||
#include "types.h"
|
||||
#include "serialize.h"
|
||||
#include "repl.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void segfaultHandle(int signal);
|
||||
|
||||
char* getFileContents(const char* filename);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
if (argc == 1) {
|
||||
exit(repl());
|
||||
}
|
||||
@@ -17,6 +21,7 @@ int main(int argc, char** argv) {
|
||||
bool compile = false;
|
||||
bool writeBytecode = false;
|
||||
bool readBytecode = false;
|
||||
bool segfaultHandler = true;
|
||||
char* fileName = NULL;
|
||||
char* outFileName = NULL;
|
||||
List groundArgs = createList();
|
||||
@@ -28,6 +33,9 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
compile = true;
|
||||
}
|
||||
else if (strcmp("--disable-segfault-handler", argv[i]) == 0) {
|
||||
segfaultHandler = false;
|
||||
}
|
||||
else if (strcmp("--help", argv[i]) == 0 || strcmp("-h", argv[i]) == 0) {
|
||||
printf("GroundVM help\n");
|
||||
printf("Usage: %s <file> [-c] [--compile] [-h] [--help] [-w <output>] [--writeBytecode <output>] [-b] [--bytecode]\n", argv[0]);
|
||||
@@ -66,6 +74,9 @@ int main(int argc, char** argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (segfaultHandler) signal(SIGSEGV, segfaultHandle);
|
||||
|
||||
|
||||
GroundProgram program;
|
||||
|
||||
if (readBytecode) {
|
||||
|
||||
44
src/types.c
44
src/types.c
@@ -89,14 +89,11 @@ GroundValue copyGroundValue(const GroundValue* gv) {
|
||||
case CHAR: newGv.data.charVal = gv->data.charVal; break;
|
||||
case BOOL: newGv.data.boolVal = gv->data.boolVal; break;
|
||||
case STRING:
|
||||
/*
|
||||
if (gv->data.stringVal != NULL) {
|
||||
newGv.data.stringVal = strdup(gv->data.stringVal);
|
||||
} else {
|
||||
newGv.data.stringVal = NULL;
|
||||
}
|
||||
*/
|
||||
newGv.data.stringVal = gv->data.stringVal;
|
||||
break;
|
||||
case LIST: {
|
||||
List newList = createList();
|
||||
@@ -109,6 +106,10 @@ GroundValue copyGroundValue(const GroundValue* gv) {
|
||||
}
|
||||
case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break;
|
||||
case STRUCTVAL: {
|
||||
if (gv->data.structVal == NULL) {
|
||||
newGv.data.structVal = NULL;
|
||||
break;
|
||||
}
|
||||
newGv.data.structVal = malloc(sizeof(GroundStruct));
|
||||
if (newGv.data.structVal == NULL) {
|
||||
printf("Couldn't allocate memory for GroundStruct copy\n");
|
||||
@@ -119,6 +120,7 @@ GroundValue copyGroundValue(const GroundValue* gv) {
|
||||
newGv.data.structVal->fields = malloc(gv->data.structVal->size * sizeof(GroundStructField));
|
||||
if (newGv.data.structVal->fields == NULL && gv->data.structVal->size > 0) {
|
||||
printf("Couldn't allocate memory for GroundStruct fields copy\n");
|
||||
printf("%p, %zu\n", newGv.data.structVal->fields, newGv.data.structVal->size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -166,6 +168,30 @@ GroundValue copyGroundValue(const GroundValue* gv) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ERROR: {
|
||||
const GroundError* err = &gv->data.errorVal;
|
||||
GroundError newErr;
|
||||
if (err->what != NULL) {
|
||||
newErr.what = strdup(err->what);
|
||||
} else {
|
||||
newErr.what = NULL;
|
||||
}
|
||||
if (err->type != NULL) {
|
||||
newErr.type = strdup(err->type);
|
||||
} else {
|
||||
newErr.type = NULL;
|
||||
}
|
||||
if (err->where != NULL) {
|
||||
newErr.where = malloc(sizeof(GroundInstruction));
|
||||
*newErr.where = copyGroundInstruction(err->where);
|
||||
} else {
|
||||
newErr.where = NULL;
|
||||
}
|
||||
newErr.line = err->line;
|
||||
newErr.hasLine = err->hasLine;
|
||||
newGv.data.errorVal = newErr;
|
||||
break;
|
||||
}
|
||||
case NONE:
|
||||
default: {
|
||||
|
||||
@@ -268,7 +294,7 @@ void printGroundValue(GroundValue* gv) {
|
||||
void freeGroundValue(GroundValue* gv) {
|
||||
if (gv->type == STRING && gv->data.stringVal != NULL) {
|
||||
// leak some memory for now
|
||||
// free(gv->data.stringVal);
|
||||
free(gv->data.stringVal);
|
||||
gv->data.stringVal = NULL;
|
||||
}
|
||||
if (gv->type == LIST && gv->data.listVal.values != NULL) {
|
||||
@@ -280,10 +306,15 @@ void freeGroundValue(GroundValue* gv) {
|
||||
list->values = NULL;
|
||||
gv->data.listVal = createList();
|
||||
}
|
||||
if (gv->type == STRUCTVAL && gv->data.structVal->fields != NULL) {
|
||||
if (gv->type == STRUCTVAL && gv->data.structVal != NULL) {
|
||||
GroundStruct* gstruct = gv->data.structVal;
|
||||
freeGroundStruct(gstruct);
|
||||
if (gstruct->fields != NULL) {
|
||||
freeGroundStruct(gstruct);
|
||||
free(gstruct->fields);
|
||||
gstruct->fields = NULL;
|
||||
}
|
||||
free(gstruct);
|
||||
gv->data.structVal = NULL;
|
||||
}
|
||||
if (gv->type == CUSTOM && gv->data.customVal != NULL) {
|
||||
freeGroundObject(gv->data.customVal);
|
||||
@@ -645,6 +676,7 @@ ListAccessStatus setListAt(List* list, size_t idx, GroundValue value) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (idx < list->size) {
|
||||
freeGroundValue(&list->values[idx]);
|
||||
list->values[idx] = value;
|
||||
return LIST_OKAY;
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user