utility functions for implementing noja functions in c; built-ins for socket management; http server draft in noja
This commit is contained in:
+1
-1
@@ -46,7 +46,7 @@ static const char usage[] =
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
assert(argc > 0);
|
||||
|
||||
|
||||
if(argc == 1)
|
||||
{
|
||||
// $ noja
|
||||
|
||||
+49
-95
@@ -32,7 +32,9 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include "net.h"
|
||||
#include "math.h"
|
||||
#include "utils.h"
|
||||
#include "basic.h"
|
||||
#include "files.h"
|
||||
#include "string.h"
|
||||
@@ -43,41 +45,48 @@
|
||||
#include "../runtime/runtime.h"
|
||||
#include "../compiler/compile.h"
|
||||
|
||||
static int bin_typename(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
ASSERT(argc == 1);
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
const char *name = argv[0]->type->name;
|
||||
Object *o_name = Object_FromString(name, -1, heap, error);
|
||||
if (o_name == NULL)
|
||||
return -1;
|
||||
|
||||
rets[0] = o_name;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(runtime);
|
||||
UNUSED(rets);
|
||||
UNUSED(error);
|
||||
|
||||
|
||||
for(int i = 0; i < (int) argc; i += 1)
|
||||
Object_Print(argv[i], stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bin_import(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
static int bin_import(Runtime *runtime,
|
||||
Object **argv,
|
||||
unsigned int argc,
|
||||
Object *rets[static MAX_RETS],
|
||||
Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
ASSERT(argc == 1);
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
ASSERT(heap != NULL);
|
||||
|
||||
Object *o_path = argv[0];
|
||||
const char *path;
|
||||
size_t path_len;
|
||||
{
|
||||
if(!Object_IsString(o_path))
|
||||
{
|
||||
Error_Report(error, 0, "Argument #%d is not a string", 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
path = Object_GetString(o_path, &path_len);
|
||||
if (path == NULL)
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
ParsedArgument pargs[2];
|
||||
if (!parseArgs(error, argv, argc, pargs, "s"))
|
||||
return -1;
|
||||
|
||||
const char *path = pargs[0].as_string.data;
|
||||
size_t path_len = pargs[0].as_string.size;
|
||||
|
||||
char full_path[1024];
|
||||
|
||||
if(path[0] == '/') {
|
||||
@@ -101,88 +110,28 @@ static int bin_import(Runtime *runtime, Object **argv, unsigned int argc, Object
|
||||
memcpy(full_path + written, path, path_len);
|
||||
full_path[written + path_len] = '\0';
|
||||
}
|
||||
|
||||
Error sub_error;
|
||||
Error_Init(&sub_error);
|
||||
Source *src = Source_FromFile(full_path, &sub_error);
|
||||
if(src == NULL) {
|
||||
|
||||
Object *o_none = Object_NewNone(heap, error);
|
||||
if(o_none == NULL)
|
||||
return -1;
|
||||
|
||||
Object *o_err = Object_FromString(sub_error.message, -1, heap, error);
|
||||
if(o_err == NULL)
|
||||
return -1;
|
||||
|
||||
Error_Free(&sub_error);
|
||||
rets[0] = o_none;
|
||||
rets[1] = o_err;
|
||||
return 2;
|
||||
}
|
||||
Source *src = Source_FromFile(full_path, error);
|
||||
if(src == NULL)
|
||||
return -1;
|
||||
|
||||
CompilationErrorType errtyp;
|
||||
Executable *exe = compile(src, &sub_error, &errtyp);
|
||||
Executable *exe = compile(src, error, &errtyp);
|
||||
if(exe == NULL) {
|
||||
const char *errname;
|
||||
switch(errtyp) {
|
||||
default:
|
||||
case CompilationErrorType_INTERNAL: errname = NULL; break;
|
||||
case CompilationErrorType_SYNTAX: errname = "Syntax"; break;
|
||||
case CompilationErrorType_SEMANTIC: errname = "Semantic"; break;
|
||||
}
|
||||
UNUSED(errname);
|
||||
|
||||
Object *o_none = Object_NewNone(heap, error);
|
||||
if(o_none == NULL) {
|
||||
Source_Free(src);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Object *o_err = Object_FromString(sub_error.message, -1, heap, error);
|
||||
if(o_err == NULL) {
|
||||
Source_Free(src);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Source_Free(src);
|
||||
Error_Free(&sub_error);
|
||||
rets[0] = o_none;
|
||||
rets[1] = o_err;
|
||||
return 2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Object *sub_rets[8];
|
||||
int retc = run(runtime, &sub_error, exe, 0, NULL, NULL, 0, sub_rets);
|
||||
int retc = run(runtime, error, exe, 0, NULL, NULL, 0, sub_rets);
|
||||
if(retc < 0)
|
||||
{
|
||||
const char *errname = "Runtime";
|
||||
// Snapshot?
|
||||
UNUSED(errname);
|
||||
|
||||
Object *o_none = Object_NewNone(heap, error);
|
||||
if(o_none == NULL) {
|
||||
Source_Free(src);
|
||||
Executable_Free(exe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Object *o_err = Object_FromString(sub_error.message, -1, heap, error);
|
||||
if(o_err == NULL) {
|
||||
Source_Free(src);
|
||||
Executable_Free(exe);
|
||||
return -1;
|
||||
}
|
||||
Error_Free(&sub_error);
|
||||
rets[0] = o_none;
|
||||
rets[1] = o_err;
|
||||
Source_Free(src);
|
||||
Executable_Free(exe);
|
||||
return 2;
|
||||
return -1;
|
||||
}
|
||||
ASSERT(retc == 1);
|
||||
|
||||
Error_Free(&sub_error);
|
||||
Source_Free(src);
|
||||
Executable_Free(exe);
|
||||
rets[0] = sub_rets[0];
|
||||
@@ -355,13 +304,14 @@ void bins_basic_init(StaticMapSlot slots[])
|
||||
slots[3].as_type = Object_GetBoolType();
|
||||
slots[4].as_type = Object_GetFloatType();
|
||||
slots[5].as_type = Object_GetStringType();
|
||||
slots[6].as_type = Object_GetListType();
|
||||
slots[7].as_type = Object_GetMapType();
|
||||
slots[8].as_type = Object_GetFileType();
|
||||
slots[9].as_type = Object_GetDirType();
|
||||
slots[10].as_type = Object_GetNullableType();
|
||||
slots[11].as_type = Object_GetSumType();
|
||||
slots[12].as_object = Object_NewAny();
|
||||
slots[6].as_type = Object_GetBufferType();
|
||||
slots[7].as_type = Object_GetListType();
|
||||
slots[8].as_type = Object_GetMapType();
|
||||
slots[9].as_type = Object_GetFileType();
|
||||
slots[10].as_type = Object_GetDirType();
|
||||
slots[11].as_type = Object_GetNullableType();
|
||||
slots[12].as_type = Object_GetSumType();
|
||||
slots[13].as_object = Object_NewAny();
|
||||
}
|
||||
|
||||
StaticMapSlot bins_basic[] = {
|
||||
@@ -371,6 +321,7 @@ StaticMapSlot bins_basic[] = {
|
||||
{ TYPENAME_BOOL, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ TYPENAME_FLOAT, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ TYPENAME_STRING, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ TYPENAME_BUFFER, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ TYPENAME_LIST, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ TYPENAME_MAP, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
{ TYPENAME_FILE, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
||||
@@ -378,6 +329,8 @@ StaticMapSlot bins_basic[] = {
|
||||
{ TYPENAME_NULLABLE, SM_TYPE, .as_type = NULL },
|
||||
{ TYPENAME_SUM, SM_TYPE, .as_type = NULL },
|
||||
{ "any", SM_OBJECT, .as_object = NULL },
|
||||
|
||||
{ "net", SM_SMAP, .as_smap = bins_net, },
|
||||
{ "math", SM_SMAP, .as_smap = bins_math, },
|
||||
{ "files", SM_SMAP, .as_smap = bins_files, },
|
||||
{ "buffer", SM_SMAP, .as_smap = bins_buffer, },
|
||||
@@ -391,6 +344,7 @@ StaticMapSlot bins_basic[] = {
|
||||
{ "error", SM_FUNCT, .as_funct = bin_error, .argc = 1 },
|
||||
{ "assert", SM_FUNCT, .as_funct = bin_assert, .argc = -1 },
|
||||
{ "istypeof", SM_FUNCT, .as_funct = bin_istypeof, .argc = 2, },
|
||||
{ "typename", SM_FUNCT, .as_funct = bin_typename, .argc = 1, },
|
||||
{ "keysof", SM_FUNCT, .as_funct = bin_keysof, .argc = 1, },
|
||||
{ NULL, SM_END, {}, {} },
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "buffer.h"
|
||||
#include "utils.h"
|
||||
#include "../utils/defs.h"
|
||||
#include "../utils/utf8.h"
|
||||
#include "../runtime/runtime.h"
|
||||
|
||||
static int bin_new(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
@@ -12,7 +14,7 @@ static int bin_new(Runtime *runtime, Object **argv, unsigned int argc, Object *r
|
||||
Error_Report(error, 0, "Argument is not an int");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
long long int size = Object_GetInt(argv[0]);
|
||||
|
||||
Object *temp = Object_NewBuffer(size, Runtime_GetHeap(runtime), error);
|
||||
@@ -53,6 +55,22 @@ static int bin_sliceUp(Runtime *runtime, Object **argv, unsigned int argc, Objec
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bin_fromString(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
ASSERT(argc == 1);
|
||||
ParsedArgument pargs[1];
|
||||
if (!parseArgs(error, argv, argc, pargs, "s"))
|
||||
return -1;
|
||||
|
||||
const char *str = pargs[0].as_string.data;
|
||||
size_t len = pargs[0].as_string.size;
|
||||
Object *buffer = Object_NewBufferFromString(str, len, Runtime_GetHeap(runtime), error);
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
rets[0] = buffer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bin_toString(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
@@ -70,6 +88,9 @@ static int bin_toString(Runtime *runtime, Object **argv, unsigned int argc, Obje
|
||||
buffaddr = Object_GetBuffer(argv[0], &buffsize);
|
||||
ASSERT(buffaddr != NULL);
|
||||
|
||||
if(utf8_strlen(buffaddr, buffsize) < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", "Buffer doesn't contain valid UTF-8");
|
||||
|
||||
Object *temp = Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error);
|
||||
|
||||
if(temp == NULL)
|
||||
@@ -80,7 +101,8 @@ static int bin_toString(Runtime *runtime, Object **argv, unsigned int argc, Obje
|
||||
}
|
||||
|
||||
StaticMapSlot bins_buffer[] = {
|
||||
{ "new", SM_FUNCT, .as_funct = bin_new, .argc = 1 },
|
||||
{ "new", SM_FUNCT, .as_funct = bin_new, .argc = 1 },
|
||||
{ "sliceUp", SM_FUNCT, .as_funct = bin_sliceUp, .argc = 3 },
|
||||
{ "toString", SM_FUNCT, .as_funct = bin_toString, .argc = 1 },
|
||||
{ "toString", SM_FUNCT, .as_funct = bin_toString, .argc = 1 },
|
||||
{ "fromString", SM_FUNCT, .as_funct = bin_fromString, .argc = 1 },
|
||||
};
|
||||
|
||||
+55
-148
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include "files.h"
|
||||
#include "utils.h"
|
||||
#include "../utils/defs.h"
|
||||
|
||||
enum {
|
||||
@@ -38,30 +39,19 @@ enum {
|
||||
MD_APPEND = 2,
|
||||
};
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
static int bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
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 -1;
|
||||
}
|
||||
|
||||
if(!Object_IsInt(argv[1]))
|
||||
{
|
||||
Error_Report(error, 0, "Expected second argument to be an int, but it's a %s", Object_GetName(argv[1]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
|
||||
int mode = Object_GetInt(argv[1]);
|
||||
const char *path = Object_GetString(argv[0], NULL);
|
||||
ASSERT(path != NULL); // We know argv[0] is a string.
|
||||
ParsedArgument pargs[2];
|
||||
if (!parseArgs(error, argv, argc, pargs, "si"))
|
||||
return -1;
|
||||
|
||||
const char *path = pargs[0].as_string.data;
|
||||
int mode = pargs[1].as_int;
|
||||
|
||||
FILE *fp;
|
||||
{
|
||||
@@ -91,39 +81,23 @@ static int bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, Obje
|
||||
fp = fopen(path, mode2);
|
||||
|
||||
if(fp == NULL) {
|
||||
|
||||
Object *o_none = Object_NewNone(heap, error);
|
||||
if(o_none == NULL)
|
||||
return -1;
|
||||
|
||||
const char *errdesc;
|
||||
switch(errno) {
|
||||
case EACCES: errdesc = "Can't access file"; break;
|
||||
case EPERM: errdesc = "Permission denied"; break;
|
||||
case EEXIST: errdesc = "File or folder already exists"; break;
|
||||
case EISDIR: errdesc = "Entity is a directory"; break;
|
||||
case EACCES: errdesc = "Can't access file"; break;
|
||||
case EPERM: errdesc = "Permission denied"; break;
|
||||
case EEXIST: errdesc = "File or folder already exists"; break;
|
||||
case EISDIR: errdesc = "Entity is a directory"; break;
|
||||
case ENOTDIR: errdesc = "Entity is not a directory"; break;
|
||||
case ELOOP: errdesc = "Too many symbolic links"; break;
|
||||
case ELOOP: errdesc = "Too many symbolic links"; break;
|
||||
case ENAMETOOLONG: errdesc = "Entity name is too long"; break;
|
||||
case ENFILE: errdesc = "Open descriptors limit reached"; break;
|
||||
case ENOENT: errdesc = "File or folder doesn't exist"; break;
|
||||
default: errdesc = "Unexpected error"; break;
|
||||
case ENFILE: errdesc = "Open descriptors limit reached"; break;
|
||||
case ENOENT: errdesc = "File or folder doesn't exist"; break;
|
||||
default: errdesc = "Unexpected error"; break;
|
||||
}
|
||||
|
||||
Object *o_error = Object_FromString(errdesc, -1, heap, error);
|
||||
if(o_error == NULL)
|
||||
return -1;
|
||||
|
||||
rets[0] = o_none;
|
||||
rets[1] = o_error;
|
||||
return 2;
|
||||
return returnValues(error, heap, rets, "ns", errdesc);
|
||||
}
|
||||
}
|
||||
|
||||
rets[0] = Object_FromStream(fp, heap, error);
|
||||
if(rets[0] == NULL)
|
||||
return -1;
|
||||
return 1;
|
||||
return returnValues(error, heap, rets, "F", fp);
|
||||
}
|
||||
|
||||
static int bin_read(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
@@ -135,62 +109,31 @@ static int bin_read(Runtime *runtime, Object **argv, unsigned int argc, Object *
|
||||
// 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]));
|
||||
ParsedArgument pargs[3];
|
||||
if (!parseArgs(error, argv, argc, pargs, "FB?i"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!Object_IsBuffer(argv[1]))
|
||||
{
|
||||
Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1]));
|
||||
return -1;
|
||||
}
|
||||
FILE *stream;
|
||||
void *dstptr;
|
||||
size_t dstlen;
|
||||
size_t count;
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
|
||||
void *buff_addr;
|
||||
size_t buff_size;
|
||||
|
||||
buff_addr = Object_GetBuffer(argv[1], &buff_size);
|
||||
|
||||
size_t read_size;
|
||||
|
||||
if(Object_IsNone(argv[2]))
|
||||
{
|
||||
read_size = buff_size;
|
||||
}
|
||||
else if(Object_IsInt(argv[2]))
|
||||
{
|
||||
long long int temp = Object_GetInt(argv[2]);
|
||||
if(temp < 0)
|
||||
{
|
||||
Error_Report(error, 0, "Expected third argument to be a positive integer");
|
||||
stream = pargs[0].as_file;
|
||||
dstptr = pargs[1].as_buffer.data;
|
||||
dstlen = pargs[1].as_buffer.size;
|
||||
if (pargs[2].defined) {
|
||||
int n = pargs[2].as_int;
|
||||
if (n < 0) {
|
||||
Error_Report(error, 0, "Argument count must be a non-negative integer");
|
||||
return -1;
|
||||
}
|
||||
count = MIN((size_t) n, dstlen);
|
||||
} else
|
||||
count = (size_t) dstlen;
|
||||
|
||||
read_size = (size_t) 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 -1;
|
||||
}
|
||||
|
||||
FILE *fp = Object_GetStream(argv[0]);
|
||||
size_t n = fread(dstptr, 1, count, stream);
|
||||
|
||||
if(fp == NULL)
|
||||
return -1;
|
||||
|
||||
size_t n = fread(buff_addr, 1, read_size, fp);
|
||||
|
||||
rets[0] = Object_FromInt(n, heap, error);
|
||||
if(rets[0] == NULL)
|
||||
return -1;
|
||||
return 1;
|
||||
return returnValues2(error, runtime, rets, "i", n);
|
||||
}
|
||||
|
||||
static int bin_write(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
@@ -202,62 +145,31 @@ static int bin_write(Runtime *runtime, Object **argv, unsigned int argc, Object
|
||||
// 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]));
|
||||
ParsedArgument pargs[3];
|
||||
if (!parseArgs(error, argv, argc, pargs, "FB?i"))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!Object_IsBuffer(argv[1]))
|
||||
{
|
||||
Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1]));
|
||||
return -1;
|
||||
}
|
||||
FILE *stream;
|
||||
void *srcptr;
|
||||
size_t srclen;
|
||||
size_t count;
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
|
||||
void *buff_addr;
|
||||
size_t buff_size;
|
||||
|
||||
buff_addr = Object_GetBuffer(argv[1], &buff_size);
|
||||
|
||||
size_t write_size;
|
||||
|
||||
if(Object_IsNone(argv[2]))
|
||||
{
|
||||
write_size = buff_size;
|
||||
}
|
||||
else if(Object_IsInt(argv[2]))
|
||||
{
|
||||
long long int temp = Object_GetInt(argv[2]);
|
||||
if(temp < 0)
|
||||
{
|
||||
Error_Report(error, 0, "Expected third argument to be a positive integer");
|
||||
stream = pargs[0].as_file;
|
||||
srcptr = pargs[1].as_buffer.data;
|
||||
srclen = pargs[1].as_buffer.size;
|
||||
if (pargs[2].defined) {
|
||||
int n = pargs[2].as_int;
|
||||
if (n < 0) {
|
||||
Error_Report(error, 0, "Argument count must be a non-negative integer");
|
||||
return -1;
|
||||
}
|
||||
count = MIN((size_t) n, srclen);
|
||||
} else
|
||||
count = (int) srclen;
|
||||
|
||||
write_size = (size_t) temp; // TODO: Handle potential overflow.
|
||||
size_t n = fwrite(srcptr, 1, count, stream);
|
||||
|
||||
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 -1;
|
||||
}
|
||||
|
||||
FILE *fp = Object_GetStream(argv[0]);
|
||||
|
||||
if(fp == NULL)
|
||||
return -1;
|
||||
|
||||
size_t n = fwrite(buff_addr, 1, write_size, fp);
|
||||
|
||||
rets[0] = Object_FromInt(n, heap, error);
|
||||
if(rets[0] == NULL)
|
||||
return -1;
|
||||
return 1;
|
||||
return returnValues2(error, runtime, rets, "i", n);
|
||||
}
|
||||
|
||||
static int bin_openDir(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
@@ -310,9 +222,7 @@ static int bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int argc, O
|
||||
|
||||
DIR *dir = Object_GetDIR(argv[0]);
|
||||
ASSERT(dir != NULL);
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
|
||||
|
||||
errno = 0;
|
||||
|
||||
struct dirent *ent = readdir(dir);
|
||||
@@ -327,10 +237,7 @@ static int bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int argc, O
|
||||
return -1;
|
||||
}
|
||||
|
||||
rets[0] = Object_FromString(ent->d_name, -1, heap, error);
|
||||
if(rets[0] == NULL)
|
||||
return -1;
|
||||
return 1;
|
||||
return returnValues2(error, runtime, rets, "s", ent->d_name);
|
||||
}
|
||||
|
||||
StaticMapSlot bins_files[] = {
|
||||
|
||||
+42
-2
@@ -81,8 +81,6 @@
|
||||
return 1; \
|
||||
}
|
||||
|
||||
WRAP_FUNC(ceil)
|
||||
WRAP_FUNC(floor)
|
||||
WRAP_FUNC(sin)
|
||||
WRAP_FUNC(cos)
|
||||
WRAP_FUNC(tan)
|
||||
@@ -96,6 +94,48 @@ WRAP_FUNC(sqrt)
|
||||
WRAP_FUNC_2(atan2)
|
||||
WRAP_FUNC_2(pow)
|
||||
|
||||
static int bin_ceil(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) \
|
||||
{
|
||||
UNUSED(argc);
|
||||
ASSERT(argc == 1);
|
||||
|
||||
if(Object_IsFloat(argv[0]))
|
||||
{
|
||||
double v = Object_GetFloat(argv[0]);
|
||||
|
||||
rets[0] = Object_FromInt(ceil(v), Runtime_GetHeap(runtime), error);
|
||||
if(rets[0] == NULL)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int bin_floor(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) \
|
||||
{
|
||||
UNUSED(argc);
|
||||
ASSERT(argc == 1);
|
||||
|
||||
if(Object_IsFloat(argv[0]))
|
||||
{
|
||||
double v = Object_GetFloat(argv[0]);
|
||||
|
||||
rets[0] = Object_FromInt(floor(v), Runtime_GetHeap(runtime), error);
|
||||
if(rets[0] == NULL)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
StaticMapSlot bins_math[] = {
|
||||
{ "PI", SM_FLOAT, .as_float = M_PI },
|
||||
{ "E", SM_FLOAT, .as_float = M_E },
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "net.h"
|
||||
#include "utils.h"
|
||||
#include "../utils/defs.h"
|
||||
|
||||
static int bin_socket(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
ASSERT(argc == 3);
|
||||
ParsedArgument pargs[3];
|
||||
if (!parseArgs(error, argv, argc, pargs, "iii"))
|
||||
return -1;
|
||||
|
||||
int domain = pargs[0].as_int;
|
||||
int type = pargs[1].as_int;
|
||||
int proto = pargs[2].as_int;
|
||||
|
||||
int fd = socket(domain, type, proto);
|
||||
|
||||
if (fd < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", strerror(errno));
|
||||
return returnValues2(error, runtime, rets, "i", fd);
|
||||
}
|
||||
|
||||
static int bin_bind(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: fd
|
||||
// 1: family
|
||||
// 2: port (family=AF_INET)
|
||||
// 3: addr (family=AF_INET)
|
||||
|
||||
ASSERT(argc == 4);
|
||||
ParsedArgument pargs[4];
|
||||
if (!parseArgs(error, argv, argc, pargs, "iii?s"))
|
||||
return -1;
|
||||
|
||||
int fd = pargs[0].as_int;
|
||||
int family = pargs[1].as_int;
|
||||
|
||||
if (family != AF_INET)
|
||||
return returnValues2(error, runtime, rets, "ns", "Invalid family (only AF_INET is supported at the moment)");
|
||||
|
||||
int port = pargs[2].as_int;
|
||||
const char *addr = pargs[3].defined ? pargs[3].as_string.data : NULL;
|
||||
|
||||
struct in_addr parsed_addr;
|
||||
if (addr == NULL)
|
||||
parsed_addr.s_addr = INADDR_ANY;
|
||||
else {
|
||||
int res = inet_pton(family, addr, &parsed_addr);
|
||||
if (res == 0) return returnValues2(error, runtime, rets, "ns", "Invalid address");
|
||||
if (res < 0) return returnValues2(error, runtime, rets, "ns", "Invalid family");
|
||||
}
|
||||
|
||||
struct sockaddr_in buff;
|
||||
buff.sin_family = family;
|
||||
buff.sin_port = htons(port);
|
||||
buff.sin_addr = parsed_addr;
|
||||
if (bind(fd, (struct sockaddr*) &buff, sizeof(buff)) < 0)
|
||||
return returnValues2(error, runtime, rets, "s", strerror(errno));
|
||||
|
||||
return returnValues2(error, runtime, rets, "n");
|
||||
}
|
||||
|
||||
static int bin_listen(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: fd
|
||||
// 1: backlog
|
||||
|
||||
ASSERT(argc == 2);
|
||||
ParsedArgument pargs[2];
|
||||
if (!parseArgs(error, argv, argc, pargs, "ii"))
|
||||
return -1;
|
||||
|
||||
int fd = pargs[0].as_int;
|
||||
int backlog = pargs[1].as_int;
|
||||
|
||||
if (listen(fd, backlog) < 0)
|
||||
return returnValues2(error, runtime, rets, "s", strerror(errno));
|
||||
return returnValues2(error, runtime, rets, "n");
|
||||
}
|
||||
|
||||
static int bin_recv(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: fd
|
||||
// 1: buffer
|
||||
// 2: count
|
||||
|
||||
ASSERT(argc == 3);
|
||||
ParsedArgument pargs[3];
|
||||
if (!parseArgs(error, argv, argc, pargs, "iB?i"))
|
||||
return -1;
|
||||
|
||||
int fd = pargs[0].as_int;
|
||||
void *dstptr = pargs[1].as_buffer.data;
|
||||
size_t dstlen = pargs[1].as_buffer.size;
|
||||
|
||||
size_t count;
|
||||
if (pargs[2].defined) {
|
||||
int n = pargs[2].as_int;
|
||||
if (n < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", "Invalid negative count");
|
||||
count = MIN((size_t) n, dstlen);
|
||||
} else
|
||||
count = dstlen;
|
||||
|
||||
ssize_t res = recv(fd, dstptr, count, 0);
|
||||
if (res < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", strerror(errno));
|
||||
return returnValues2(error, runtime, rets, "i", res);
|
||||
}
|
||||
|
||||
static int bin_send(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: fd
|
||||
// 1: buffer
|
||||
// 2: count
|
||||
|
||||
ASSERT(argc == 3);
|
||||
ParsedArgument pargs[3];
|
||||
if (!parseArgs(error, argv, argc, pargs, "iB?i"))
|
||||
return -1;
|
||||
|
||||
int fd = pargs[0].as_int;
|
||||
void *srcptr = pargs[1].as_buffer.data;
|
||||
size_t srclen = pargs[1].as_buffer.size;
|
||||
|
||||
size_t count;
|
||||
if (pargs[2].defined) {
|
||||
int n = pargs[2].as_int;
|
||||
if (n < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", "Invalid negative count");
|
||||
count = MIN((size_t) n, srclen);
|
||||
} else
|
||||
count = srclen;
|
||||
|
||||
ssize_t res = send(fd, srcptr, count, 0);
|
||||
if (res < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", strerror(errno));
|
||||
return returnValues2(error, runtime, rets, "i", res);
|
||||
}
|
||||
|
||||
static int bin_accept(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: fd
|
||||
|
||||
ASSERT(argc == 1);
|
||||
ParsedArgument pargs[1];
|
||||
if (!parseArgs(error, argv, argc, pargs, "i"))
|
||||
return -1;
|
||||
|
||||
int fd = pargs[0].as_int;
|
||||
|
||||
struct sockaddr_in new_addr;
|
||||
socklen_t new_addr_size;
|
||||
int new_fd = accept(fd, (struct sockaddr*) &new_addr, &new_addr_size);
|
||||
if (new_fd < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", strerror(errno));
|
||||
ASSERT(new_addr.sin_family == AF_INET);
|
||||
ASSERT(new_addr_size == sizeof(struct sockaddr_in));
|
||||
|
||||
return returnValues2(error, runtime, rets, "iii", new_fd, new_addr.sin_addr.s_addr, new_addr.sin_port);
|
||||
}
|
||||
|
||||
|
||||
static int bin_close(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: fd
|
||||
|
||||
ASSERT(argc == 1);
|
||||
ParsedArgument pargs[1];
|
||||
if (!parseArgs(error, argv, argc, pargs, "i"))
|
||||
return -1;
|
||||
|
||||
int fd = pargs[0].as_int;
|
||||
int res = close(fd);
|
||||
return returnValues2(error, runtime, rets, "i", res);
|
||||
}
|
||||
|
||||
StaticMapSlot bins_net[] = {
|
||||
{ "AF_INET", SM_INT, .as_int = AF_INET, },
|
||||
{ "SOCK_STREAM", SM_INT, .as_int = SOCK_STREAM, },
|
||||
{ "SOCK_DGRAM", SM_INT, .as_int = SOCK_DGRAM, },
|
||||
{ "socket", SM_FUNCT, .as_funct = bin_socket, .argc = 3, },
|
||||
{ "bind", SM_FUNCT, .as_funct = bin_bind, .argc = 4, },
|
||||
{ "listen", SM_FUNCT, .as_funct = bin_listen, .argc = 2, },
|
||||
{ "accept", SM_FUNCT, .as_funct = bin_accept, .argc = 1, },
|
||||
{ "recv", SM_FUNCT, .as_funct = bin_recv, .argc = 3, },
|
||||
{ "send", SM_FUNCT, .as_funct = bin_send, .argc = 3, },
|
||||
{ "close", SM_FUNCT, .as_funct = bin_close, .argc = 1, },
|
||||
{ NULL, SM_END, {}, {} },
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../runtime/runtime.h"
|
||||
extern StaticMapSlot bins_net[];
|
||||
+168
-40
@@ -1,53 +1,41 @@
|
||||
|
||||
fun abs(n: Numeric) {
|
||||
if n < 0:
|
||||
return -n;
|
||||
return n;
|
||||
}
|
||||
fun dummy() {}
|
||||
|
||||
fun min(x, y) {
|
||||
if x < y:
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
fun max(x, y) {
|
||||
if x > y:
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
Func = type(abs);
|
||||
Func = type(dummy);
|
||||
NFunc = type(print);
|
||||
Numeric = int | float;
|
||||
Callable = Func | NFunc;
|
||||
Collection = List | Map;
|
||||
|
||||
chr = string.chr;
|
||||
ord = string.ord;
|
||||
cat = string.cat;
|
||||
|
||||
# Stringify a number between 0 and 9.
|
||||
fun stringFromDigit(digit: int) {
|
||||
assert(digit >= 0 and digit <= 9);
|
||||
return string.chr(string.ord("0") + digit);
|
||||
return chr(ord("0") + digit);
|
||||
}
|
||||
|
||||
# This function returns the magnitude of the
|
||||
# argument and the power of 10 with the same
|
||||
# magnitude.
|
||||
fun getIntegerMagnitude(n: int) {
|
||||
assert(n >= 0);
|
||||
magn = 0;
|
||||
powr = 1;
|
||||
# Basically grow the power until it's
|
||||
# bigger than the input.
|
||||
while n >= powr * 10: {
|
||||
powr = 10 * powr;
|
||||
magn = 1 + magn;
|
||||
}
|
||||
return magn, powr;
|
||||
}
|
||||
|
||||
# Stringify an unsigned integer
|
||||
fun stringFromInteger(n: int) {
|
||||
|
||||
# This function returns the magnitude of the
|
||||
# argument and the power of 10 with the same
|
||||
# magnitude.
|
||||
fun getIntegerMagnitude(n: int) {
|
||||
assert(n >= 0);
|
||||
magn = 0;
|
||||
powr = 1;
|
||||
# Basically grow the power until it's
|
||||
# bigger than the input.
|
||||
while n >= powr * 10: {
|
||||
powr = 10 * powr;
|
||||
magn = 1 + magn;
|
||||
}
|
||||
return magn, powr;
|
||||
}
|
||||
|
||||
negative = (n < 0);
|
||||
|
||||
# Get the power of 10 with the
|
||||
@@ -63,27 +51,167 @@ fun stringFromInteger(n: int) {
|
||||
temp = temp % power; # Remove it
|
||||
|
||||
# Add the digit to the output.
|
||||
text = string.cat(text, stringFromDigit(digit));
|
||||
text = cat(text, stringFromDigit(digit));
|
||||
|
||||
# Prep for the next iteration.
|
||||
power = power / 10;
|
||||
}
|
||||
|
||||
if negative:
|
||||
text = string.cat("-", text);
|
||||
text = cat("-", text);
|
||||
return text;
|
||||
}
|
||||
|
||||
fun stringFromFloating(f: float, max_decimals: int = 2) {
|
||||
# This function is just a fast hack
|
||||
epsilon = 0.00000001;
|
||||
asint = math.floor(f);
|
||||
text = stringFromInteger(asint);
|
||||
text = cat(text, ".");
|
||||
magn = 1.0;
|
||||
temp = f - asint;
|
||||
i = 0;
|
||||
do {
|
||||
magn = magn / 10;
|
||||
digit = math.floor(temp / magn);
|
||||
text = cat(text, stringFromDigit(digit));
|
||||
temp = temp - magn * digit; # Remove the handled digit
|
||||
i = i+1;
|
||||
} while temp > epsilon and i < max_decimals;
|
||||
return text;
|
||||
}
|
||||
|
||||
fun stringFromNumeric(num: Numeric) {
|
||||
if type(num) == int:
|
||||
return stringFromInteger(num);
|
||||
return stringFromFloating(num);
|
||||
}
|
||||
|
||||
fun floatFromInteger(n: int)
|
||||
return 1.0 * n;
|
||||
|
||||
fun stringFromList(list: List) {
|
||||
|
||||
s = "[";
|
||||
i = 0;
|
||||
while i < count(list): {
|
||||
s = cat(s, toString(list[i]));
|
||||
i = i+1;
|
||||
if i < count(list):
|
||||
s = cat(s, ", ");
|
||||
}
|
||||
s = cat(s, "]");
|
||||
return s;
|
||||
}
|
||||
|
||||
fun stringFromMap(map: Map, can_use_method=true) {
|
||||
s = none; # Result
|
||||
has_method = istypeof(Callable, map.toString);
|
||||
if can_use_method and has_method:
|
||||
s = map->toString();
|
||||
else {
|
||||
s = "{";
|
||||
i = 0;
|
||||
keys = keysof(map);
|
||||
while i < count(keys): {
|
||||
s = cat(s, toString(keys[i]), ": ", toString(map[keys[i]]));
|
||||
i = i+1;
|
||||
if i < count(keys):
|
||||
s = cat(s, ", ");
|
||||
}
|
||||
s = cat(s, "}");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
fun integerFromDigit(char: String) {
|
||||
ord = string.ord;
|
||||
res = ord(char) - ord('0');
|
||||
if res < 0 or res > 9:
|
||||
error("String isn't a digit");
|
||||
return res;
|
||||
}
|
||||
|
||||
fun append(array: List, item)
|
||||
array[count(array)] = item;
|
||||
fun GenericIterator(T) return {
|
||||
set : T,
|
||||
keys : List,
|
||||
index: ?int,
|
||||
next : Callable
|
||||
};
|
||||
|
||||
fun makeGenericIterator(set: Collection) return {
|
||||
set : set,
|
||||
keys : keysof(set),
|
||||
index: none,
|
||||
fun next(iter: GenericIterator(type(set))) {
|
||||
|
||||
index = iter.index;
|
||||
|
||||
if index == none:
|
||||
index = 0;
|
||||
else {
|
||||
if index < count(iter.keys):
|
||||
index = index+1;
|
||||
}
|
||||
|
||||
if index == count(iter.keys):
|
||||
return none;
|
||||
|
||||
iter.index = index;
|
||||
key = iter.keys[index];
|
||||
val = iter.set[key];
|
||||
return val, key, index;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
Func: Func,
|
||||
NFunc: NFunc,
|
||||
Numeric: Numeric,
|
||||
Callable: Callable,
|
||||
Collection: Collection,
|
||||
|
||||
fun makeIterator(set: Collection, can_use_method=true) {
|
||||
if can_use_method and type(set) == Map and istypeof(Callable, set.iter):
|
||||
return set->iter();
|
||||
return makeGenericIterator(set);
|
||||
}
|
||||
|
||||
fun toString(value, can_use_method=true) {
|
||||
T = type(value);
|
||||
if T == None : return "none";
|
||||
if T == int : return stringFromInteger(value);
|
||||
if T == float: return stringFromFloating(value);
|
||||
if T == List : return stringFromList(value);
|
||||
if T == Map : return stringFromMap(value, can_use_method);
|
||||
if T == Type : return typename(T);
|
||||
if T == Func : return "Func";
|
||||
if T == NFunc: return "NFunc";
|
||||
if T == String: return value;
|
||||
error(cat("Don't know how to convert ", typename(value), " to a string"));
|
||||
}
|
||||
|
||||
fun isCallable(x)
|
||||
return istypeof(Callable, x);
|
||||
|
||||
fun append(array: List, item)
|
||||
array[count(array)] = item;
|
||||
|
||||
fun abs(n: Numeric) {
|
||||
if n < 0:
|
||||
return -n;
|
||||
return n;
|
||||
}
|
||||
|
||||
fun min(x, y) {
|
||||
if x < y:
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
fun max(x, y) {
|
||||
if x > y:
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#include "utils.h"
|
||||
|
||||
int returnValuesVA(Error *error, Heap *heap, Object *rets[static MAX_RETS], const char *fmt, va_list va)
|
||||
{
|
||||
int retc = 0, i = 0;
|
||||
while (fmt[i] != '\0') {
|
||||
|
||||
if (retc == MAX_RETS) {
|
||||
Error_Report(error, 1, "Return value limit reached");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Object *ret;
|
||||
switch (fmt[i]) {
|
||||
case 'o': ret = va_arg(va, Object*); break;
|
||||
case 'n': ret = Object_NewNone(heap, error); break;
|
||||
case 'i': ret = Object_FromInt (va_arg(va, int), heap, error); break;
|
||||
case 'f': ret = Object_FromFloat(va_arg(va, double), heap, error); break;
|
||||
case 's': ret = Object_FromString(va_arg(va, char*), -1, heap, error); break;
|
||||
default:
|
||||
Error_Report(error, 1, "Invalid format specifier '%c'", fmt[i]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == NULL)
|
||||
return -1;
|
||||
|
||||
rets[retc++] = ret;
|
||||
i++;
|
||||
}
|
||||
return retc;
|
||||
}
|
||||
|
||||
bool parseArgs(Error *error,
|
||||
Object **argv,
|
||||
unsigned int argc,
|
||||
ParsedArgument *pargs,
|
||||
const char *fmt)
|
||||
{
|
||||
unsigned int current_arg = 0;
|
||||
int i = 0;
|
||||
while (fmt[i] != '\0') {
|
||||
|
||||
if (current_arg == argc) {
|
||||
Error_Report(error, 0, "Missing arguments");
|
||||
return false;
|
||||
}
|
||||
Object *arg = argv[current_arg];
|
||||
|
||||
bool may_be_none = false;
|
||||
if (fmt[i] == '?') {
|
||||
may_be_none = true;
|
||||
i++;
|
||||
if (fmt[i] == '\0') {
|
||||
Error_Report(error, 1, "Format terminated unexpectedly");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (may_be_none && Object_IsNone(arg)) {
|
||||
pargs[current_arg].defined = false;
|
||||
} else {
|
||||
switch (fmt[i]) {
|
||||
|
||||
case 'o': /* Any object */
|
||||
pargs[current_arg].defined = true;
|
||||
break;
|
||||
|
||||
case 'b': /* Boolean */
|
||||
if (!Object_IsBool(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be bool, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
pargs[current_arg].defined = true;
|
||||
pargs[current_arg].as_bool = Object_GetBool(arg);
|
||||
break;
|
||||
|
||||
case 'B': /* Buffer */
|
||||
{
|
||||
if (!Object_IsBuffer(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be a buffer, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
void *data;
|
||||
size_t size;
|
||||
data = Object_GetBuffer(arg, &size);
|
||||
pargs[current_arg].defined = true;
|
||||
pargs[current_arg].as_buffer.data = data;
|
||||
pargs[current_arg].as_buffer.size = size;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'i': /* Integer */
|
||||
if (!Object_IsInt(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be an int, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
pargs[current_arg].defined = true;
|
||||
pargs[current_arg].as_int = Object_GetInt(arg);
|
||||
break;
|
||||
|
||||
case 'f': /* Float */
|
||||
if (!Object_IsFloat(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be a float, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
pargs[current_arg].defined = true;
|
||||
pargs[current_arg].as_float = Object_GetFloat(arg);
|
||||
break;
|
||||
|
||||
case 'l': /* List */
|
||||
if (!Object_IsList(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be a list, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
pargs[current_arg].defined = true;
|
||||
break;
|
||||
|
||||
case 'm': /* Map */
|
||||
if (!Object_IsMap(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be a map, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's': /* String */
|
||||
{
|
||||
if (!Object_IsString(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be a string, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
const void *data;
|
||||
size_t size;
|
||||
data = Object_GetString(arg, &size);
|
||||
pargs[current_arg].defined = true;
|
||||
pargs[current_arg].as_string.data = data;
|
||||
pargs[current_arg].as_string.size = size;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Error_Report(error, 1, "Invalid argument parser format specifier");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
current_arg++;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (current_arg < argc) {
|
||||
// Ignoring part of the format string
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int returnValues2(Error *error, Runtime *runtime, Object *rets[static MAX_RETS], const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
int retc = returnValuesVA(error, Runtime_GetHeap(runtime), rets, fmt, va);
|
||||
va_end(va);
|
||||
return retc;
|
||||
}
|
||||
|
||||
int returnValues(Error *error, Heap *heap, Object *rets[static MAX_RETS], const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
int retc = returnValuesVA(error, heap, rets, fmt, va);
|
||||
va_end(va);
|
||||
return retc;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "../utils/error.h"
|
||||
#include "../objects/objects.h"
|
||||
#include "../runtime/runtime.h"
|
||||
|
||||
typedef struct {
|
||||
bool defined;
|
||||
union {
|
||||
struct {
|
||||
const char *data;
|
||||
size_t size;
|
||||
} as_string;
|
||||
struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
} as_buffer;
|
||||
bool as_bool;
|
||||
int64_t as_int;
|
||||
double as_float;
|
||||
FILE *as_file;
|
||||
};
|
||||
} ParsedArgument;
|
||||
|
||||
bool parseArgs(Error *error, Object **argv, unsigned int argc, ParsedArgument *pargs, const char *fmt);
|
||||
int returnValues (Error *error, Heap *heap, Object *rets[static MAX_RETS], const char *fmt, ...);
|
||||
int returnValues2(Error *error, Runtime *runtime, Object *rets[static MAX_RETS], const char *fmt, ...);
|
||||
@@ -76,6 +76,18 @@ _Bool Object_IsBuffer(Object *obj)
|
||||
return Object_GetType(obj) == Object_GetBufferType();
|
||||
}
|
||||
|
||||
Object *Object_NewBufferFromString(const char *str, size_t len, Heap *heap, Error *error)
|
||||
{
|
||||
Object *buffer = Object_NewBuffer(len, heap, error);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
void *ptr = Object_GetBuffer(buffer, NULL);
|
||||
memcpy(ptr, str, len);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Object *Object_NewBuffer(size_t size, Heap *heap, Error *error)
|
||||
{
|
||||
// Make the thing.
|
||||
|
||||
@@ -139,7 +139,7 @@ int Object_Call(Object *obj, Object **argv, unsigned int argc, Object *rets[stat
|
||||
|
||||
if(type->call == NULL)
|
||||
{
|
||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||
Error_Report(err, 0, "Object of type %s isn't callable", Object_GetName(obj), __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ Object* Object_NewList2(int num, Object **items, Heap *heap, Error *error);
|
||||
Object* Object_NewListOfConsecutiveIntegers(int first, int last, Heap *heap, Error *error);
|
||||
Object* Object_NewNone(Heap *heap, Error *error);
|
||||
Object* Object_NewBuffer(size_t size, Heap *heap, Error *error);
|
||||
Object* Object_NewBufferFromString(const char *str, size_t len, Heap *heap, Error *error);
|
||||
Object* Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error);
|
||||
Object* Object_SliceBuffer(Object *obj, size_t offset, size_t length, Heap *heap, Error *error);
|
||||
Object* Object_NewNullable(Object *item, Heap *heap, Error *error);
|
||||
|
||||
@@ -879,6 +879,7 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
|
||||
arg_index = ops[0].as_int;
|
||||
arg_name = ops[1].as_string;
|
||||
ASSERT(arg_name != NULL);
|
||||
|
||||
if(runtime->frame->used < 2)
|
||||
{
|
||||
|
||||
@@ -104,7 +104,7 @@ void _Error_Report2(Error *err, _Bool internal,
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(temp, p+1, fmt, va2);
|
||||
vsnprintf(temp, p+1, fmt, va2);
|
||||
err->truncated = 0;
|
||||
err->message = temp;
|
||||
err->length = p;
|
||||
|
||||
Reference in New Issue
Block a user