advances of the http server example; built-ins for generating random numbers; built-ins for slicing, trimming and converting strings to integers
This commit is contained in:
@@ -39,12 +39,28 @@
|
||||
#include "files.h"
|
||||
#include "string.h"
|
||||
#include "buffer.h"
|
||||
#include "random.h"
|
||||
#include "../utils/defs.h"
|
||||
#include "../common/defs.h"
|
||||
#include "../objects/objects.h"
|
||||
#include "../runtime/runtime.h"
|
||||
#include "../compiler/compile.h"
|
||||
|
||||
static int bin_getCurrentWorkingDirectory(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
ASSERT(argc == 0);
|
||||
|
||||
char path[1024];
|
||||
if(getcwd(path, sizeof(path)) == NULL) {
|
||||
Error_Report(error, 1, "Couldn't get current working directory because a buffer is too small");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return returnValues2(error, runtime, rets, "s", path);
|
||||
}
|
||||
|
||||
static int bin_typename(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
@@ -335,6 +351,7 @@ StaticMapSlot bins_basic[] = {
|
||||
{ "files", SM_SMAP, .as_smap = bins_files, },
|
||||
{ "buffer", SM_SMAP, .as_smap = bins_buffer, },
|
||||
{ "string", SM_SMAP, .as_smap = bins_string, },
|
||||
{ "random", SM_SMAP, .as_smap = bins_random, },
|
||||
|
||||
{ "import", SM_FUNCT, .as_funct = bin_import, .argc = 1, },
|
||||
{ "type", SM_FUNCT, .as_funct = bin_type, .argc = 1 },
|
||||
@@ -346,5 +363,6 @@ StaticMapSlot bins_basic[] = {
|
||||
{ "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, },
|
||||
{ "getCurrentWorkingDirectory", SM_FUNCT, .as_funct = bin_getCurrentWorkingDirectory, .argc = 0 },
|
||||
{ NULL, SM_END, {}, {} },
|
||||
};
|
||||
|
||||
+13
-5
@@ -9,19 +9,27 @@
|
||||
|
||||
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"))
|
||||
ASSERT(argc == 4);
|
||||
ParsedArgument pargs[4];
|
||||
if (!parseArgs(error, argv, argc, pargs, "iii?b"))
|
||||
return -1;
|
||||
|
||||
int domain = pargs[0].as_int;
|
||||
int type = pargs[1].as_int;
|
||||
int proto = pargs[2].as_int;
|
||||
bool reuse = pargs[3].defined ? pargs[3].as_bool : false;
|
||||
|
||||
int fd = socket(domain, type, proto);
|
||||
|
||||
|
||||
if (fd < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", strerror(errno));
|
||||
|
||||
if (reuse) {
|
||||
int value = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0)
|
||||
return returnValues2(error, runtime, rets, "ns", strerror(errno));
|
||||
}
|
||||
|
||||
return returnValues2(error, runtime, rets, "i", fd);
|
||||
}
|
||||
|
||||
@@ -184,7 +192,7 @@ 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, },
|
||||
{ "socket", SM_FUNCT, .as_funct = bin_socket, .argc = 4, },
|
||||
{ "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, },
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <stdlib.h>
|
||||
#include "utils.h"
|
||||
#include "random.h"
|
||||
#include "../utils/defs.h"
|
||||
|
||||
static int bin_seed(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
ASSERT(argc == 1);
|
||||
|
||||
ParsedArgument pargs[1];
|
||||
if (!parseArgs(error, argv, argc, pargs, "i"))
|
||||
return -1;
|
||||
|
||||
int64_t seed = pargs[0].as_int;
|
||||
srand(seed);
|
||||
return returnValues2(error, runtime, rets, "n");
|
||||
}
|
||||
|
||||
static int bin_generate(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
ASSERT(argc == 2);
|
||||
|
||||
ParsedArgument pargs[2];
|
||||
if (!parseArgs(error, argv, argc, pargs, "?i?i"))
|
||||
return -1;
|
||||
|
||||
int64_t min, max;
|
||||
if (pargs[0].defined) min = pargs[0].as_int; else min = 0;
|
||||
if (pargs[1].defined) max = pargs[1].as_int; else max = INT64_MAX;
|
||||
int64_t value = min + (max - min) * (double) rand() / RAND_MAX;
|
||||
return returnValues2(error, runtime, rets, "i", value);
|
||||
}
|
||||
|
||||
StaticMapSlot bins_random[] = {
|
||||
{"seed", SM_FUNCT, .as_funct = bin_seed, .argc = 1},
|
||||
{"generate", SM_FUNCT, .as_funct = bin_generate, .argc = 2},
|
||||
{ NULL, SM_END, {}, {} },
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../runtime/runtime.h"
|
||||
extern StaticMapSlot bins_random[];
|
||||
+135
-3
@@ -1,6 +1,8 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "utils.h"
|
||||
#include "string.h"
|
||||
#include "../utils/defs.h"
|
||||
#include "../utils/utf8.h"
|
||||
@@ -135,8 +137,138 @@ static int bin_cat(Runtime *runtime, Object **argv, unsigned int argc, Object *r
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bin_slice(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: string
|
||||
// 1: start offset or none
|
||||
// 2: end offset or none
|
||||
|
||||
ParsedArgument pargs[3];
|
||||
if (!parseArgs(error, argv, argc, pargs, "s?i?i"))
|
||||
return -1;
|
||||
|
||||
const char *srcstr = pargs[0].as_string.data;
|
||||
size_t srclen = pargs[0].as_string.size;
|
||||
|
||||
size_t offset;
|
||||
size_t length;
|
||||
|
||||
if (pargs[1].defined) {
|
||||
int64_t n = pargs[1].as_int;
|
||||
if (n < 0) {
|
||||
Error_Report(error, 0, "starting offset of string slice must be non-negative");
|
||||
return -1;
|
||||
}
|
||||
offset = (size_t) n;
|
||||
} else
|
||||
offset = 0;
|
||||
|
||||
if (pargs[2].defined) {
|
||||
int64_t n = pargs[2].as_int;
|
||||
if (n < 0) {
|
||||
Error_Report(error, 0, "length of string slice must be non-negative");
|
||||
return -1;
|
||||
}
|
||||
length = (size_t) n;
|
||||
} else
|
||||
length = srclen - offset;
|
||||
|
||||
if (offset > srclen) {
|
||||
Error_Report(error, 0, "string slice offset is out of bounds");
|
||||
return -1;
|
||||
}
|
||||
if (offset + length > srclen) {
|
||||
Error_Report(error, 0, "string slice length is out of bounds");
|
||||
return -1;
|
||||
}
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
Object *slice = Object_FromString(srcstr + offset, length, heap, error);
|
||||
if (slice == NULL)
|
||||
return -1;
|
||||
rets[0] = slice;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bin_trim(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: string
|
||||
|
||||
ParsedArgument pargs[1];
|
||||
if (!parseArgs(error, argv, argc, pargs, "s"))
|
||||
return -1;
|
||||
|
||||
const char *srcstr = pargs[0].as_string.data;
|
||||
size_t srclen = pargs[0].as_string.size;
|
||||
|
||||
size_t offset = 0;
|
||||
size_t length = srclen;
|
||||
|
||||
while (offset < srclen && srcstr[offset] == ' ')
|
||||
offset++;
|
||||
|
||||
Heap *heap = Runtime_GetHeap(runtime);
|
||||
|
||||
Object *result;
|
||||
if (offset == srclen)
|
||||
// The string only contained whitespace.
|
||||
// Return an empty string.
|
||||
result = Object_FromString("", 0, heap, error);
|
||||
else {
|
||||
|
||||
// NOTE: The string doesn't contain only
|
||||
// whitespace, so the length can't
|
||||
// go under 1.
|
||||
while (srcstr[offset + length - 1] == ' ')
|
||||
length--;
|
||||
|
||||
result = Object_FromString(srcstr + offset, length, heap, error);
|
||||
}
|
||||
|
||||
if (result == NULL)
|
||||
return -1;
|
||||
rets[0] = result;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bin_toInt(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
||||
{
|
||||
// 0: string
|
||||
|
||||
ParsedArgument pargs[1];
|
||||
if (!parseArgs(error, argv, argc, pargs, "s"))
|
||||
return -1;
|
||||
|
||||
const char *srcstr = pargs[0].as_string.data;
|
||||
size_t srclen = pargs[0].as_string.size;
|
||||
|
||||
if (srclen == 0 || !isdigit(srcstr[0]))
|
||||
return returnValues2(error, runtime, rets, "ns", "String doesn't contain an integer");
|
||||
|
||||
int64_t result = 0;
|
||||
size_t i = 0;
|
||||
do {
|
||||
int digit = srcstr[i] - '0';
|
||||
if (result > (INT64_MAX - digit) / 10)
|
||||
return returnValues2(error, runtime, rets, "ns", "An overflow occurred");
|
||||
result = result * 10 + digit;
|
||||
i++;
|
||||
} while (i < srclen && isdigit(srcstr[i]));
|
||||
|
||||
if (i < srclen)
|
||||
// Found something other than a digit after the
|
||||
// sequence of digits, therefore the string can't
|
||||
// be considered an integer.
|
||||
return returnValues2(error, runtime, rets, "ns", "String doesn't contain an integer");
|
||||
|
||||
return returnValues2(error, runtime, rets, "i", result);
|
||||
}
|
||||
|
||||
StaticMapSlot bins_string[] = {
|
||||
{ "ord", SM_FUNCT, .as_funct = bin_ord, .argc = 1 },
|
||||
{ "chr", SM_FUNCT, .as_funct = bin_chr, .argc = 1 },
|
||||
{ "cat", SM_FUNCT, .as_funct = bin_cat, .argc = -1 },
|
||||
{ "ord", SM_FUNCT, .as_funct = bin_ord, .argc = 1 },
|
||||
{ "chr", SM_FUNCT, .as_funct = bin_chr, .argc = 1 },
|
||||
{ "cat", SM_FUNCT, .as_funct = bin_cat, .argc = -1 },
|
||||
{ "trim", SM_FUNCT, .as_funct = bin_trim, .argc = 1 },
|
||||
{ "slice", SM_FUNCT, .as_funct = bin_slice, .argc = 3 },
|
||||
{ "toInt", SM_FUNCT, .as_funct = bin_toInt, .argc = 1 },
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ int returnValuesVA(Error *error, Heap *heap, Object *rets[static MAX_RETS], cons
|
||||
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;
|
||||
case 'F': ret = Object_FromStream(va_arg(va, FILE*), heap, error); break;
|
||||
default:
|
||||
Error_Report(error, 1, "Invalid format specifier '%c'", fmt[i]);
|
||||
return -1;
|
||||
@@ -138,8 +139,17 @@ bool parseArgs(Error *error,
|
||||
break;
|
||||
}
|
||||
|
||||
case 'F': /* File */
|
||||
if (!Object_IsFile(arg)) {
|
||||
Error_Report(error, 0, "Argument %d was expected to be a file, but a %s was provided", current_arg+1, arg->type->name);
|
||||
return false;
|
||||
}
|
||||
pargs[current_arg].defined = true;
|
||||
pargs[current_arg].as_file = Object_GetStream(arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
Error_Report(error, 1, "Invalid argument parser format specifier");
|
||||
Error_Report(error, 1, "Invalid argument parser format specifier '%c'", fmt[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
||||
if(str[i] == '\\')
|
||||
{
|
||||
i += 1; // Consume the \.
|
||||
if(i < len && (str[i] == '\'' || str[i] == '"'))
|
||||
if(i < len && (str[i] == '\'' || str[i] == '"' || str[i] == '\\'))
|
||||
i += 1;
|
||||
}
|
||||
else break;
|
||||
|
||||
@@ -73,6 +73,7 @@ keysof(Object *self,
|
||||
Error *error)
|
||||
{
|
||||
MapObject *map = (MapObject*) self;
|
||||
#warning "This shouldn't return items that contain none"
|
||||
return Object_NewList2(map->count, map->keys, heap, error);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user