353 lines
11 KiB
C
353 lines
11 KiB
C
|
|
/* +--------------------------------------------------------------------------+
|
|
** | _ _ _ |
|
|
** | | \ | | (_) |
|
|
** | | \| | ___ _ __ _ |
|
|
** | | . ` |/ _ \| |/ _` | |
|
|
** | | |\ | (_) | | (_| | |
|
|
** | |_| \_|\___/| |\__,_| |
|
|
** | _/ | |
|
|
** | |__/ |
|
|
** +--------------------------------------------------------------------------+
|
|
** | Copyright (c) 2022 Francesco Cozzuto <francesco.cozzuto@gmail.com> |
|
|
** +--------------------------------------------------------------------------+
|
|
** | This file is part of The Noja Interpreter. |
|
|
** | |
|
|
** | The Noja Interpreter is free software: you can redistribute it and/or |
|
|
** | modify it under the terms of the GNU General Public License as published |
|
|
** | by the Free Software Foundation, either version 3 of the License, or (at |
|
|
** | your option) any later version. |
|
|
** | |
|
|
** | The Noja Interpreter is distributed in the hope that it will be useful, |
|
|
** | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
** | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
|
** | Public License for more details. |
|
|
** | |
|
|
** | You should have received a copy of the GNU General Public License along |
|
|
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
|
** +--------------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#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"
|
|
#include "buffer.h"
|
|
#include "random.h"
|
|
#include "../defs.h"
|
|
#include "../utils/defs.h"
|
|
#include "../objects/objects.h"
|
|
#include "../runtime.h"
|
|
#include "../run.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, ErrorType_INTERNAL, "Couldn't get current working directory because a buffer is too small");
|
|
return -1;
|
|
}
|
|
|
|
return returnValues2(error, runtime, rets, "s", path);
|
|
}
|
|
|
|
static int bin_getCurrentScriptDirectory(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(argv);
|
|
ASSERT(argc == 0);
|
|
const char *path = Runtime_GetCurrentScriptAbsolutePath(runtime);
|
|
if (path == NULL)
|
|
return returnValues2(error, runtime, rets, "n");
|
|
|
|
size_t len = strlen(path);
|
|
|
|
while (path[len-1] != '/') // This underflows if path has len 0 or doesn't contain a "/".
|
|
len--;
|
|
|
|
Object *obj = Object_FromString(path, len, Runtime_GetHeap(runtime), error);
|
|
if (obj == NULL)
|
|
return -1;
|
|
rets[0] = obj;
|
|
return 1;
|
|
}
|
|
|
|
static int bin_getCurrentScriptLocation(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(argv);
|
|
ASSERT(argc == 0);
|
|
const char *path = Runtime_GetCurrentScriptAbsolutePath(runtime);
|
|
if (path == NULL)
|
|
return returnValues2(error, runtime, rets, "n");
|
|
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);
|
|
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], Runtime_GetOutputStream(runtime));
|
|
return 0;
|
|
}
|
|
|
|
static int bin_import(Runtime *runtime,
|
|
Object **argv,
|
|
unsigned int argc,
|
|
Object *rets[static MAX_RETS],
|
|
Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
ASSERT(argc == 1);
|
|
|
|
ParsedArgument pargs[2];
|
|
if (!parseArgs(error, argv, argc, pargs, "s"))
|
|
return -1;
|
|
|
|
const char *path = pargs[0].as_string.data;
|
|
return runFileRelativeToScript(runtime, path, rets, error);
|
|
}
|
|
|
|
static int bin_type(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
ASSERT(argc == 1);
|
|
UNUSED(runtime);
|
|
UNUSED(error);
|
|
UNUSED(argc);
|
|
|
|
rets[0] = (Object*) argv[0]->type;
|
|
return 1;
|
|
}
|
|
|
|
static int bin_count(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
ASSERT(argc == 1);
|
|
|
|
int n = Object_Count(argv[0], error);
|
|
|
|
if(error->occurred)
|
|
return -1;
|
|
|
|
Object *temp = Object_FromInt(n, Runtime_GetHeap(runtime), error);
|
|
|
|
if(temp == NULL)
|
|
return -1;
|
|
|
|
rets[0] = temp;
|
|
return 1;
|
|
}
|
|
|
|
static int bin_input(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argv);
|
|
UNUSED(argc);
|
|
ASSERT(argc == 0);
|
|
|
|
char maybe[256];
|
|
char *str = maybe;
|
|
int size = 0, cap = sizeof(maybe)-1;
|
|
|
|
while(1)
|
|
{
|
|
char c = getc(Runtime_GetInputStream(runtime));
|
|
|
|
if(c == '\n')
|
|
break;
|
|
|
|
if(size == cap)
|
|
{
|
|
int newcap = cap*2;
|
|
char *tmp = realloc(str, newcap + 1);
|
|
|
|
if(tmp == NULL)
|
|
{
|
|
if(str != maybe) free(str);
|
|
Error_Report(error, ErrorType_INTERNAL, "No memory");
|
|
return -1;
|
|
}
|
|
|
|
str = tmp;
|
|
cap = newcap;
|
|
}
|
|
|
|
str[size++] = c;
|
|
}
|
|
|
|
str[size] = '\0';
|
|
|
|
Object *res = Object_FromString(str, size, Runtime_GetHeap(runtime), error);
|
|
|
|
if(str != maybe)
|
|
free(str);
|
|
|
|
if(res == NULL)
|
|
return -1;
|
|
|
|
rets[0] = res;
|
|
return 1;
|
|
}
|
|
|
|
static int bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(runtime);
|
|
UNUSED(rets);
|
|
|
|
for(unsigned int i = 0; i < argc; i += 1)
|
|
{
|
|
if(!Object_IsBool(argv[i]))
|
|
{
|
|
Error_Report(error, ErrorType_RUNTIME, "Argument %d isn't a boolean", i);
|
|
return -1;
|
|
}
|
|
|
|
if(!Object_GetBool(argv[i]))
|
|
{
|
|
Error_Report(error, ErrorType_RUNTIME, "Assertion failed");
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int bin_error(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(rets);
|
|
UNUSED(runtime);
|
|
|
|
ASSERT(argc == 1);
|
|
|
|
if(!Object_IsString(argv[0]))
|
|
{
|
|
Error_Report(error, ErrorType_RUNTIME, "Argument is not a string");
|
|
return -1;
|
|
}
|
|
|
|
size_t length;
|
|
const char *string;
|
|
|
|
string = Object_GetString(argv[0], &length);
|
|
ASSERT(string != NULL);
|
|
|
|
Error_Report(error, ErrorType_RUNTIME, "%s", string);
|
|
return -1;
|
|
}
|
|
|
|
static int bin_istypeof(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(rets);
|
|
UNUSED(runtime);
|
|
|
|
ASSERT(argc == 2);
|
|
|
|
Heap *heap = Runtime_GetHeap(runtime);
|
|
bool yes = Object_IsTypeOf(argv[0], argv[1], heap, error);
|
|
Object *o_yes = Object_FromBool(yes, heap, error);
|
|
if (o_yes == NULL)
|
|
return -1;
|
|
|
|
rets[0] = o_yes;
|
|
return 1;
|
|
}
|
|
|
|
static int bin_keysof(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(rets);
|
|
UNUSED(runtime);
|
|
ASSERT(argc == 1);
|
|
Heap *heap = Runtime_GetHeap(runtime);
|
|
Object *keys = Object_KeysOf(argv[0], heap, error);
|
|
if (keys == NULL)
|
|
return -1;
|
|
rets[0] = keys;
|
|
return 1;
|
|
}
|
|
|
|
void bins_basic_init(StaticMapSlot slots[])
|
|
{
|
|
slots[0].as_type = Object_GetTypeType();
|
|
slots[1].as_type = Object_GetNoneType();
|
|
slots[2].as_type = Object_GetIntType();
|
|
slots[3].as_type = Object_GetBoolType();
|
|
slots[4].as_type = Object_GetFloatType();
|
|
slots[5].as_type = Object_GetStringType();
|
|
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[] = {
|
|
{ TYPENAME_TYPE, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
|
{ TYPENAME_NONE, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
|
{ TYPENAME_INT, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
|
{ 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 */ },
|
|
{ TYPENAME_DIRECTORY, SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ },
|
|
{ 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, },
|
|
{ "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 },
|
|
{ "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 },
|
|
{ "input", SM_FUNCT, .as_funct = bin_input, .argc = 0 },
|
|
{ "count", SM_FUNCT, .as_funct = bin_count, .argc = 1 },
|
|
{ "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, },
|
|
{ "getCurrentWorkingDirectory", SM_FUNCT, .as_funct = bin_getCurrentWorkingDirectory, .argc = 0 },
|
|
{ "getCurrentScriptDirectory", SM_FUNCT, .as_funct = bin_getCurrentScriptDirectory, .argc = 0 },
|
|
{ "getCurrentScriptLocation", SM_FUNCT, .as_funct = bin_getCurrentScriptLocation, .argc = 0 },
|
|
{ NULL, SM_END, {}, {} },
|
|
};
|