reorganized build-ins and implement a circular queue as an example
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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]
|
||||
@@ -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();
|
||||
@@ -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]));
|
||||
@@ -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');
|
||||
@@ -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]));
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
|
||||
a = 1;
|
||||
myName = "Francesco";
|
||||
myAge = 25;
|
||||
@@ -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");
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
l = [1, 2, 3, 4];
|
||||
|
||||
print('The list contains ', count(l), ' items.\n');
|
||||
print('The list is: ', l, '.\n');
|
||||
@@ -1,3 +1,5 @@
|
||||
# This script reads the contents of the specified
|
||||
# folder, and then prints all of the containd files.
|
||||
|
||||
dirname = '.';
|
||||
dir = files.openDir(dirname);
|
||||
|
||||
+12
-5
@@ -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);
|
||||
@@ -1,6 +0,0 @@
|
||||
A = 'Hello';
|
||||
B = ', ';
|
||||
C = 'world';
|
||||
D = strcat(A, B, C);
|
||||
|
||||
print(D, '\n');
|
||||
+6
-131
@@ -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, },
|
||||
{ "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 },
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../runtime/runtime.h"
|
||||
extern StaticMapSlot bins_buffer[];
|
||||
@@ -38,6 +38,8 @@ enum {
|
||||
MD_APPEND = 2,
|
||||
};
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#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 },
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
#include "../runtime/runtime.h"
|
||||
extern StaticMapSlot bins_string[];
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
** | with The Noja Interpreter. If not, see <http://www.gnu.org/licenses/>. |
|
||||
** +--------------------------------------------------------------------------+
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 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(); \
|
||||
} \
|
||||
} while(0);
|
||||
#else
|
||||
#define ASSERT(x)
|
||||
|
||||
Reference in New Issue
Block a user