diff --git a/examples/json/json.noja b/examples/json/json.noja index f002fee..79d2cd4 100644 --- a/examples/json/json.noja +++ b/examples/json/json.noja @@ -265,22 +265,4 @@ fun compareAny(A, B) { error("Maps aren't supported yet!"); return A == B; -} - -assert(compareAny(1, 2) == true); -assert(compareAny([], []) == true); -assert(compareAny([], [1]) == false); -assert(compareAny([1, 2, 3], [1, 2, 3]) == true); -assert(compareAny([1, 2, 3], [1, 2, 4]) == false); -assert(compareAny([1, 2, 3], [1, 2, 3, 4]) == false); - -assert(parse("null") == none); -assert(parse("true") == true); -assert(parse("false") == false); -assert(parse('"Hello, world!"') == "Hello, world!"); -assert(compareAny(parse('[]'), [])); -assert(compareAny(parse('[1, 2, 3]'), [1, 2, 3])); - -val, err = parse('[1, 2, 3]'); -print("val=[", val, "]\n"); -print("err=[", err, "]\n"); \ No newline at end of file +} \ No newline at end of file diff --git a/examples/json/test.noja b/examples/json/test.noja index e69de29..983cc71 100644 --- a/examples/json/test.noja +++ b/examples/json/test.noja @@ -0,0 +1,12 @@ + +json, err = import("json.noja"); +utils = import("utils.noja"); + +assert(json.parse("null") == none); +assert(json.parse("true") == true); +assert(json.parse("false") == false); +assert(json.parse('"Hello, world!"') == "Hello, world!"); +assert(utils.compareAny(json.parse('[]'), [])); +assert(utils.compareAny(json.parse('[1, 2, 3]'), [1, 2, 3])); + +print("No assertions fired!\n"); \ No newline at end of file diff --git a/examples/json/utils.noja b/examples/json/utils.noja new file mode 100644 index 0000000..8af29fd --- /dev/null +++ b/examples/json/utils.noja @@ -0,0 +1,37 @@ + +fun compareAny(A, B) { + + fun compareLists(A: List, B: List) { + n = count(A); + if n != count(B): + return false; + + i = 0; + while i < n: { + if not compareAny(A[i], B[i]): + return false; + i = i + 1; + } + return true; + } + + T = type(A); + + if T != type(B): + return false; + + if T == List: + return compareLists(A, B); + + if T == Map: + error("Maps aren't supported yet!"); + + return A == B; +} + +assert(compareAny(1, 2) == false); +assert(compareAny([], []) == true); +assert(compareAny([], [1]) == false); +assert(compareAny([1, 2, 3], [1, 2, 3]) == true); +assert(compareAny([1, 2, 3], [1, 2, 4]) == false); +assert(compareAny([1, 2, 3], [1, 2, 3, 4]) == false); diff --git a/src/lib/builtins/basic.c b/src/lib/builtins/basic.c index c7a5161..5aaf4aa 100644 --- a/src/lib/builtins/basic.c +++ b/src/lib/builtins/basic.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "math.h" #include "basic.h" #include "files.h" @@ -51,6 +52,61 @@ static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object return 0; } +static const char *getCurrentScriptAbsolutePath(Runtime *runtime) +{ + Executable *exe = Runtime_GetCurrentExecutable(runtime); + assert(exe != NULL); + + Source *src = Executable_GetSource(exe); + if(src == NULL) + return NULL; + + const char *path = Source_GetAbsolutePath(src); + if(path == NULL) + return NULL; + + assert(path[0] != '\0'); + return path; +} + +// Returns the length written in buff (not considering the zero byte) +static size_t getCurrentScriptFolder(Runtime *runtime, char *buff, size_t buffsize) +{ + const char *path = getCurrentScriptAbsolutePath(runtime); + if(path == NULL) { + if(getcwd(buff, sizeof(buffsize)) == NULL) + return 0; + return strlen(buff); + } + + size_t dir_len; + { + // This is buggy code!! + size_t path_len = strlen(path); + assert(path_len > 0); // Not empty + assert(path[0] == '/'); // Is absolute + assert(path[path_len-1] != '/'); // Doesn't end with a slash. + + size_t popped = 0; + while(path[path_len-1-popped] != '/') + popped += 1; + + assert(path_len > popped); + + dir_len = path_len - popped; + + assert(dir_len < path_len); + assert(path[dir_len-1] == '/'); + } + + if(dir_len >= buffsize) + return 0; + + memcpy(buff, path, dir_len); + buff[dir_len] = '\0'; + return dir_len; +} + static int bin_import(Runtime *runtime, Object **argv, unsigned int argc, Object **rets, unsigned int maxretc, Error *error) { assert(argc == 1); @@ -76,9 +132,33 @@ static int bin_import(Runtime *runtime, Object **argv, unsigned int argc, Object path_len = (size_t) n; } + char full_path[1024]; + + if(path[0] == '/') { + if(path_len >= sizeof(full_path)) { + Error_Report(error, 1, "Internal buffer is too small"); + return -1; + } + strcpy(full_path, path); + } else { + size_t written = getCurrentScriptFolder(runtime, full_path, sizeof(full_path)); + if(written == 0) { + Error_Report(error, 1, "Internal buffer is too small"); + return -1; + } + + if(written + path_len >= sizeof(full_path)) { + Error_Report(error, 1, "Internal buffer is too small"); + return -1; + } + + memcpy(full_path + written, path, path_len); + full_path[written + path_len] = '\0'; + } + Error sub_error; Error_Init(&sub_error); - Source *src = Source_FromFile(path, &sub_error); + Source *src = Source_FromFile(full_path, &sub_error); if(src == NULL) { if(maxretc == 0) diff --git a/src/lib/utils/source.c b/src/lib/utils/source.c index 3927195..9ba93af 100644 --- a/src/lib/utils/source.c +++ b/src/lib/utils/source.c @@ -28,9 +28,11 @@ ** +--------------------------------------------------------------------------+ */ +#include #include #include #include +#include #include #include #include "source.h" @@ -40,6 +42,7 @@ struct xSource { char *body; int size; int refs; + bool is_file; }; Source *Source_Copy(Source *s) @@ -72,10 +75,56 @@ unsigned int Source_GetSize(const Source *s) return s->size; } +const char *Source_GetAbsolutePath(Source *src) +{ + if(src != NULL && src->is_file) + return src->name; + return NULL; +} + Source *Source_FromFile(const char *file, Error *error) { assert(file != NULL); + if(file[0] == '\0') { + Error_Report(error, 0, "Empty file name"); + return NULL; + } + + char maybe[1024]; + const char *abs_path; + + if(file[0] == '/') + abs_path = file; + else { + if(getcwd(maybe, sizeof(maybe)) == NULL) { + Error_Report(error, 0, "Internal buffer is too small"); + return NULL; + } + + size_t written = strlen(maybe); + assert(maybe[written-1] != '/'); + + if(written+1 >= sizeof(maybe)) { + Error_Report(error, 0, "Internal buffer is too small"); + return NULL; + } + + maybe[written] = '/'; + written += 1; + + size_t n = strlen(file); + if(written + n >= sizeof(maybe)) { + Error_Report(error, 0, "Internal buffer is too small"); + return NULL; + } + + memcpy(maybe + written, file, n); + maybe[written + n] = '\0'; + + abs_path = maybe; + } + // Open the file and get it's size. // at the end of the block, the file // cursor will point at the start of @@ -83,7 +132,7 @@ Source *Source_FromFile(const char *file, Error *error) FILE *fp; int size; { - fp = fopen(file, "rb"); + fp = fopen(abs_path, "rb"); if(fp == NULL) { @@ -121,7 +170,7 @@ Source *Source_FromFile(const char *file, Error *error) // Allocate the source structure. Source *s; { - int namel = strlen(file); + int namel = strlen(abs_path); s = malloc(sizeof(Source) + namel + size + 2); @@ -132,12 +181,13 @@ Source *Source_FromFile(const char *file, Error *error) return NULL; } + s->is_file = true; s->name = (char*) (s + 1); s->body = s->name + namel + 1; } // Copy the name into it. - strcpy(s->name, file); + strcpy(s->name, abs_path); s->size = size; s->refs = 1; @@ -182,6 +232,7 @@ Source *Source_FromString(const char *name, const char *body, int size, Error *e s->body = s->name + namel + 1; s->size = size; s->refs = 1; + s->is_file = 0; if(name) strcpy(s->name, name); diff --git a/src/lib/utils/source.h b/src/lib/utils/source.h index 75aba6a..922b2dd 100644 --- a/src/lib/utils/source.h +++ b/src/lib/utils/source.h @@ -39,4 +39,5 @@ const char *Source_GetBody(const Source *s); unsigned int Source_GetSize(const Source *s); Source *Source_FromFile(const char *file, Error *error); Source *Source_FromString(const char *name, const char *body, int size, Error *error); +const char *Source_GetAbsolutePath(Source *src); #endif \ No newline at end of file