/* +--------------------------------------------------------------------------+ ** | _ _ _ | ** | | \ | | (_) | ** | | \| | ___ _ __ _ | ** | | . ` |/ _ \| |/ _` | | ** | | |\ | (_) | | (_| | | ** | |_| \_|\___/| |\__,_| | ** | _/ | | ** | |__/ | ** +--------------------------------------------------------------------------+ ** | Copyright (c) 2022 Francesco Cozzuto | ** +--------------------------------------------------------------------------+ ** | 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 . | ** +--------------------------------------------------------------------------+ */ #include #include #include #include #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, {}, {} }, };