added statis map object and used it to implement builtins. Also, new objects File and Directory

This commit is contained in:
cozis
2022-03-10 19:00:30 +01:00
parent 5b097e2b76
commit 8deec027d1
19 changed files with 824 additions and 1045 deletions
+146
View File
@@ -0,0 +1,146 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "basic.h"
#include "file.h"
#include "math.h"
static Object *bin_print(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
for(int i = 0; i < (int) argc; i += 1)
Object_Print(argv[i], stdout);
return Object_NewNone(Runtime_GetHeap(runtime), error);
}
static Object *bin_type(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 1);
(void) runtime;
(void) error;
return (Object*) argv[0]->type;
}
static Object *bin_count(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 1);
int n = Object_Count(argv[0], error);
if(error->occurred)
return NULL;
return Object_FromInt(n, Runtime_GetHeap(runtime), error);
}
static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
for(unsigned int i = 0; i < argc; i += 1)
if(!Object_ToBool(argv[i], error))
{
if(!error->occurred)
Error_Report(error, 0, "Assertion failed");
return NULL;
}
return Object_NewNone(Runtime_GetHeap(runtime), error);
}
static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
unsigned int total_count = 0;
for(unsigned int i = 0; i < argc; i += 1)
{
if(!Object_IsString(argv[i]))
{
Error_Report(error, 0, "Argument #%d is not a string", i+1);
return NULL;
}
total_count += Object_Count(argv[i], error);
if(error->occurred)
return NULL;
}
char starting[128];
char *buffer = starting;
if(total_count > sizeof(starting)-1)
{
buffer = malloc(total_count+1);
if(buffer == NULL)
{
Error_Report(error, 1, "No memory");
return NULL;
}
}
Object *result = NULL;
for(unsigned int i = 0, written = 0; i < argc; i += 1)
{
int n;
const char *s;
s = Object_ToString(argv[i], &n, Runtime_GetHeap(runtime), error);
if(error->occurred)
goto done;
memcpy(buffer + written, s, n);
written += n;
}
buffer[total_count] = '\0';
result = Object_FromString(buffer, total_count, Runtime_GetHeap(runtime), error);
done:
if(starting != buffer)
free(buffer);
return result;
}
static Object *bin_newBuffer(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 1);
long long int size = Object_ToInt(argv[0], error);
if(error->occurred == 1)
return NULL;
return Object_NewBuffer(size, Runtime_GetHeap(runtime), error);
}
static Object *bin_sliceBuffer(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 3);
long long int offset = Object_ToInt(argv[1], error);
if(error->occurred == 1) return NULL;
long long int length = Object_ToInt(argv[2], error);
if(error->occurred == 1) return NULL;
return Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error);
}
const StaticMapSlot bins_basic[] = {
{ "math", SM_SMAP, .as_smap = bins_math, },
{ "file", SM_SMAP, .as_smap = bins_file, },
// { "net", SM_SMAP, .as_smap = bins_net, },
{ "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 },
{ "sliceBuffer", SM_FUNCT, .as_funct = bin_sliceBuffer, .argc = 3 },
{ "strcat", SM_FUNCT, .as_funct = bin_strcat },
{ "type", SM_FUNCT, .as_funct = bin_type, .argc = 1 },
{ "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 },
{ "count", SM_FUNCT, .as_funct = bin_count, .argc = 1 },
{ "assert", SM_FUNCT, .as_funct = bin_assert, .argc = -1 },
{ NULL, SM_END, {}, {} },
};
+2
View File
@@ -0,0 +1,2 @@
#include "../o_staticmap.h"
extern const StaticMapSlot bins_basic[];
+278
View File
@@ -0,0 +1,278 @@
#include <assert.h>
#include <errno.h>
#include "file.h"
enum {
MD_READ = 0,
MD_WRITE = 1,
MD_APPEND = 2,
};
static Object *bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 2);
if(!Object_IsString(argv[0]))
{
Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
if(!Object_IsInt(argv[1]))
{
Error_Report(error, 0, "Expected second argument to be an int, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
Heap *heap = Runtime_GetHeap(runtime);
const char *path = Object_ToString(argv[0], NULL, heap, error);
if(error->occurred)
return NULL;
int mode = Object_ToInt(argv[1], error);
if(error->occurred)
return NULL;
FILE *fp;
{
const char *mode2;
switch(mode)
{
case MD_READ:
mode2 = "r";
break;
case MD_READ | MD_WRITE:
mode2 = "w+";
break;
case MD_READ | MD_APPEND:
case MD_READ | MD_WRITE | MD_APPEND:
mode2 = "a";
break;
default:
assert(0);
break;
}
fp = fopen(path, mode2);
if(fp == NULL)
return Object_NewNone(heap, error);
}
return Object_FromStream(fp, heap, error);
}
static Object *bin_read(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 3);
// Arg 0: file
// Arg 1: buffer
// Arg 2: count
if(!Object_IsFile(argv[0]))
{
Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
if(!Object_IsBuffer(argv[1]))
{
Error_Report(error, 0, "Expected first argument to be a buffer, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
Heap *heap = Runtime_GetHeap(runtime);
void *buff_addr;
int buff_size;
buff_addr = Object_GetBufferAddrAndSize(argv[1], &buff_size, error);
int read_size;
if(Object_IsNone(argv[2]))
{
read_size = buff_size;
}
else if(Object_IsInt(argv[2]))
{
long long int temp = Object_ToInt(argv[2], error);
if(error->occurred)
return NULL;
read_size = temp; // TODO: Handle potential overflow.
if(read_size > buff_size)
read_size = buff_size;
}
else
{
Error_Report(error, 0, "Expected third argument to be an int or none, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
FILE *fp = Object_ToStream(argv[0], error);
if(fp == NULL)
return NULL;
size_t n = fread(buff_addr, 1, read_size, fp);
return Object_FromInt(n, heap, error);
}
static Object *bin_write(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 3);
// Arg 0: file
// Arg 1: buffer
// Arg 2: count
if(!Object_IsFile(argv[0]))
{
Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
if(!Object_IsBuffer(argv[1]))
{
Error_Report(error, 0, "Expected first argument to be a buffer, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
Heap *heap = Runtime_GetHeap(runtime);
void *buff_addr;
int buff_size;
buff_addr = Object_GetBufferAddrAndSize(argv[1], &buff_size, error);
int write_size;
if(Object_IsNone(argv[2]))
{
write_size = buff_size;
}
else if(Object_IsInt(argv[2]))
{
long long int temp = Object_ToInt(argv[2], error);
if(error->occurred)
return NULL;
write_size = temp; // TODO: Handle potential overflow.
if(write_size > buff_size)
write_size = buff_size;
}
else
{
Error_Report(error, 0, "Expected third argument to be an int or none, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
FILE *fp = Object_ToStream(argv[0], error);
if(fp == NULL)
return NULL;
size_t n = fwrite(buff_addr, 1, write_size, fp);
return Object_FromInt(n, heap, error);
}
static Object *bin_openDir(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 1);
// Arg 0: path
if(!Object_IsString(argv[0]))
{
Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
Heap *heap = Runtime_GetHeap(runtime);
const char *path = Object_ToString(argv[0], NULL, heap, error);
if(error->occurred)
return NULL;
DIR *dir = opendir(path);
if(dir == NULL)
return Object_NewNone(heap, error);
Object *dob = Object_FromDIR(dir, heap, error);
if(error->occurred)
{
(void) closedir(dir);
return NULL;
}
return dob;
}
static Object *bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
{
assert(argc == 1);
// Arg 0: path
if(!Object_IsDir(argv[0]))
{
Error_Report(error, 0, "Expected first argument to be a directory, but it's a %s", Object_GetName(argv[0]));
return NULL;
}
DIR *dir = Object_ToDIR(argv[0], error);
if(error->occurred)
return NULL;
assert(dir != NULL);
Heap *heap = Runtime_GetHeap(runtime);
errno = 0;
struct dirent *ent = readdir(dir);
if(ent == NULL)
{
if(errno == 0)
// Nothing left to read.
return Object_NewNone(heap, error);
// An error occurred.
Error_Report(error, 1, "Failed to read directory item");
return NULL;
}
return Object_FromString(ent->d_name, -1, heap, error);
}
const StaticMapSlot bins_file[] = {
{ "READ", SM_INT, .as_int = MD_READ, },
{ "WRITE", SM_INT, .as_int = MD_WRITE, },
{ "APPEND", SM_INT, .as_int = MD_APPEND, },
{ "openFile", SM_FUNCT, .as_funct = bin_openFile, .argc = 2, },
{ "openDir", SM_FUNCT, .as_funct = bin_openDir, .argc = 1, },
{ "nextDirItem", SM_FUNCT, .as_funct = bin_nextDirItem, .argc = 1, },
{ "read", SM_FUNCT, .as_funct = bin_read, .argc = 2, },
{ "write", SM_FUNCT, .as_funct = bin_write, .argc = 3, },
{ NULL, SM_END, {}, {} },
};
+2
View File
@@ -0,0 +1,2 @@
#include "../o_staticmap.h"
extern const StaticMapSlot bins_file[];
+94
View File
@@ -0,0 +1,94 @@
#include <assert.h>
#include <math.h>
#include "math.h"
#define WRAP_FUNC(name) \
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
{ \
assert(argc == 1); \
\
if(Object_IsFloat(argv[0])) \
{ \
double v = Object_ToFloat(argv[0], error); \
\
if(error->occurred) \
return NULL; \
\
return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
} \
else \
{ \
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
return NULL; \
} \
}
#define WRAP_FUNC_2(name) \
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
{ \
assert(argc == 2); \
\
if(!Object_IsFloat(argv[0])) \
{ \
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
return NULL; \
} \
\
if(!Object_IsFloat(argv[1])) \
{ \
Error_Report(error, 0, "Expected second argument to be a float, but it's a %s", Object_GetName(argv[1]));\
return NULL; \
} \
\
double v1 = Object_ToFloat(argv[0], error); \
\
if(error->occurred) \
return NULL; \
\
double v2 = Object_ToFloat(argv[1], error); \
\
if(error->occurred) \
return NULL; \
\
return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
}
WRAP_FUNC(ceil)
WRAP_FUNC(floor)
WRAP_FUNC(sin)
WRAP_FUNC(cos)
WRAP_FUNC(tan)
WRAP_FUNC(asin)
WRAP_FUNC(acos)
WRAP_FUNC(atan)
WRAP_FUNC(exp)
WRAP_FUNC(log)
WRAP_FUNC(log10)
WRAP_FUNC(sqrt)
WRAP_FUNC_2(atan2)
WRAP_FUNC_2(pow)
const StaticMapSlot bins_math[] = {
{ "PI", SM_FLOAT, .as_float = M_PI },
{ "E", SM_FLOAT, .as_float = M_E },
{ "floor", SM_FUNCT, .as_funct = bin_floor, .argc = 1, },
{ "ceil", SM_FUNCT, .as_funct = bin_ceil, .argc = 1, },
{ "cos", SM_FUNCT, .as_funct = bin_cos, .argc = 1, },
{ "sin", SM_FUNCT, .as_funct = bin_sin, .argc = 1, },
{ "tan", SM_FUNCT, .as_funct = bin_tan, .argc = 1, },
{ "acos", SM_FUNCT, .as_funct = bin_acos, .argc = 1, },
{ "asin", SM_FUNCT, .as_funct = bin_asin, .argc = 1, },
{ "atan", SM_FUNCT, .as_funct = bin_atan, .argc = 1, },
{ "atan2", SM_FUNCT, .as_funct = bin_atan2, .argc = 2, },
{ "exp", SM_FUNCT, .as_funct = bin_exp, .argc = 1, },
{ "log", SM_FUNCT, .as_funct = bin_log, .argc = 1, },
{ "log10", SM_FUNCT, .as_funct = bin_log10, .argc = 1, },
{ "pow", SM_FUNCT, .as_funct = bin_pow, .argc = 1, },
{ "sqrt", SM_FUNCT, .as_funct = bin_sqrt, .argc = 1, },
{ NULL, SM_END, {}, {} },
};
+2
View File
@@ -0,0 +1,2 @@
#include "../o_staticmap.h"
extern const StaticMapSlot bins_math[];