diff --git a/docs/00_Overview.md b/docs/00_Overview.md index a4bb986..7c13f35 100644 --- a/docs/00_Overview.md +++ b/docs/00_Overview.md @@ -8,7 +8,7 @@ A Noja program is a sequence of statements separated by semi-colons (with some e * expressions * function definitions * if-else branches -* while loops +* while loops * do-while loops * compound statements * `break` jumps diff --git a/docs/01_Expressions.md b/docs/01_Expressions.md index d21b18f..8c399c5 100644 --- a/docs/01_Expressions.md +++ b/docs/01_Expressions.md @@ -142,6 +142,13 @@ ls[0 + 2]; # OK! ls[true or false]; # Runtime error!! ``` +To append a value to a list, increasing it's size, you can just insert the new value at the first unused position (which will have index equal to the current list size). As we'll see in the built-in chapter, to get the size of a list one can use the `count` function. Which means appending to a list can be done like this: +```py +ls = [1, 2, 3]; +ls[count(ls)] = 4; +# Now ls is [1, 2, 3, 4] +``` + ## Maps Maps are defined as a list of key-value pairs: ```py diff --git a/docs/05_Build-Ins.md b/docs/05_Build-Ins.md new file mode 100644 index 0000000..e538360 --- /dev/null +++ b/docs/05_Build-Ins.md @@ -0,0 +1,44 @@ +# Built-Ins +int +bool +float +String + +print +import +unicode +type +unicode +chr +count +input +assert +error +string.cat +buffer.new +buffer.sliceUp +buffer.toString +math.PI +math.E +math.floor +math.ceil +math.cos +math.sin +math.tan +math.acos +math.asin +math.atan +math.atan2 +math.exp +math.log +math.log10 +math.pow +math.sqrt +files.READ +files.WRITE +files.APPEND +files.openFile +files.openDir +files.nextDirItem +files.read +files.write \ No newline at end of file diff --git a/examples/adder.noja b/examples/adder.noja index 0c00ae8..2e310a4 100644 --- a/examples/adder.noja +++ b/examples/adder.noja @@ -9,4 +9,4 @@ add10 = makeAdder(10); add20 = makeAdder(20); assert(add10(1) == 11); -assert(add20(1) == 21); \ No newline at end of file +assert(add20(1) == 21); diff --git a/examples/algorithms/bubble_sort.noja b/examples/algorithms/bubble_sort.noja new file mode 100644 index 0000000..b324d1c --- /dev/null +++ b/examples/algorithms/bubble_sort.noja @@ -0,0 +1,48 @@ + +fun dummy() {} +Func = type(dummy); +NFunc = type(print); # The function type is not a build-in at the moment, + # but we can define it manually. + +fun copyList(list: List) { + + list2 = []; + + i = 0; + while i < count(list): { + list2[i] = list[i]; + i = i+1; + } + + return list2; +} + +fun numericLess(a: int | float, b: int | float) + return a < b; + +fun bubbleSort(list: List, less: NFunc | Func = numericLess) { + + list2 = copyList(list); + + do { + swapped = false; + + i = 0; + while i < count(list2)-1 and not swapped: { + if less(list2[i+1], list2[i]): { + swapped = true; + tmp = list2[i+1]; + list2[i+1] = list2[i]; + list2[i] = tmp; + } + i = i + 1; + } + } while swapped; + + return list2; +} + +unordered_list = [3, 2, 1, 6, -2]; + ordered_list = bubbleSort(unordered_list); + +print(ordered_list, '\n'); # [-2, 1, 2, 3, 6] \ No newline at end of file diff --git a/examples/args.noja b/examples/args.noja deleted file mode 100644 index b1ff276..0000000 --- a/examples/args.noja +++ /dev/null @@ -1,10 +0,0 @@ - -fun x(a, b, c) - print('a = ', a, '\nb = ', b, '\nc = ', c, '\n\n'); - -x(1, 2, 3, 4, 5); -x(1, 2, 3, 4); -x(1, 2, 3); -x(1, 2); -x(1); -x(); \ No newline at end of file diff --git a/examples/bubble_sort.noja b/examples/bubble_sort.noja deleted file mode 100644 index 00eb3a0..0000000 --- a/examples/bubble_sort.noja +++ /dev/null @@ -1,40 +0,0 @@ - -fun copy(L) { - - L2 = []; - - i = 0; - while i < count(L): { - L2[i] = L[i]; - i = i + 1; - } - - return L2; -} - -fun bubbleSort(L, less) { - if less == none: - fun less(a, b) return a < b; - - L = copy(L); - - do { - swapped = false; - - i = 0; - while i < count(L)-1 and not swapped: { - if less(L[i+1], L[i]): { - swapped = true; - tmp = L[i+1]; - L[i+1] = L[i]; - L[i] = tmp; - } - i = i + 1; - } - } while swapped; - - return L; -} - - -print(bubbleSort([3, 2, 1, 6, 0-2])); \ No newline at end of file diff --git a/examples/buffer.noja b/examples/buffer.noja deleted file mode 100644 index 7e95a4f..0000000 --- a/examples/buffer.noja +++ /dev/null @@ -1,21 +0,0 @@ - -b = newBuffer(16); - -b[2] = 10; - -print(b, '\n'); - -fun toArray(buffer) { - - i = 0; - r = []; - - while i < count(buffer): { - r[i] = buffer[i]; - i = i+1; - } - - return r; -} - -print(toArray(b), '\n'); diff --git a/examples/data_structures/queue.noja b/examples/data_structures/queue.noja new file mode 100644 index 0000000..0419d2c --- /dev/null +++ b/examples/data_structures/queue.noja @@ -0,0 +1,142 @@ +# This script implements a circular queue and +# it's relative tests! + +fun newCircularQueue(T: Type = int, max: int = 3) { + + if T == None: + error("Invalid type"); + + if max <= 0: + error("Maximum queue size must be positive"); + + list = []; + i = 0; + while i < max: { + list[i] = none; + i = i+1; + } + + return { + max: max, + head: 0, + tail: 0, + list: list, + type: T + }; +} + +fun getSize(queue: Map) { + + size = none; + if queue.tail == queue.head: { + if queue.list[queue.tail] == none: { + size = 0; + } else { + size = queue.max; + } + } else if queue.tail < queue.head: { + size = queue.head + - queue.tail; + } else { + size = queue.head + + queue.max + - queue.tail; + } + return size; +} + +fun append(queue: Map, value) { + + if type(value) != queue.type: + error("Invalid type"); + + size = getSize(queue); + + queue.list[queue.head] = value; + + if size == queue.max: { + queue.tail = queue.tail+1; + if queue.tail == queue.max: + queue.tail = 0; + } + + queue.head = queue.head+1; + if queue.head == queue.max: + queue.head = 0; +} + +fun pop(queue: Map) { + + if getSize(queue) == 0: + return none; + + value = queue.list[queue.tail]; + queue.list[queue.tail] = none; + + queue.tail = queue.tail+1; + if queue.tail == queue.max: + queue.tail = 0; + + return value; +} + +{ + utils = import("../utils.noja"); + + queue = newCircularQueue(int, 3); + assert(getSize(queue) == 0); + assert(queue.head == 0); + assert(queue.tail == 0); + + append(queue, 1); + assert(queue.head == 1); + assert(queue.tail == 0); + assert(getSize(queue) == 1); + assert(utils.compareAny(queue.list, [1, none, none])); + + append(queue, 2); + assert(queue.head == 2); + assert(queue.tail == 0); + assert(getSize(queue) == 2); + assert(utils.compareAny(queue.list, [1, 2, none])); + + append(queue, 3); + assert(queue.head == 0); + assert(queue.tail == 0); + assert(getSize(queue) == 3); + assert(utils.compareAny(queue.list, [1, 2, 3])); + + append(queue, 4); + assert(queue.head == 1); + assert(queue.tail == 1); + assert(getSize(queue) == 3); + assert(utils.compareAny(queue.list, [4, 2, 3])); + + v = pop(queue); + assert(v == 2); + assert(queue.head == 1); + assert(queue.tail == 2); + assert(getSize(queue) == 2); + assert(utils.compareAny(queue.list, [4, none, 3])); + + v = pop(queue); + assert(v == 3); + assert(queue.head == 1); + assert(queue.tail == 0); + assert(getSize(queue) == 1); + assert(utils.compareAny(queue.list, [4, none, none])); + + v = pop(queue); + assert(v == 4); + assert(queue.head == 1); + assert(queue.tail == 1); + assert(getSize(queue) == 0); + assert(utils.compareAny(queue.list, [none, none, none])); + + v = pop(queue); + assert(v == none); + assert(queue.head == 1); + assert(queue.tail == 1); + assert(getSize(queue) == 0); + assert(utils.compareAny(queue.list, [none, none, none])); +} \ No newline at end of file diff --git a/examples/stack.noja b/examples/data_structures/stack.noja similarity index 90% rename from examples/stack.noja rename to examples/data_structures/stack.noja index 7f1457f..d20b8f1 100644 --- a/examples/stack.noja +++ b/examples/data_structures/stack.noja @@ -1,10 +1,15 @@ # Implementation of a stack using a linked list. -fun Stack_New(T) +fun Stack_New(T) { + if T == None: + return none, "The type can't be None"; return { count: 0, head: none, type: T }; +} fun Stack_Push(stack: Map, value) { + assert(stack.type != None); + if type(value) != stack.type: error("Invalid type"); @@ -19,7 +24,7 @@ fun Stack_Pop(stack: Map) { if stack.head == none: return none; - + value = stack.head.item; stack.head = stack.head.prev; stack.count = stack.count - 1; diff --git a/examples/hello.noja b/examples/function.noja similarity index 100% rename from examples/hello.noja rename to examples/function.noja diff --git a/examples/imported.noja b/examples/imported.noja index 3c654e9..4f65221 100644 --- a/examples/imported.noja +++ b/examples/imported.noja @@ -1,2 +1,2 @@ - -a = 1; \ No newline at end of file +myName = "Francesco"; +myAge = 25; \ No newline at end of file diff --git a/examples/importer.noja b/examples/importer.noja index 7f0045d..19011e5 100644 --- a/examples/importer.noja +++ b/examples/importer.noja @@ -1,4 +1,10 @@ -vars, err = import("examples/imported.noja"); -print("vars=[", vars, "]\n"); -print("err=[", err, "]\n"); +vars, err = import("imported.noja"); +if vars == none: { + print("L'import รจ fallito!! (", err, ")\n"); + return none; +} + +me = {name: vars.myName, age: vars.myAge}; + +print(me, "\n"); \ No newline at end of file diff --git a/examples/json/json.noja b/examples/json/json.noja index 99534d7..437d52c 100644 --- a/examples/json/json.noja +++ b/examples/json/json.noja @@ -149,7 +149,7 @@ fun parseString(context: Map) { while context.cur < count(context.str) and context.str[context.cur] != '"': { # TODO: Support special characters such as \n, \t ecc - buffer = strcat(buffer, context.str[context.cur]); + buffer = string.cat(buffer, context.str[context.cur]); context.cur = context.cur + 1; } @@ -228,7 +228,7 @@ fun parseValue(context: Map) { val, err = parseFalse(context); else { val = none; - err = strcat("Unexepected character \"", c, "\" where a value was expected"); + err = string.cat("Unexepected character \"", c, "\" where a value was expected"); } return val, err; } diff --git a/examples/json/test.noja b/examples/json/test.noja index ec6f3c4..d903ddc 100644 --- a/examples/json/test.noja +++ b/examples/json/test.noja @@ -1,5 +1,5 @@ json = import("json.noja"); -utils = import("utils.noja"); +utils = import("../utils.noja"); assert(json.parse("null") == none); assert(json.parse("true") == true); diff --git a/examples/list.noja b/examples/list.noja deleted file mode 100644 index db4cf75..0000000 --- a/examples/list.noja +++ /dev/null @@ -1,5 +0,0 @@ - -l = [1, 2, 3, 4]; - -print('The list contains ', count(l), ' items.\n'); -print('The list is: ', l, '.\n'); diff --git a/examples/list_files.noja b/examples/list_files.noja index 15be59d..ab065c3 100644 --- a/examples/list_files.noja +++ b/examples/list_files.noja @@ -1,4 +1,6 @@ - +# This script reads the contents of the specified +# folder, and then prints all of the containd files. + dirname = '.'; dir = files.openDir(dirname); diff --git a/examples/read_file.noja b/examples/read_file.noja index 43d76cd..9f82eb3 100644 --- a/examples/read_file.noja +++ b/examples/read_file.noja @@ -1,8 +1,15 @@ +# This script reads the contents of a file. + +name = 'examples/algorithms/bubble_sort.noja'; +buff = buffer.new(1024); + +handle, err = files.openFile(name, files.READ); +if handle == none: + error(err); + +n = files.read(handle, buff); + +resl = buffer.toString(buffer.sliceUp(buff, 0, n)); -buff = newBuffer(1024); -name = 'examples/bubble_sort.noja'; -hdle = files.openFile(name, files.READ); -n = files.read(hdle, buff); -resl = bufferToString(sliceBuffer(buff, 0, n)); print('Read ', n, ' bytes.\n'); -print(resl); \ No newline at end of file +print(resl); diff --git a/examples/strcat.noja b/examples/strcat.noja deleted file mode 100644 index d64ec3d..0000000 --- a/examples/strcat.noja +++ /dev/null @@ -1,6 +0,0 @@ -A = 'Hello'; -B = ', '; -C = 'world'; -D = strcat(A, B, C); - -print(D, '\n'); \ No newline at end of file diff --git a/examples/json/utils.noja b/examples/utils.noja similarity index 100% rename from examples/json/utils.noja rename to examples/utils.noja diff --git a/examples/bug.noja b/misc/bugs/bug.noja similarity index 100% rename from examples/bug.noja rename to misc/bugs/bug.noja diff --git a/examples/bug2.noja b/misc/bugs/bug2.noja similarity index 100% rename from examples/bug2.noja rename to misc/bugs/bug2.noja diff --git a/examples/deepfailure.noja b/misc/deepfailure.noja similarity index 100% rename from examples/deepfailure.noja rename to misc/deepfailure.noja diff --git a/examples/makegarbage.noja b/misc/makegarbage.noja similarity index 100% rename from examples/makegarbage.noja rename to misc/makegarbage.noja diff --git a/src/lib/builtins/basic.c b/src/lib/builtins/basic.c index 08cef70..dbdb831 100644 --- a/src/lib/builtins/basic.c +++ b/src/lib/builtins/basic.c @@ -35,11 +35,13 @@ #include "math.h" #include "basic.h" #include "files.h" +#include "string.h" +#include "buffer.h" #include "../utils/utf8.h" #include "../utils/defs.h" #include "../objects/objects.h" -#include "../compiler/compile.h" #include "../runtime/runtime.h" +#include "../compiler/compile.h" static int bin_print(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { @@ -364,129 +366,6 @@ static int bin_error(Runtime *runtime, Object **argv, unsigned int argc, Object return -1; } -static int bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) -{ - unsigned int total_count = 0; - - for(unsigned int i = 0; i < argc; i += 1) - { - if(!Object_IsString(argv[i])) - { - Error_Report(error, 0, "Argument #%d is not a string", i+1); - return -1; - } - - total_count += Object_Count(argv[i], error); - - if(error->occurred) - return -1; - } - - char starting[128]; - char *buffer = starting; - - if(total_count > sizeof(starting)-1) - { - buffer = malloc(total_count+1); - - if(buffer == NULL) - { - Error_Report(error, 1, "No memory"); - return -1; - } - } - - Object *result = NULL; - - for(unsigned int i = 0, written = 0; i < argc; i += 1) - { - int n; - const char *s = Object_ToString(argv[i], &n, - Runtime_GetHeap(runtime), error); - - if(error->occurred) - goto done; - - memcpy(buffer + written, s, n); - written += n; - } - - buffer[total_count] = '\0'; - - result = Object_FromString(buffer, total_count, Runtime_GetHeap(runtime), error); - -done: - if(starting != buffer) - free(buffer); - - if(result == NULL) - return -1; - - rets[0] = result; - return 1; -} - -static int bin_newBuffer(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) -{ - UNUSED(argc); - ASSERT(argc == 1); - - long long int size = Object_ToInt(argv[0], error); - - if(error->occurred == 1) - return -1; - - Object *temp = Object_NewBuffer(size, Runtime_GetHeap(runtime), error); - - if(temp == NULL) - return -1; - - rets[0] = temp; - return 1; -} - -static int bin_sliceBuffer(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) -{ - UNUSED(argc); - ASSERT(argc == 3); - - long long int offset = Object_ToInt(argv[1], error); - if(error->occurred == 1) return -1; - - long long int length = Object_ToInt(argv[2], error); - if(error->occurred == 1) return -1; - - Object *temp = Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error); - - if(temp == NULL) - return -1; - - rets[0] = temp; - return 1; -} - -static int bin_bufferToString(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) -{ - UNUSED(argc); - ASSERT(argc == 1); - - void *buffaddr; - int buffsize; - - buffaddr = Object_GetBufferAddrAndSize(argv[0], &buffsize, error); - - if(error->occurred) - return -1; - - Object *temp = Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error); - - if(temp == NULL) - return -1; - - rets[0] = temp; - return 1; -} - void bins_basic_init(StaticMapSlot slots[]) { slots[0].as_type = Object_GetTypeType(); @@ -512,17 +391,13 @@ StaticMapSlot bins_basic[] = { { "Map", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "File", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, { "Dir", SM_TYPE, .as_type = NULL /* Until bins_basic_init is called */ }, - - { "math", SM_SMAP, .as_smap = bins_math, }, - { "files", SM_SMAP, .as_smap = bins_files, }, - + { "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, }, + { "import", SM_FUNCT, .as_funct = bin_import, .argc = 1, }, - { "newBuffer", SM_FUNCT, .as_funct = bin_newBuffer, .argc = 1 }, - { "sliceBuffer", SM_FUNCT, .as_funct = bin_sliceBuffer, .argc = 3 }, - { "bufferToString", SM_FUNCT, .as_funct = bin_bufferToString, .argc = 1 }, - - { "strcat", SM_FUNCT, .as_funct = bin_strcat, .argc = -1 }, - { "type", SM_FUNCT, .as_funct = bin_type, .argc = 1 }, { "unicode", SM_FUNCT, .as_funct = bin_unicode, .argc = 1 }, { "chr", SM_FUNCT, .as_funct = bin_chr, .argc = 1 }, diff --git a/src/lib/builtins/buffer.c b/src/lib/builtins/buffer.c new file mode 100644 index 0000000..8c24e9c --- /dev/null +++ b/src/lib/builtins/buffer.c @@ -0,0 +1,70 @@ +#include "buffer.h" +#include "../utils/defs.h" +#include "../runtime/runtime.h" + +static int bin_new(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) +{ + UNUSED(argc); + ASSERT(argc == 1); + + long long int size = Object_ToInt(argv[0], error); + + if(error->occurred == 1) + return -1; + + Object *temp = Object_NewBuffer(size, Runtime_GetHeap(runtime), error); + + if(temp == NULL) + return -1; + + rets[0] = temp; + return 1; +} + +static int bin_sliceUp(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) +{ + UNUSED(argc); + ASSERT(argc == 3); + + long long int offset = Object_ToInt(argv[1], error); + if(error->occurred == 1) return -1; + + long long int length = Object_ToInt(argv[2], error); + if(error->occurred == 1) return -1; + + Object *temp = Object_SliceBuffer(argv[0], offset, length, Runtime_GetHeap(runtime), error); + + if(temp == NULL) + return -1; + + rets[0] = temp; + return 1; +} + +static int bin_toString(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) +{ + UNUSED(argc); + ASSERT(argc == 1); + + void *buffaddr; + int buffsize; + + buffaddr = Object_GetBufferAddrAndSize(argv[0], &buffsize, error); + + if(error->occurred) + return -1; + + Object *temp = Object_FromString(buffaddr, buffsize, Runtime_GetHeap(runtime), error); + + if(temp == NULL) + return -1; + + rets[0] = temp; + return 1; +} + +StaticMapSlot bins_buffer[] = { + { "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 }, +}; diff --git a/src/lib/builtins/buffer.h b/src/lib/builtins/buffer.h new file mode 100644 index 0000000..cd8f3f1 --- /dev/null +++ b/src/lib/builtins/buffer.h @@ -0,0 +1,2 @@ +#include "../runtime/runtime.h" +extern StaticMapSlot bins_buffer[]; \ No newline at end of file diff --git a/src/lib/builtins/files.c b/src/lib/builtins/files.c index 166e411..733f300 100644 --- a/src/lib/builtins/files.c +++ b/src/lib/builtins/files.c @@ -38,6 +38,8 @@ enum { MD_APPEND = 2, }; +#include + static int bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) { UNUSED(argc); @@ -94,8 +96,34 @@ static int bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, Obje fp = fopen(path, mode2); - if(fp == NULL) - return 0; + 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 ENOTDIR: errdesc = "Entity is not a directory"; 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; + } + + 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; + } } rets[0] = Object_FromStream(fp, heap, error); diff --git a/src/lib/builtins/string.c b/src/lib/builtins/string.c new file mode 100644 index 0000000..d47f63e --- /dev/null +++ b/src/lib/builtins/string.c @@ -0,0 +1,71 @@ +#include +#include +#include "string.h" +#include "../utils/defs.h" +#include "../runtime/runtime.h" + +static int bin_cat(Runtime *runtime, Object **argv, unsigned int argc, Object *rets[static MAX_RETS], Error *error) +{ + unsigned int total_count = 0; + + for(unsigned int i = 0; i < argc; i += 1) + { + if(!Object_IsString(argv[i])) + { + Error_Report(error, 0, "Argument #%d is not a string", i+1); + return -1; + } + + total_count += Object_Count(argv[i], error); + + if(error->occurred) + return -1; + } + + char starting[128]; + char *buffer = starting; + + if(total_count > sizeof(starting)-1) + { + buffer = malloc(total_count+1); + + if(buffer == NULL) + { + Error_Report(error, 1, "No memory"); + return -1; + } + } + + Object *result = NULL; + + for(unsigned int i = 0, written = 0; i < argc; i += 1) + { + int n; + const char *s = Object_ToString(argv[i], &n, + Runtime_GetHeap(runtime), error); + + if(error->occurred) + goto done; + + memcpy(buffer + written, s, n); + written += n; + } + + buffer[total_count] = '\0'; + + result = Object_FromString(buffer, total_count, Runtime_GetHeap(runtime), error); + +done: + if(starting != buffer) + free(buffer); + + if(result == NULL) + return -1; + + rets[0] = result; + return 1; +} + +StaticMapSlot bins_string[] = { + { "cat", SM_FUNCT, .as_funct = bin_cat, .argc = -1 }, +}; diff --git a/src/lib/builtins/string.h b/src/lib/builtins/string.h new file mode 100644 index 0000000..781be8e --- /dev/null +++ b/src/lib/builtins/string.h @@ -0,0 +1,2 @@ +#include "../runtime/runtime.h" +extern StaticMapSlot bins_string[]; \ No newline at end of file diff --git a/src/lib/objects/o_closure.c b/src/lib/objects/o_closure.c index 06c43ec..d385abb 100644 --- a/src/lib/objects/o_closure.c +++ b/src/lib/objects/o_closure.c @@ -40,13 +40,13 @@ struct ClosureObject { }; static void walk(Object *self, void (*callback)(Object **referer, void *userp), void *userp); -static Object *select(Object *self, Object *key, Heap *heap, Error *err); +static Object *select_(Object *self, Object *key, Heap *heap, Error *err); static TypeObject t_closure = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, .name = "closure", .size = sizeof(ClosureObject), - .select = select, + .select = select_, .walk = walk, }; @@ -69,7 +69,7 @@ Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *er return (Object*) obj; } -static Object *select(Object *self, Object *key, Heap *heap, Error *err) +static Object *select_(Object *self, Object *key, Heap *heap, Error *err) { ClosureObject *closure = (ClosureObject*) self; diff --git a/src/lib/objects/o_list.c b/src/lib/objects/o_list.c index 3dc1943..343b4a3 100644 --- a/src/lib/objects/o_list.c +++ b/src/lib/objects/o_list.c @@ -38,7 +38,7 @@ typedef struct { Object **vals; } ListObject; -static Object *select(Object *self, Object *key, Heap *heap, Error *err); +static Object *select_(Object *self, Object *key, Heap *heap, Error *err); static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); static int count(Object *self); static void print(Object *obj, FILE *fp); @@ -53,7 +53,7 @@ static TypeObject t_list = { .size = sizeof (ListObject), .copy = copy, .hash = hash, - .select = select, + .select = select_, .insert = insert, .count = count, .print = print, @@ -158,7 +158,7 @@ static void walkexts(Object *self, void (*callback)(void **referer, unsigned int callback((void**) &list->vals, sizeof(Object) * list->capacity, userp); } -static Object *select(Object *self, Object *key, Heap *heap, Error *error) +static Object *select_(Object *self, Object *key, Heap *heap, Error *error) { UNUSED(heap); ASSERT(self != NULL); diff --git a/src/lib/objects/o_map.c b/src/lib/objects/o_map.c index c369777..a233ef4 100644 --- a/src/lib/objects/o_map.c +++ b/src/lib/objects/o_map.c @@ -39,7 +39,7 @@ typedef struct { Object **vals; } MapObject; -static Object *select(Object *self, Object *key, Heap *heap, Error *err); +static Object *select_(Object *self, Object *key, Heap *heap, Error *err); static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *err); static int count(Object *self); static void print(Object *self, FILE *fp); @@ -54,7 +54,7 @@ static TypeObject t_map = { .size = sizeof (MapObject), .copy = copy, .hash = hash, - .select = select, + .select = select_, .insert = insert, .count = count, .print = print, @@ -174,7 +174,7 @@ static void walkexts(Object *self, void (*callback)(void **referer, unsigned int callback((void**) &map->vals, sizeof(Object*) * capacity, userp); } -static Object *select(Object *self, Object *key, Heap *heap, Error *error) +static Object *select_(Object *self, Object *key, Heap *heap, Error *error) { UNUSED(heap); ASSERT(self != NULL); diff --git a/src/lib/objects/o_string.c b/src/lib/objects/o_string.c index 27c3327..7c85efc 100644 --- a/src/lib/objects/o_string.c +++ b/src/lib/objects/o_string.c @@ -48,7 +48,7 @@ static void print(Object *obj, FILE *fp); static char *to_string(Object *self, int *size, Heap *heap, Error *err); static _Bool op_eql(Object *self, Object *other); static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp); -static Object *select(Object *self, Object *key, Heap *heap, Error *error); +static Object *select_(Object *self, Object *key, Heap *heap, Error *error); static TypeObject t_string = { .base = (Object) { .type = &t_type, .flags = Object_STATIC }, @@ -59,7 +59,7 @@ static TypeObject t_string = { .count = count, .copy = copy, .print = print, - .select = select, + .select = select_, .to_string = to_string, .op_eql = op_eql, .walkexts = walkexts, @@ -89,7 +89,7 @@ static int char_index_to_offset(StringObject *str, int idx) return scanned_bytes; } -static Object *select(Object *self, Object *key, Heap *heap, Error *error) +static Object *select_(Object *self, Object *key, Heap *heap, Error *error) { ASSERT(self != NULL && self->type == &t_string); ASSERT(key != NULL && heap != NULL && error != NULL); diff --git a/src/lib/runtime/o_staticmap.c b/src/lib/runtime/o_staticmap.c index f359209..56d335a 100644 --- a/src/lib/runtime/o_staticmap.c +++ b/src/lib/runtime/o_staticmap.c @@ -57,7 +57,7 @@ typedef struct { const StaticMapSlot *slots; } StaticMapObject; -static Object *select(Object *self, Object *key, Heap *heap, Error *err); +static Object *select_(Object *self, Object *key, Heap *heap, Error *err); static Object *copy(Object *self, Heap *heap, Error *err); static int hash(Object *self); @@ -67,7 +67,7 @@ static TypeObject t_staticmap = { .size = sizeof (StaticMapObject), .copy = copy, .hash = hash, - .select = select, + .select = select_, }; static Object *copy(Object *self, Heap *heap, Error *err) @@ -103,7 +103,7 @@ Object *Object_NewStaticMap(StaticMapSlot slots[], void (*initfn)(StaticMapSlot[ return (Object*) obj; } -static Object *select(Object *self, Object *key, Heap *heap, Error *error) +static Object *select_(Object *self, Object *key, Heap *heap, Error *error) { assert(self != NULL); assert(self->type == &t_staticmap); diff --git a/src/lib/utils/defs.h b/src/lib/utils/defs.h index 4901898..cc5e975 100644 --- a/src/lib/utils/defs.h +++ b/src/lib/utils/defs.h @@ -27,6 +27,8 @@ ** | with The Noja Interpreter. If not, see . | ** +--------------------------------------------------------------------------+ */ +#include +#include // just for [abort] #ifndef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) @@ -46,16 +48,14 @@ #define ASSERT(X) \ do { \ if(!(X)) { \ - fprintf(stderr, "Assertion failure %s:%d (in %s): [" #X "] is false\n", __FILE__, __LINE__, __func__); \ + fprintf(stderr, "Assertion failure %s:%d (in %s): [%s] is false\n", __FILE__, __LINE__, __func__, #X); \ abort(); \ } \ } while(0); -#define UNREACHABLE \ - do { \ - if(!(x)) { \ - fprintf(stderr, "ABORT at %s:%d (in %s): Reached code assumed to be unreachable\n", __FILE__, __LINE__, __func__); \ - abort(); \ - } \ +#define UNREACHABLE \ + do { \ + fprintf(stderr, "ABORT at %s:%d (in %s): Reached code assumed to be unreachable\n", __FILE__, __LINE__, __func__); \ + abort(); \ } while(0); #else #define ASSERT(x)