new curly bracket coding convention
This commit is contained in:
+39
-38
@@ -42,10 +42,10 @@ fun parse(str) {
|
|||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseAnyValue(ctx);
|
return parseAny(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseArrayValue(ctx) {
|
fun parseArray(ctx) {
|
||||||
|
|
||||||
assert(current(ctx) == '[');
|
assert(current(ctx) == '[');
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ fun parseArrayValue(ctx) {
|
|||||||
|
|
||||||
while true: {
|
while true: {
|
||||||
|
|
||||||
child = parseAnyValue(ctx);
|
child = parseAny(ctx);
|
||||||
|
|
||||||
if child == none:
|
if child == none:
|
||||||
return none;
|
return none;
|
||||||
@@ -103,7 +103,7 @@ fun parseArrayValue(ctx) {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseObjectValue(ctx) {
|
fun parseObject(ctx) {
|
||||||
|
|
||||||
assert(current(ctx) == '{');
|
assert(current(ctx) == '{');
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ fun parseObjectValue(ctx) {
|
|||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = parseStringValue(ctx);
|
key = parseString(ctx);
|
||||||
|
|
||||||
if key == none:
|
if key == none:
|
||||||
return none;
|
return none;
|
||||||
@@ -146,7 +146,7 @@ fun parseObjectValue(ctx) {
|
|||||||
|
|
||||||
skip(ctx, isSpace);
|
skip(ctx, isSpace);
|
||||||
|
|
||||||
child = parseAnyValue(ctx);
|
child = parseAny(ctx);
|
||||||
|
|
||||||
if child == none:
|
if child == none:
|
||||||
return none;
|
return none;
|
||||||
@@ -182,7 +182,7 @@ fun parseObjectValue(ctx) {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseStringValue(ctx) {
|
fun parseString(ctx) {
|
||||||
|
|
||||||
next(ctx); # Skip the '"'.
|
next(ctx); # Skip the '"'.
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ fun parseStringValue(ctx) {
|
|||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseNumberValue(ctx) {
|
fun parseNumber(ctx) {
|
||||||
|
|
||||||
assert(isDigit(current(ctx)));
|
assert(isDigit(current(ctx)));
|
||||||
|
|
||||||
@@ -251,49 +251,50 @@ fun parseNumberValue(ctx) {
|
|||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseAnyValue(ctx) {
|
fun parseAny(ctx) {
|
||||||
|
|
||||||
|
print('Parsing value\n');
|
||||||
|
|
||||||
assert(not ended(ctx));
|
assert(not ended(ctx));
|
||||||
|
|
||||||
if current(ctx) == '[':
|
if current(ctx) == '[':
|
||||||
return parseArrayValue(ctx);
|
return parseArray(ctx);
|
||||||
|
|
||||||
if current(ctx) == '{':
|
if current(ctx) == '{':
|
||||||
return parseObjectValue(ctx);
|
return parseObject(ctx);
|
||||||
|
|
||||||
if current(ctx) == '"':
|
if current(ctx) == '"':
|
||||||
return parseStringValue(ctx);
|
return parseString(ctx);
|
||||||
|
|
||||||
if isDigit(current(ctx)):
|
if isDigit(current(ctx)):
|
||||||
return parseNumberValue(ctx);
|
return parseNumber(ctx);
|
||||||
|
|
||||||
error("Not implemented yet");
|
error("Not implemented yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tests = [
|
#tests = ['', '1', '10', '1.10', '"jeje"', '[]', '[1,2,3]', ' [ ] ', ' [ 1 , 2 , 3 ]', '{}', ' { } ', '{"hoy":4}', ' { "hoy" : 4 } '];
|
||||||
'',
|
|
||||||
'1',
|
|
||||||
'10',
|
|
||||||
'1.10',
|
|
||||||
'"jeje"',
|
|
||||||
'[]',
|
|
||||||
'[1,2,3]',
|
|
||||||
' [ ] ',
|
|
||||||
' [ 1 , 2 , 3 ]',
|
|
||||||
'{}',
|
|
||||||
' { } ',
|
|
||||||
'{"hoy":4}',
|
|
||||||
' { "hoy" : 4 } ',
|
|
||||||
'a'
|
|
||||||
];
|
|
||||||
|
|
||||||
i = 0;
|
#i = 0;
|
||||||
while i < count(tests): {
|
#while i < count(tests): {
|
||||||
r = parse(tests[i]);
|
# r = parse(tests[i]);
|
||||||
if r == none:
|
# if r == none:
|
||||||
print('\nTest ', i, ' failed\n');
|
# print('\nTest ', i, ' failed\n');
|
||||||
else
|
# else
|
||||||
print(tests[i], ' -> ', r, '\n');
|
# print(tests[i], ' -> ', r, '\n');
|
||||||
i = i + 1;
|
# i = i + 1;
|
||||||
}
|
#}
|
||||||
|
|
||||||
|
file = files.openFile('examples/large-file.json', files.READ);
|
||||||
|
if file == none:
|
||||||
|
error("Failed to open file");
|
||||||
|
|
||||||
|
buff = newBuffer(30000000);
|
||||||
|
if buff == none:
|
||||||
|
error("Failed to create buffer");
|
||||||
|
|
||||||
|
n = files.read(file, buff);
|
||||||
|
|
||||||
|
text = bufferToString(sliceBuffer(buff, 0, n));
|
||||||
|
|
||||||
|
print(parse(text));
|
||||||
|
|||||||
+59
-60
@@ -64,10 +64,10 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E
|
|||||||
uint32_t ret = 0;
|
uint32_t ret = 0;
|
||||||
|
|
||||||
if(!Object_IsString(argv[0]))
|
if(!Object_IsString(argv[0]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Argument #%d is not a string", 1);
|
Error_Report(error, 0, "Argument #%d is not a string", 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *string;
|
const char *string;
|
||||||
int n;
|
int n;
|
||||||
@@ -76,10 +76,10 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if(n == 0)
|
if(n == 0)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Argument #%d is an empty string", 1);
|
Error_Report(error, 0, "Argument #%d is an empty string", 1);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int k = utf8_sequence_to_utf32_codepoint(string,n,&ret);
|
int k = utf8_sequence_to_utf32_codepoint(string,n,&ret);
|
||||||
@@ -111,31 +111,31 @@ static Object *bin_input(Runtime *runtime, Object **argv, unsigned int argc, Err
|
|||||||
int size = 0, cap = sizeof(maybe)-1;
|
int size = 0, cap = sizeof(maybe)-1;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
|
{
|
||||||
|
char c = getc(stdin);
|
||||||
|
|
||||||
|
if(c == '\n')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(size == cap)
|
||||||
{
|
{
|
||||||
char c = getc(stdin);
|
int newcap = cap*2;
|
||||||
|
char *tmp = realloc(str, newcap + 1);
|
||||||
|
|
||||||
if(c == '\n')
|
if(tmp == NULL)
|
||||||
break;
|
{
|
||||||
|
if(str != maybe) free(str);
|
||||||
|
Error_Report(error, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(size == cap)
|
str = tmp;
|
||||||
{
|
cap = newcap;
|
||||||
int newcap = cap*2;
|
|
||||||
char *tmp = realloc(str, newcap + 1);
|
|
||||||
|
|
||||||
if(tmp == NULL)
|
|
||||||
{
|
|
||||||
if(str != maybe) free(str);
|
|
||||||
Error_Report(error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = tmp;
|
|
||||||
cap = newcap;
|
|
||||||
}
|
|
||||||
|
|
||||||
str[size++] = c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str[size++] = c;
|
||||||
|
}
|
||||||
|
|
||||||
str[size] = '\0';
|
str[size] = '\0';
|
||||||
|
|
||||||
Object *res = Object_FromString(str, size, Runtime_GetHeap(runtime), error);
|
Object *res = Object_FromString(str, size, Runtime_GetHeap(runtime), error);
|
||||||
@@ -150,11 +150,11 @@ static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Er
|
|||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < argc; i += 1)
|
for(unsigned int i = 0; i < argc; i += 1)
|
||||||
if(!Object_ToBool(argv[i], error))
|
if(!Object_ToBool(argv[i], error))
|
||||||
{
|
{
|
||||||
if(!error->occurred)
|
if(!error->occurred)
|
||||||
Error_Report(error, 0, "Assertion failed");
|
Error_Report(error, 0, "Assertion failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,48 +179,47 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
|
|||||||
unsigned int total_count = 0;
|
unsigned int total_count = 0;
|
||||||
|
|
||||||
for(unsigned int i = 0; i < argc; i += 1)
|
for(unsigned int i = 0; i < argc; i += 1)
|
||||||
|
{
|
||||||
|
if(!Object_IsString(argv[i]))
|
||||||
{
|
{
|
||||||
if(!Object_IsString(argv[i]))
|
Error_Report(error, 0, "Argument #%d is not a string", i+1);
|
||||||
{
|
return NULL;
|
||||||
Error_Report(error, 0, "Argument #%d is not a string", i+1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
total_count += Object_Count(argv[i], error);
|
|
||||||
|
|
||||||
if(error->occurred)
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total_count += Object_Count(argv[i], error);
|
||||||
|
|
||||||
|
if(error->occurred)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char starting[128];
|
char starting[128];
|
||||||
char *buffer = starting;
|
char *buffer = starting;
|
||||||
|
|
||||||
if(total_count > sizeof(starting)-1)
|
if(total_count > sizeof(starting)-1)
|
||||||
{
|
{
|
||||||
buffer = malloc(total_count+1);
|
buffer = malloc(total_count+1);
|
||||||
|
|
||||||
if(buffer == NULL)
|
if(buffer == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Object *result = NULL;
|
Object *result = NULL;
|
||||||
|
|
||||||
for(unsigned int i = 0, written = 0; i < argc; i += 1)
|
for(unsigned int i = 0, written = 0; i < argc; i += 1)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
const char *s;
|
const char *s = Object_ToString(argv[i], &n,
|
||||||
|
Runtime_GetHeap(runtime), error);
|
||||||
|
|
||||||
s = Object_ToString(argv[i], &n, Runtime_GetHeap(runtime), error);
|
if(error->occurred)
|
||||||
|
goto done;
|
||||||
|
|
||||||
if(error->occurred)
|
memcpy(buffer + written, s, n);
|
||||||
goto done;
|
written += n;
|
||||||
|
}
|
||||||
memcpy(buffer + written, s, n);
|
|
||||||
written += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[total_count] = '\0';
|
buffer[total_count] = '\0';
|
||||||
|
|
||||||
|
|||||||
+93
-93
@@ -43,16 +43,16 @@ static Object *bin_openFile(Runtime *runtime, Object **argv, unsigned int argc,
|
|||||||
assert(argc == 2);
|
assert(argc == 2);
|
||||||
|
|
||||||
if(!Object_IsString(argv[0]))
|
if(!Object_IsString(argv[0]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0]));
|
Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Object_IsInt(argv[1]))
|
if(!Object_IsInt(argv[1]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected second argument to be an int, but it's a %s", Object_GetName(argv[1]));
|
Error_Report(error, 0, "Expected second argument to be an int, but it's a %s", Object_GetName(argv[1]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap *heap = Runtime_GetHeap(runtime);
|
Heap *heap = Runtime_GetHeap(runtime);
|
||||||
|
|
||||||
@@ -71,24 +71,24 @@ static Object *bin_openFile(Runtime *runtime, Object **argv, unsigned int argc,
|
|||||||
const char *mode2;
|
const char *mode2;
|
||||||
|
|
||||||
switch(mode)
|
switch(mode)
|
||||||
{
|
{
|
||||||
case MD_READ:
|
case MD_READ:
|
||||||
mode2 = "r";
|
mode2 = "r";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MD_READ | MD_WRITE:
|
case MD_READ | MD_WRITE:
|
||||||
mode2 = "w+";
|
mode2 = "w+";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MD_READ | MD_APPEND:
|
case MD_READ | MD_APPEND:
|
||||||
case MD_READ | MD_WRITE | MD_APPEND:
|
case MD_READ | MD_WRITE | MD_APPEND:
|
||||||
mode2 = "a";
|
mode2 = "a";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(path, mode2);
|
fp = fopen(path, mode2);
|
||||||
|
|
||||||
@@ -108,16 +108,16 @@ static Object *bin_read(Runtime *runtime, Object **argv, unsigned int argc, Erro
|
|||||||
// Arg 2: count
|
// Arg 2: count
|
||||||
|
|
||||||
if(!Object_IsFile(argv[0]))
|
if(!Object_IsFile(argv[0]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0]));
|
Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Object_IsBuffer(argv[1]))
|
if(!Object_IsBuffer(argv[1]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1]));
|
Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap *heap = Runtime_GetHeap(runtime);
|
Heap *heap = Runtime_GetHeap(runtime);
|
||||||
|
|
||||||
@@ -129,26 +129,26 @@ static Object *bin_read(Runtime *runtime, Object **argv, unsigned int argc, Erro
|
|||||||
int read_size;
|
int read_size;
|
||||||
|
|
||||||
if(Object_IsNone(argv[2]))
|
if(Object_IsNone(argv[2]))
|
||||||
{
|
{
|
||||||
read_size = buff_size;
|
read_size = buff_size;
|
||||||
}
|
}
|
||||||
else if(Object_IsInt(argv[2]))
|
else if(Object_IsInt(argv[2]))
|
||||||
{
|
{
|
||||||
long long int temp = Object_ToInt(argv[2], error);
|
long long int temp = Object_ToInt(argv[2], error);
|
||||||
|
|
||||||
if(error->occurred)
|
if(error->occurred)
|
||||||
return NULL;
|
|
||||||
|
|
||||||
read_size = temp; // TODO: Handle potential overflow.
|
|
||||||
|
|
||||||
if(read_size > buff_size)
|
|
||||||
read_size = buff_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "Expected third argument to be an int or none, but it's a %s", Object_GetName(argv[0]));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
read_size = temp; // TODO: Handle potential overflow.
|
||||||
|
|
||||||
|
if(read_size > buff_size)
|
||||||
|
read_size = buff_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Expected third argument to be an int or none, but it's a %s", Object_GetName(argv[0]));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *fp = Object_ToStream(argv[0], error);
|
FILE *fp = Object_ToStream(argv[0], error);
|
||||||
|
|
||||||
@@ -169,16 +169,16 @@ static Object *bin_write(Runtime *runtime, Object **argv, unsigned int argc, Err
|
|||||||
// Arg 2: count
|
// Arg 2: count
|
||||||
|
|
||||||
if(!Object_IsFile(argv[0]))
|
if(!Object_IsFile(argv[0]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0]));
|
Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Object_IsBuffer(argv[1]))
|
if(!Object_IsBuffer(argv[1]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1]));
|
Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap *heap = Runtime_GetHeap(runtime);
|
Heap *heap = Runtime_GetHeap(runtime);
|
||||||
|
|
||||||
@@ -190,26 +190,26 @@ static Object *bin_write(Runtime *runtime, Object **argv, unsigned int argc, Err
|
|||||||
int write_size;
|
int write_size;
|
||||||
|
|
||||||
if(Object_IsNone(argv[2]))
|
if(Object_IsNone(argv[2]))
|
||||||
{
|
{
|
||||||
write_size = buff_size;
|
write_size = buff_size;
|
||||||
}
|
}
|
||||||
else if(Object_IsInt(argv[2]))
|
else if(Object_IsInt(argv[2]))
|
||||||
{
|
{
|
||||||
long long int temp = Object_ToInt(argv[2], error);
|
long long int temp = Object_ToInt(argv[2], error);
|
||||||
|
|
||||||
if(error->occurred)
|
if(error->occurred)
|
||||||
return NULL;
|
|
||||||
|
|
||||||
write_size = temp; // TODO: Handle potential overflow.
|
|
||||||
|
|
||||||
if(write_size > buff_size)
|
|
||||||
write_size = buff_size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "Expected third argument to be an int or none, but it's a %s", Object_GetName(argv[0]));
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
write_size = temp; // TODO: Handle potential overflow.
|
||||||
|
|
||||||
|
if(write_size > buff_size)
|
||||||
|
write_size = buff_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Expected third argument to be an int or none, but it's a %s", Object_GetName(argv[0]));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *fp = Object_ToStream(argv[0], error);
|
FILE *fp = Object_ToStream(argv[0], error);
|
||||||
|
|
||||||
@@ -228,10 +228,10 @@ static Object *bin_openDir(Runtime *runtime, Object **argv, unsigned int argc, E
|
|||||||
// Arg 0: path
|
// Arg 0: path
|
||||||
|
|
||||||
if(!Object_IsString(argv[0]))
|
if(!Object_IsString(argv[0]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0]));
|
Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Heap *heap = Runtime_GetHeap(runtime);
|
Heap *heap = Runtime_GetHeap(runtime);
|
||||||
|
|
||||||
@@ -248,10 +248,10 @@ static Object *bin_openDir(Runtime *runtime, Object **argv, unsigned int argc, E
|
|||||||
Object *dob = Object_FromDIR(dir, heap, error);
|
Object *dob = Object_FromDIR(dir, heap, error);
|
||||||
|
|
||||||
if(error->occurred)
|
if(error->occurred)
|
||||||
{
|
{
|
||||||
(void) closedir(dir);
|
(void) closedir(dir);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dob;
|
return dob;
|
||||||
}
|
}
|
||||||
@@ -263,10 +263,10 @@ static Object *bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int arg
|
|||||||
// Arg 0: path
|
// Arg 0: path
|
||||||
|
|
||||||
if(!Object_IsDir(argv[0]))
|
if(!Object_IsDir(argv[0]))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Expected first argument to be a directory, but it's a %s", Object_GetName(argv[0]));
|
Error_Report(error, 0, "Expected first argument to be a directory, but it's a %s", Object_GetName(argv[0]));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR *dir = Object_ToDIR(argv[0], error);
|
DIR *dir = Object_ToDIR(argv[0], error);
|
||||||
|
|
||||||
@@ -282,15 +282,15 @@ static Object *bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int arg
|
|||||||
struct dirent *ent = readdir(dir);
|
struct dirent *ent = readdir(dir);
|
||||||
|
|
||||||
if(ent == NULL)
|
if(ent == NULL)
|
||||||
{
|
{
|
||||||
if(errno == 0)
|
if(errno == 0)
|
||||||
// Nothing left to read.
|
// Nothing left to read.
|
||||||
return Object_NewNone(heap, error);
|
return Object_NewNone(heap, error);
|
||||||
|
|
||||||
// An error occurred.
|
// An error occurred.
|
||||||
Error_Report(error, 1, "Failed to read directory item");
|
Error_Report(error, 1, "Failed to read directory item");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object_FromString(ent->d_name, -1, heap, error);
|
return Object_FromString(ent->d_name, -1, heap, error);
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-45
@@ -33,54 +33,54 @@
|
|||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#define WRAP_FUNC(name) \
|
#define WRAP_FUNC(name) \
|
||||||
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
|
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
|
||||||
{ \
|
{ \
|
||||||
assert(argc == 1); \
|
assert(argc == 1); \
|
||||||
\
|
\
|
||||||
if(Object_IsFloat(argv[0])) \
|
if(Object_IsFloat(argv[0])) \
|
||||||
{ \
|
{ \
|
||||||
double v = Object_ToFloat(argv[0], error); \
|
double v = Object_ToFloat(argv[0], error); \
|
||||||
\
|
\
|
||||||
if(error->occurred) \
|
if(error->occurred) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
\
|
\
|
||||||
return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
|
return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
|
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WRAP_FUNC_2(name) \
|
#define WRAP_FUNC_2(name) \
|
||||||
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
|
static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \
|
||||||
{ \
|
{ \
|
||||||
assert(argc == 2); \
|
assert(argc == 2); \
|
||||||
\
|
\
|
||||||
if(!Object_IsFloat(argv[0])) \
|
if(!Object_IsFloat(argv[0])) \
|
||||||
{ \
|
{ \
|
||||||
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
|
Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
if(!Object_IsFloat(argv[1])) \
|
if(!Object_IsFloat(argv[1])) \
|
||||||
{ \
|
{ \
|
||||||
Error_Report(error, 0, "Expected second argument to be a float, but it's a %s", Object_GetName(argv[1]));\
|
Error_Report(error, 0, "Expected second argument to be a float, but it's a %s", Object_GetName(argv[1]));\
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
double v1 = Object_ToFloat(argv[0], error); \
|
double v1 = Object_ToFloat(argv[0], error); \
|
||||||
\
|
\
|
||||||
if(error->occurred) \
|
if(error->occurred) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
\
|
\
|
||||||
double v2 = Object_ToFloat(argv[1], error); \
|
double v2 = Object_ToFloat(argv[1], error); \
|
||||||
\
|
\
|
||||||
if(error->occurred) \
|
if(error->occurred) \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
\
|
\
|
||||||
return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
|
return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \
|
||||||
}
|
}
|
||||||
|
|
||||||
WRAP_FUNC(ceil)
|
WRAP_FUNC(ceil)
|
||||||
|
|||||||
+167
-169
@@ -131,51 +131,51 @@ void Executable_Free(Executable *exe)
|
|||||||
assert(exe->refs >= 0);
|
assert(exe->refs >= 0);
|
||||||
|
|
||||||
if(exe->refs == 0)
|
if(exe->refs == 0)
|
||||||
{
|
{
|
||||||
if(exe->src)
|
if(exe->src)
|
||||||
Source_Free(exe->src);
|
Source_Free(exe->src);
|
||||||
free(exe);
|
free(exe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Executable_Dump(Executable *exe)
|
void Executable_Dump(Executable *exe)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < exe->bodyl; i += 1)
|
for(int i = 0; i < exe->bodyl; i += 1)
|
||||||
|
{
|
||||||
|
Opcode opcode;
|
||||||
|
Operand ops[MAX_OPS];
|
||||||
|
int opc = MAX_OPS;
|
||||||
|
|
||||||
|
(void) Executable_Fetch(exe, i, &opcode, ops, &opc);
|
||||||
|
|
||||||
|
const InstrInfo *info = instr_table + exe->body[i].opcode;
|
||||||
|
|
||||||
|
fprintf(stderr, "%d: %s ", i, info->name);
|
||||||
|
|
||||||
|
for(int j = 0; j < opc; j += 1)
|
||||||
{
|
{
|
||||||
Opcode opcode;
|
switch(ops[j].type)
|
||||||
Operand ops[MAX_OPS];
|
{
|
||||||
int opc = MAX_OPS;
|
case OPTP_INT:
|
||||||
|
fprintf(stderr, "%lld ", ops[j].as_int);
|
||||||
|
break;
|
||||||
|
|
||||||
(void) Executable_Fetch(exe, i, &opcode, ops, &opc);
|
case OPTP_FLOAT:
|
||||||
|
fprintf(stderr, "%f ", ops[j].as_float);
|
||||||
|
break;
|
||||||
|
|
||||||
const InstrInfo *info = instr_table + exe->body[i].opcode;
|
case OPTP_STRING:
|
||||||
|
fprintf(stderr, "[%s] ", ops[j].as_string);
|
||||||
|
break;
|
||||||
|
|
||||||
fprintf(stderr, "%d: %s ", i, info->name);
|
case OPTP_PROMISE:
|
||||||
|
UNREACHABLE;
|
||||||
for(int j = 0; j < opc; j += 1)
|
break;
|
||||||
{
|
}
|
||||||
switch(ops[j].type)
|
|
||||||
{
|
|
||||||
case OPTP_INT:
|
|
||||||
fprintf(stderr, "%lld ", ops[j].as_int);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_FLOAT:
|
|
||||||
fprintf(stderr, "%f ", ops[j].as_float);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_STRING:
|
|
||||||
fprintf(stderr, "[%s] ", ops[j].as_string);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_PROMISE:
|
|
||||||
UNREACHABLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_Bool Executable_SetSource(Executable *exe, Source *src)
|
_Bool Executable_SetSource(Executable *exe, Source *src)
|
||||||
@@ -232,46 +232,46 @@ _Bool Executable_Fetch(Executable *exe, int index, Opcode *opcode, Operand *ops,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(ops && opc)
|
if(ops && opc)
|
||||||
|
{
|
||||||
|
int k = MIN(*opc, info->opcount);
|
||||||
|
|
||||||
|
for(i = 0; i < k; i += 1)
|
||||||
{
|
{
|
||||||
int k = MIN(*opc, info->opcount);
|
OperandType type = info->optypes[i];
|
||||||
|
assert(type != OPTP_PROMISE);
|
||||||
|
|
||||||
for(i = 0; i < k; i += 1)
|
switch(type)
|
||||||
|
{
|
||||||
|
case OPTP_STRING:
|
||||||
{
|
{
|
||||||
OperandType type = info->optypes[i];
|
int data_offset = instr->operands[i].as_int;
|
||||||
assert(type != OPTP_PROMISE);
|
|
||||||
|
|
||||||
switch(type) {
|
assert(data_offset < exe->headl);
|
||||||
|
|
||||||
case OPTP_STRING:
|
ops[i].type = OPTP_STRING;
|
||||||
{
|
ops[i].as_string = exe->head + data_offset;
|
||||||
int data_offset = instr->operands[i].as_int;
|
break;
|
||||||
|
|
||||||
assert(data_offset < exe->headl);
|
|
||||||
|
|
||||||
ops[i].type = OPTP_STRING;
|
|
||||||
ops[i].as_string = exe->head + data_offset;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case OPTP_INT:
|
|
||||||
ops[i].type = OPTP_INT;
|
|
||||||
ops[i].as_int = instr->operands[i].as_int;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_FLOAT:
|
|
||||||
ops[i].type = OPTP_FLOAT;
|
|
||||||
ops[i].as_int = instr->operands[i].as_int;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_PROMISE:
|
|
||||||
UNREACHABLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*opc = MIN(*opc, info->opcount);
|
case OPTP_INT:
|
||||||
|
ops[i].type = OPTP_INT;
|
||||||
|
ops[i].as_int = instr->operands[i].as_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTP_FLOAT:
|
||||||
|
ops[i].type = OPTP_FLOAT;
|
||||||
|
ops[i].as_int = instr->operands[i].as_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTP_PROMISE:
|
||||||
|
UNREACHABLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*opc = MIN(*opc, info->opcount);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,10 +298,10 @@ Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error)
|
|||||||
assert(exeb != NULL);
|
assert(exeb != NULL);
|
||||||
|
|
||||||
if(exeb->promc > 0)
|
if(exeb->promc > 0)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "There are still %d unfulfilled promises", exeb->promc);
|
Error_Report(error, 0, "There are still %d unfulfilled promises", exeb->promc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Executable *exe;
|
Executable *exe;
|
||||||
{
|
{
|
||||||
@@ -313,10 +313,10 @@ Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error)
|
|||||||
void *temp = malloc(sizeof(Executable) + data_size + code_size);
|
void *temp = malloc(sizeof(Executable) + data_size + code_size);
|
||||||
|
|
||||||
if(temp == NULL)
|
if(temp == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
exe = temp;
|
exe = temp;
|
||||||
exe->headl = data_size;
|
exe->headl = data_size;
|
||||||
@@ -369,13 +369,13 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
|||||||
const InstrInfo *info = instr_table + opcode;
|
const InstrInfo *info = instr_table + opcode;
|
||||||
|
|
||||||
if(opc != info->opcount)
|
if(opc != info->opcount)
|
||||||
{
|
{
|
||||||
// ERROR: Too many operands were provided.
|
// ERROR: Too many operands were provided.
|
||||||
Error_Report(error, 0,
|
Error_Report(error, 0,
|
||||||
"Instruction %s expects %d operands, but %d were provided",
|
"Instruction %s expects %d operands, but %d were provided",
|
||||||
info->name, info->opcount, opc);
|
info->name, info->opcount, opc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(opc <= MAX_OPS);
|
assert(opc <= MAX_OPS);
|
||||||
|
|
||||||
@@ -383,106 +383,104 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
|||||||
Instruction *instr = BucketList_Append2(exeb->code, NULL, sizeof(Instruction));
|
Instruction *instr = BucketList_Append2(exeb->code, NULL, sizeof(Instruction));
|
||||||
|
|
||||||
if(instr == NULL)
|
if(instr == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
instr->opcode = opcode;
|
instr->opcode = opcode;
|
||||||
instr->offset = off;
|
instr->offset = off;
|
||||||
instr->length = len;
|
instr->length = len;
|
||||||
|
|
||||||
for(int i = 0; i < opc; i += 1)
|
for(int i = 0; i < opc; i += 1)
|
||||||
|
{
|
||||||
|
// Check that the expected type and the provided one
|
||||||
|
// match, or that the provided type is a promise with
|
||||||
|
// the same size of the expected type.
|
||||||
{
|
{
|
||||||
// Check that the expected type and the provided one
|
OperandType expected_type = info->optypes[i];
|
||||||
// match, or that the provided type is a promise with
|
OperandType provided_type = opv[i].type;
|
||||||
// the same size of the expected type.
|
|
||||||
|
assert(expected_type != OPTP_PROMISE);
|
||||||
|
|
||||||
|
if(provided_type == OPTP_PROMISE)
|
||||||
{
|
{
|
||||||
OperandType expected_type = info->optypes[i];
|
assert(opv[i].as_promise != NULL);
|
||||||
OperandType provided_type = opv[i].type;
|
|
||||||
|
|
||||||
assert(expected_type != OPTP_PROMISE);
|
if(expected_type == OPTP_STRING)
|
||||||
|
|
||||||
if(provided_type == OPTP_PROMISE)
|
|
||||||
{
|
|
||||||
assert(opv[i].as_promise != NULL);
|
|
||||||
|
|
||||||
if(expected_type == OPTP_STRING)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "Promise values can't be provided as string operands");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Promise_Size(opv[i].as_promise) != operand_type_sizes[expected_type])
|
|
||||||
{
|
|
||||||
Error_Report(error, 0,
|
|
||||||
"Provided promise has a value size of %d, "
|
|
||||||
"but since %s %s was expected, the promise "
|
|
||||||
"size must be %d",
|
|
||||||
Promise_Size(opv[i].as_promise),
|
|
||||||
operand_type_arts[expected_type],
|
|
||||||
operand_type_names[expected_type],
|
|
||||||
operand_type_sizes[expected_type]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(expected_type != provided_type)
|
|
||||||
{
|
|
||||||
// ERROR: Wrong operand type provided.
|
|
||||||
Error_Report(error, 0,
|
|
||||||
"Instruction %s expects %s %s as operand %d, but %s %s was provided instead",
|
|
||||||
info->name,
|
|
||||||
operand_type_arts[expected_type],
|
|
||||||
operand_type_names[expected_type],
|
|
||||||
i,
|
|
||||||
operand_type_arts[provided_type],
|
|
||||||
operand_type_names[provided_type]
|
|
||||||
);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the copying of the operands.
|
|
||||||
switch(opv[i].type)
|
|
||||||
{
|
{
|
||||||
case OPTP_STRING:
|
Error_Report(error, 0, "Promise values can't be provided as string operands");
|
||||||
|
return 0;
|
||||||
instr->operands[i].as_int = BucketList_Size(exeb->data);
|
|
||||||
|
|
||||||
if(!BucketList_Append(exeb->data, opv[i].as_string, strlen(opv[i].as_string)+1))
|
|
||||||
{
|
|
||||||
Error_Report(error, 1, "No memory");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_PROMISE:
|
|
||||||
|
|
||||||
assert(info->optypes[i] != OPTP_STRING);
|
|
||||||
|
|
||||||
// This must be incremented before subscribing
|
|
||||||
// since the counter-decrementing callback may
|
|
||||||
// be called immediately if the promise was
|
|
||||||
// already fulfilled.
|
|
||||||
exeb->promc += 1;
|
|
||||||
|
|
||||||
if(!Promise_Subscribe2(opv[i].as_promise, &instr->operands[i], exeb, promise_callback))
|
|
||||||
{
|
|
||||||
Error_Report(error, 1, "No memory");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_INT:
|
|
||||||
instr->operands[i].as_int = opv[i].as_int;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OPTP_FLOAT:
|
|
||||||
instr->operands[i].as_float = opv[i].as_float;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Promise_Size(opv[i].as_promise) != operand_type_sizes[expected_type])
|
||||||
|
{
|
||||||
|
Error_Report(error, 0,
|
||||||
|
"Provided promise has a value size of %d, "
|
||||||
|
"but since %s %s was expected, the promise "
|
||||||
|
"size must be %d",
|
||||||
|
Promise_Size(opv[i].as_promise),
|
||||||
|
operand_type_arts[expected_type],
|
||||||
|
operand_type_names[expected_type],
|
||||||
|
operand_type_sizes[expected_type]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(expected_type != provided_type)
|
||||||
|
{
|
||||||
|
// ERROR: Wrong operand type provided.
|
||||||
|
Error_Report(error, 0,
|
||||||
|
"Instruction %s expects %s %s as operand %d, but %s %s was provided instead",
|
||||||
|
info->name,
|
||||||
|
operand_type_arts[expected_type],
|
||||||
|
operand_type_names[expected_type],
|
||||||
|
i,
|
||||||
|
operand_type_arts[provided_type],
|
||||||
|
operand_type_names[provided_type]
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do the copying of the operands.
|
||||||
|
switch(opv[i].type)
|
||||||
|
{
|
||||||
|
case OPTP_STRING:
|
||||||
|
|
||||||
|
instr->operands[i].as_int = BucketList_Size(exeb->data);
|
||||||
|
|
||||||
|
if(!BucketList_Append(exeb->data, opv[i].as_string, strlen(opv[i].as_string)+1))
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "No memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTP_PROMISE:
|
||||||
|
assert(info->optypes[i] != OPTP_STRING);
|
||||||
|
|
||||||
|
// This must be incremented before subscribing
|
||||||
|
// since the counter-decrementing callback may
|
||||||
|
// be called immediately if the promise was
|
||||||
|
// already fulfilled.
|
||||||
|
exeb->promc += 1;
|
||||||
|
|
||||||
|
if(!Promise_Subscribe2(opv[i].as_promise, &instr->operands[i], exeb, promise_callback))
|
||||||
|
{
|
||||||
|
Error_Report(error, 1, "No memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTP_INT:
|
||||||
|
instr->operands[i].as_int = opv[i].as_int;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTP_FLOAT:
|
||||||
|
instr->operands[i].as_float = opv[i].as_float;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
+556
-557
File diff suppressed because it is too large
Load Diff
+1123
-1144
File diff suppressed because it is too large
Load Diff
+138
-139
@@ -57,14 +57,14 @@ static void print_error(const char *type, Error *error)
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if(error->file != NULL)
|
if(error->file != NULL)
|
||||||
{
|
{
|
||||||
if(error->line > 0 && error->func != NULL)
|
if(error->line > 0 && error->func != NULL)
|
||||||
fprintf(stderr, " (Reported in %s:%d in %s)", error->file, error->line, error->func);
|
fprintf(stderr, " (Reported in %s:%d in %s)", error->file, error->line, error->func);
|
||||||
else if(error->line > 0 && error->func == NULL)
|
else if(error->line > 0 && error->func == NULL)
|
||||||
fprintf(stderr, " (Reported in %s:%d)", error->file, error->line);
|
fprintf(stderr, " (Reported in %s:%d)", error->file, error->line);
|
||||||
else if(error->line < 1 && error->func != NULL)
|
else if(error->line < 1 && error->func != NULL)
|
||||||
fprintf(stderr, " (Reported in %s in %s)", error->file, error->func);
|
fprintf(stderr, " (Reported in %s in %s)", error->file, error->func);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
@@ -78,10 +78,10 @@ static Executable *build(Source *src)
|
|||||||
BPAlloc *alloc = BPAlloc_Init(-1);
|
BPAlloc *alloc = BPAlloc_Init(-1);
|
||||||
|
|
||||||
if(alloc == NULL)
|
if(alloc == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n");
|
fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
Error_Init(&error);
|
Error_Init(&error);
|
||||||
@@ -91,13 +91,13 @@ static Executable *build(Source *src)
|
|||||||
AST *ast = parse(src, alloc, &error);
|
AST *ast = parse(src, alloc, &error);
|
||||||
|
|
||||||
if(ast == NULL)
|
if(ast == NULL)
|
||||||
{
|
{
|
||||||
assert(error.occurred);
|
assert(error.occurred);
|
||||||
print_error("Parsing", &error);
|
print_error("Parsing", &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
BPAlloc_Free(alloc);
|
BPAlloc_Free(alloc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
exe = compile(ast, alloc, &error);
|
exe = compile(ast, alloc, &error);
|
||||||
|
|
||||||
@@ -106,12 +106,12 @@ static Executable *build(Source *src)
|
|||||||
BPAlloc_Free(alloc);
|
BPAlloc_Free(alloc);
|
||||||
|
|
||||||
if(exe == NULL)
|
if(exe == NULL)
|
||||||
{
|
{
|
||||||
assert(error.occurred);
|
assert(error.occurred);
|
||||||
print_error("Compilation", &error);
|
print_error("Compilation", &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return exe;
|
return exe;
|
||||||
}
|
}
|
||||||
@@ -123,18 +123,18 @@ static _Bool interpret(Source *src)
|
|||||||
if(exe == NULL)
|
if(exe == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Runtime *runt = Runtime_New(-1, -1, NULL, NULL);
|
Runtime *runt = Runtime_New(-1, 1024*1024, NULL, NULL);
|
||||||
|
|
||||||
if(runt == NULL)
|
if(runt == NULL)
|
||||||
{
|
{
|
||||||
Error error;
|
Error error;
|
||||||
Error_Init(&error);
|
Error_Init(&error);
|
||||||
Error_Report(&error, 1, "Couldn't initialize runtime");
|
Error_Report(&error, 1, "Couldn't initialize runtime");
|
||||||
print_error(NULL, &error);
|
print_error(NULL, &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
Executable_Free(exe);
|
Executable_Free(exe);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use a [RuntimeError] instead of a simple [Error]
|
// We use a [RuntimeError] instead of a simple [Error]
|
||||||
// because the [RuntimeError] makes a snapshot of the
|
// because the [RuntimeError] makes a snapshot of the
|
||||||
@@ -148,14 +148,14 @@ static _Bool interpret(Source *src)
|
|||||||
Object *bins = Object_NewStaticMap(bins_basic, runt, (Error*) &error);
|
Object *bins = Object_NewStaticMap(bins_basic, runt, (Error*) &error);
|
||||||
|
|
||||||
if(bins == NULL)
|
if(bins == NULL)
|
||||||
{
|
{
|
||||||
assert(error.base.occurred == 1);
|
assert(error.base.occurred == 1);
|
||||||
print_error(NULL, (Error*) &error);
|
print_error(NULL, (Error*) &error);
|
||||||
RuntimeError_Free(&error);
|
RuntimeError_Free(&error);
|
||||||
Executable_Free(exe);
|
Executable_Free(exe);
|
||||||
Runtime_Free(runt);
|
Runtime_Free(runt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime_SetBuiltins(runt, bins);
|
Runtime_SetBuiltins(runt, bins);
|
||||||
|
|
||||||
@@ -165,16 +165,16 @@ static _Bool interpret(Source *src)
|
|||||||
// now because it may be moved by the garbage collector.
|
// now because it may be moved by the garbage collector.
|
||||||
|
|
||||||
if(o == NULL)
|
if(o == NULL)
|
||||||
{
|
{
|
||||||
print_error("Runtime", (Error*) &error);
|
print_error("Runtime", (Error*) &error);
|
||||||
|
|
||||||
if(error.snapshot == NULL)
|
if(error.snapshot == NULL)
|
||||||
fprintf(stderr, "No snapshot available.\n");
|
fprintf(stderr, "No snapshot available.\n");
|
||||||
else
|
else
|
||||||
Snapshot_Print(error.snapshot, stderr);
|
Snapshot_Print(error.snapshot, stderr);
|
||||||
|
|
||||||
RuntimeError_Free(&error);
|
RuntimeError_Free(&error);
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime_Free(runt);
|
Runtime_Free(runt);
|
||||||
Executable_Free(exe);
|
Executable_Free(exe);
|
||||||
@@ -201,12 +201,12 @@ static _Bool interpret_file(const char *file)
|
|||||||
Source *src = Source_FromFile(file, &error);
|
Source *src = Source_FromFile(file, &error);
|
||||||
|
|
||||||
if(src == NULL)
|
if(src == NULL)
|
||||||
{
|
{
|
||||||
assert(error.occurred == 1);
|
assert(error.occurred == 1);
|
||||||
print_error(NULL, &error);
|
print_error(NULL, &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Bool r = interpret(src);
|
_Bool r = interpret(src);
|
||||||
|
|
||||||
@@ -222,12 +222,12 @@ static _Bool interpret_code(const char *code)
|
|||||||
Source *src = Source_FromString(NULL, code, -1, &error);
|
Source *src = Source_FromString(NULL, code, -1, &error);
|
||||||
|
|
||||||
if(src == NULL)
|
if(src == NULL)
|
||||||
{
|
{
|
||||||
assert(error.occurred);
|
assert(error.occurred);
|
||||||
print_error(NULL, &error);
|
print_error(NULL, &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Bool r = interpret(src);
|
_Bool r = interpret(src);
|
||||||
|
|
||||||
@@ -243,12 +243,12 @@ static _Bool disassemble_file(const char *file)
|
|||||||
Source *src = Source_FromFile(file, &error);
|
Source *src = Source_FromFile(file, &error);
|
||||||
|
|
||||||
if(src == NULL)
|
if(src == NULL)
|
||||||
{
|
{
|
||||||
assert(error.occurred == 1);
|
assert(error.occurred == 1);
|
||||||
print_error(NULL, &error);
|
print_error(NULL, &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Bool r = disassemble(src);
|
_Bool r = disassemble(src);
|
||||||
|
|
||||||
@@ -264,12 +264,12 @@ static _Bool disassemble_code(const char *code)
|
|||||||
Source *src = Source_FromString(NULL, code, -1, &error);
|
Source *src = Source_FromString(NULL, code, -1, &error);
|
||||||
|
|
||||||
if(src == NULL)
|
if(src == NULL)
|
||||||
{
|
{
|
||||||
assert(error.occurred);
|
assert(error.occurred);
|
||||||
print_error(NULL, &error);
|
print_error(NULL, &error);
|
||||||
Error_Free(&error);
|
Error_Free(&error);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_Bool r = disassemble(src);
|
_Bool r = disassemble(src);
|
||||||
|
|
||||||
@@ -282,82 +282,81 @@ int main(int argc, char **argv)
|
|||||||
assert(argc > 0);
|
assert(argc > 0);
|
||||||
|
|
||||||
if(argc == 1)
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
// $ noja
|
||||||
|
fprintf(stderr, "Error: Incorrect usage.\n\n");
|
||||||
|
fprintf(stderr, usage);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!strcmp(argv[1], "run"))
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
Error_Init(&error);
|
||||||
|
|
||||||
|
if(argc == 2)
|
||||||
{
|
{
|
||||||
// $ noja
|
Error_Report(&error, 0, "Missing source file");
|
||||||
fprintf(stderr, "Error: Incorrect usage.\n\n");
|
print_error(NULL, &error);
|
||||||
fprintf(stderr, usage);
|
Error_Free(&error);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[1], "run"))
|
_Bool r;
|
||||||
|
|
||||||
|
if(!strcmp(argv[2], "inline"))
|
||||||
{
|
{
|
||||||
Error error;
|
if(argc == 3)
|
||||||
Error_Init(&error);
|
{
|
||||||
|
Error_Report(&error, 0, "Missing source string");
|
||||||
if(argc == 2)
|
print_error(NULL, &error);
|
||||||
{
|
Error_Free(&error);
|
||||||
Error_Report(&error, 0, "Missing source file");
|
return -1;
|
||||||
print_error(NULL, &error);
|
}
|
||||||
Error_Free(&error);
|
r = interpret_code(argv[3]);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r;
|
|
||||||
|
|
||||||
if(!strcmp(argv[2], "inline"))
|
|
||||||
{
|
|
||||||
if(argc == 3)
|
|
||||||
{
|
|
||||||
Error_Report(&error, 0, "Missing source string");
|
|
||||||
print_error(NULL, &error);
|
|
||||||
Error_Free(&error);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = interpret_code(argv[3]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
r = interpret_file(argv[2]);
|
|
||||||
return r ? 0 : -1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
r = interpret_file(argv[2]);
|
||||||
|
return r ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[1], "dis"))
|
if(!strcmp(argv[1], "dis"))
|
||||||
|
{
|
||||||
|
Error error;
|
||||||
|
Error_Init(&error);
|
||||||
|
|
||||||
|
if(argc == 2)
|
||||||
{
|
{
|
||||||
Error error;
|
Error_Report(&error, 0, "Missing source file");
|
||||||
Error_Init(&error);
|
print_error(NULL, &error);
|
||||||
|
Error_Free(&error);
|
||||||
if(argc == 2)
|
return -1;
|
||||||
{
|
|
||||||
Error_Report(&error, 0, "Missing source file");
|
|
||||||
print_error(NULL, &error);
|
|
||||||
Error_Free(&error);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_Bool r;
|
|
||||||
|
|
||||||
if(!strcmp(argv[2], "inline"))
|
|
||||||
{
|
|
||||||
if(argc == 3)
|
|
||||||
{
|
|
||||||
Error_Report(&error, 0, "Missing source string");
|
|
||||||
print_error(NULL, &error);
|
|
||||||
Error_Free(&error);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = disassemble_code(argv[3]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
r = disassemble_file(argv[2]);
|
|
||||||
return r ? 0 : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_Bool r;
|
||||||
|
|
||||||
|
if(!strcmp(argv[2], "inline"))
|
||||||
|
{
|
||||||
|
if(argc == 3)
|
||||||
|
{
|
||||||
|
Error_Report(&error, 0, "Missing source string");
|
||||||
|
print_error(NULL, &error);
|
||||||
|
Error_Free(&error);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = disassemble_code(argv[3]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r = disassemble_file(argv[2]);
|
||||||
|
return r ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(!strcmp(argv[1], "help"))
|
if(!strcmp(argv[1], "help"))
|
||||||
{
|
{
|
||||||
fprintf(stdout, usage);
|
fprintf(stdout, usage);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Error: Incorrect usage.\n\n");
|
fprintf(stderr, "Error: Incorrect usage.\n\n");
|
||||||
fprintf(stderr, usage);
|
fprintf(stderr, usage);
|
||||||
|
|||||||
+156
-154
@@ -137,10 +137,10 @@ Heap *Heap_New(int size)
|
|||||||
heap->collecting = 0;
|
heap->collecting = 0;
|
||||||
|
|
||||||
if(heap->body == NULL)
|
if(heap->body == NULL)
|
||||||
{
|
{
|
||||||
free(heap);
|
free(heap);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USING_VALGRIND
|
#if USING_VALGRIND
|
||||||
VALGRIND_CREATE_MEMPOOL(heap, 0, 0);
|
VALGRIND_CREATE_MEMPOOL(heap, 0, 0);
|
||||||
@@ -160,23 +160,23 @@ void Heap_Free(Heap *heap)
|
|||||||
Error_Init(&error);
|
Error_Init(&error);
|
||||||
|
|
||||||
for(int i = 0; i < heap->pend_used; i += 1)
|
for(int i = 0; i < heap->pend_used; i += 1)
|
||||||
|
{
|
||||||
|
heap->pend[i].destructor(heap->pend[i].object, &error);
|
||||||
|
if(error.occurred)
|
||||||
{
|
{
|
||||||
heap->pend[i].destructor(heap->pend[i].object, &error);
|
// Errors occurred! We can't do anything about
|
||||||
if(error.occurred)
|
// it now though.
|
||||||
{
|
Error_Free(&error);
|
||||||
// Errors occurred! We can't do anything about
|
Error_Init(&error);
|
||||||
// it now though.
|
|
||||||
Error_Free(&error);
|
|
||||||
Error_Init(&error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while(heap->oflow)
|
while(heap->oflow)
|
||||||
{
|
{
|
||||||
OflowAlloc *prev = heap->oflow->prev;
|
OflowAlloc *prev = heap->oflow->prev;
|
||||||
free(heap->oflow);
|
free(heap->oflow);
|
||||||
heap->oflow = prev;
|
heap->oflow = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(heap->pend);
|
free(heap->pend);
|
||||||
free(heap->body);
|
free(heap->body);
|
||||||
@@ -208,42 +208,42 @@ void *Heap_Malloc(Heap *heap, TypeObject *type, Error *err)
|
|||||||
_Bool requires_destruct = type->free != NULL;
|
_Bool requires_destruct = type->free != NULL;
|
||||||
|
|
||||||
if(requires_destruct)
|
if(requires_destruct)
|
||||||
|
{
|
||||||
|
// This type of object requires
|
||||||
|
// a destructor to be called.
|
||||||
|
if(heap->pend == NULL)
|
||||||
{
|
{
|
||||||
// This type of object requires
|
int n = 8;
|
||||||
// a destructor to be called.
|
|
||||||
|
heap->pend = malloc(n * sizeof(PendingDestruct));
|
||||||
|
|
||||||
if(heap->pend == NULL)
|
if(heap->pend == NULL)
|
||||||
{
|
{
|
||||||
int n = 8;
|
Error_Report(err, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
heap->pend = malloc(n * sizeof(PendingDestruct));
|
heap->pend_used = 0;
|
||||||
|
heap->pend_size = n;
|
||||||
if(heap->pend == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(err, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap->pend_used = 0;
|
|
||||||
heap->pend_size = n;
|
|
||||||
}
|
|
||||||
else if(heap->pend_size == heap->pend_used)
|
|
||||||
{
|
|
||||||
int factor = 2;
|
|
||||||
|
|
||||||
void *new_pend = realloc(heap->pend, factor * heap->pend_size * sizeof(PendingDestruct));
|
|
||||||
|
|
||||||
if(new_pend == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(err, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap->pend = new_pend;
|
|
||||||
heap->pend_size *= factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(heap->pend_size > heap->pend_used);
|
|
||||||
}
|
}
|
||||||
|
else if(heap->pend_size == heap->pend_used)
|
||||||
|
{
|
||||||
|
int factor = 2;
|
||||||
|
|
||||||
|
void *new_pend = realloc(heap->pend, factor * heap->pend_size * sizeof(PendingDestruct));
|
||||||
|
|
||||||
|
if(new_pend == NULL)
|
||||||
|
{
|
||||||
|
Error_Report(err, 1, "No memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
heap->pend = new_pend;
|
||||||
|
heap->pend_size *= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(heap->pend_size > heap->pend_used);
|
||||||
|
}
|
||||||
|
|
||||||
int size = type->size;
|
int size = type->size;
|
||||||
|
|
||||||
@@ -290,23 +290,23 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err)
|
|||||||
padding = heap->used - padding;
|
padding = heap->used - padding;
|
||||||
|
|
||||||
if(heap->used + size > heap->size)
|
if(heap->used + size > heap->size)
|
||||||
{
|
{
|
||||||
OflowAlloc *oflow = malloc(sizeof(OflowAlloc) + size);
|
OflowAlloc *oflow = malloc(sizeof(OflowAlloc) + size);
|
||||||
|
|
||||||
if(oflow == 0)
|
if(oflow == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
oflow->prev = heap->oflow;
|
oflow->prev = heap->oflow;
|
||||||
heap->oflow = oflow;
|
heap->oflow = oflow;
|
||||||
|
|
||||||
addr = oflow->body;
|
addr = oflow->body;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(heap->used + size <= heap->size);
|
assert(heap->used + size <= heap->size);
|
||||||
addr = heap->body + heap->used;
|
addr = heap->body + heap->used;
|
||||||
heap->used += size;
|
heap->used += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
heap->total += size + padding;
|
heap->total += size + padding;
|
||||||
|
|
||||||
@@ -326,10 +326,10 @@ _Bool Heap_StartCollection(Heap *heap, Error *error)
|
|||||||
void *new_body = malloc(heap->size);
|
void *new_body = malloc(heap->size);
|
||||||
|
|
||||||
if(new_body == NULL)
|
if(new_body == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
heap->old_body = heap->body;
|
heap->old_body = heap->body;
|
||||||
heap->old_used = heap->used;
|
heap->old_used = heap->used;
|
||||||
@@ -351,57 +351,57 @@ _Bool Heap_StopCollection(Heap *heap)
|
|||||||
assert(heap->collecting == 1);
|
assert(heap->collecting == 1);
|
||||||
|
|
||||||
if(heap->collection_failed)
|
if(heap->collection_failed)
|
||||||
{
|
{
|
||||||
free(heap->old_body);
|
free(heap->old_body);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call destructors here */
|
/* Call destructors here */
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while(i < heap->pend_used)
|
while(i < heap->pend_used)
|
||||||
|
{
|
||||||
|
Object *obj = heap->pend[i].object;
|
||||||
|
|
||||||
|
if(obj->flags & Object_MOVED)
|
||||||
{
|
{
|
||||||
Object *obj = heap->pend[i].object;
|
heap->pend[i].object = ((MovedObject*) heap->pend[i].object)->new_location;
|
||||||
|
i += 1;
|
||||||
if(obj->flags & Object_MOVED)
|
|
||||||
{
|
|
||||||
heap->pend[i].object = ((MovedObject*) heap->pend[i].object)->new_location;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We need to call the destructor.
|
|
||||||
|
|
||||||
heap->pend[i].destructor(obj, heap->error);
|
|
||||||
|
|
||||||
if(heap->error->occurred)
|
|
||||||
return 0; // There will be leaks.
|
|
||||||
|
|
||||||
heap->pend[i] = heap->pend[heap->pend_used-1];
|
|
||||||
heap->pend_used -= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We need to call the destructor.
|
||||||
|
|
||||||
|
heap->pend[i].destructor(obj, heap->error);
|
||||||
|
|
||||||
|
if(heap->error->occurred)
|
||||||
|
return 0; // There will be leaks.
|
||||||
|
|
||||||
|
heap->pend[i] = heap->pend[heap->pend_used-1];
|
||||||
|
heap->pend_used -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(heap->pend_size / 2 > heap->pend_used)
|
if(heap->pend_size / 2 > heap->pend_used)
|
||||||
{
|
{
|
||||||
// Downsize
|
// Downsize
|
||||||
void *temp = realloc(heap->pend, heap->pend_size / 2 * sizeof(PendingDestruct));
|
void *temp = realloc(heap->pend, heap->pend_size / 2 * sizeof(PendingDestruct));
|
||||||
|
|
||||||
if(temp != NULL)
|
if(temp != NULL)
|
||||||
{
|
{
|
||||||
heap->pend = temp;
|
heap->pend = temp;
|
||||||
heap->pend_size /= 2;
|
heap->pend_size /= 2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(heap->old_oflow)
|
while(heap->old_oflow)
|
||||||
{
|
{
|
||||||
OflowAlloc *prev = heap->old_oflow->prev;
|
OflowAlloc *prev = heap->old_oflow->prev;
|
||||||
free(heap->old_oflow);
|
free(heap->old_oflow);
|
||||||
heap->old_oflow = prev;
|
heap->old_oflow = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(heap->old_body);
|
free(heap->old_body);
|
||||||
|
|
||||||
@@ -425,10 +425,10 @@ void Heap_CollectExtension(void **referer, unsigned int size, void *userp)
|
|||||||
void *new_location = Heap_RawMalloc(heap, size, heap->error);
|
void *new_location = Heap_RawMalloc(heap, size, heap->error);
|
||||||
|
|
||||||
if(new_location == NULL)
|
if(new_location == NULL)
|
||||||
{
|
{
|
||||||
heap->collection_failed = 1;
|
heap->collection_failed = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(new_location, old_location, size);
|
memcpy(new_location, old_location, size);
|
||||||
|
|
||||||
@@ -453,62 +453,64 @@ void Heap_CollectReference(Object **referer, void *userp)
|
|||||||
*referer = ((MovedObject*) old_location)->new_location;
|
*referer = ((MovedObject*) old_location)->new_location;
|
||||||
|
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
Object *new_location;
|
||||||
|
|
||||||
|
// This object wasn't moved to
|
||||||
|
// the new heap yet.
|
||||||
|
|
||||||
|
if(old_location->flags & Object_STATIC)
|
||||||
|
|
||||||
|
// The object doesn't need to be moved
|
||||||
|
// since it was statically allocated.
|
||||||
|
new_location = old_location;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Object *new_location;
|
// Get some information.
|
||||||
|
TypeObject *type = old_location->type;
|
||||||
|
int size = type->size;
|
||||||
|
|
||||||
// This object wasn't moved to
|
// Copy the object to a new location.
|
||||||
// the new heap yet.
|
{
|
||||||
|
new_location = Heap_RawMalloc(heap, size, heap->error);
|
||||||
|
|
||||||
if(old_location->flags & Object_STATIC)
|
if(new_location == NULL)
|
||||||
|
|
||||||
// The object doesn't need to be moved
|
|
||||||
// since it was statically allocated.
|
|
||||||
new_location = old_location;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Get some information.
|
heap->collection_failed = 1;
|
||||||
TypeObject *type = old_location->type;
|
return;
|
||||||
int size = type->size;
|
|
||||||
|
|
||||||
// Copy the object to a new location.
|
|
||||||
{
|
|
||||||
new_location = Heap_RawMalloc(heap, size, heap->error);
|
|
||||||
|
|
||||||
if(new_location == NULL)
|
|
||||||
{
|
|
||||||
heap->collection_failed = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(new_location, old_location, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the old location as moved and
|
|
||||||
// leave the reference to the new
|
|
||||||
// location.
|
|
||||||
{
|
|
||||||
old_location->flags |= Object_MOVED;
|
|
||||||
|
|
||||||
assert((int) sizeof(MovedObject) <= size);
|
|
||||||
((MovedObject*) old_location)->new_location = new_location;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap->movedcount += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect the reference to the type.
|
memcpy(new_location, old_location, size);
|
||||||
if((Object*) new_location->type != new_location)
|
}
|
||||||
Heap_CollectReference((Object**) &new_location->type, heap);
|
|
||||||
|
|
||||||
// Collect all of the references to
|
// Set the old location as moved and
|
||||||
// extensions allocate using the GC'd
|
// leave the reference to the new
|
||||||
// heap.
|
// location.
|
||||||
Object_WalkExtensions(new_location, Heap_CollectExtension, heap);
|
{
|
||||||
|
old_location->flags |= Object_MOVED;
|
||||||
|
|
||||||
// Now collect all of the children.
|
assert((int) sizeof(MovedObject) <= size);
|
||||||
Object_WalkReferences(new_location, Heap_CollectReference, heap);
|
((MovedObject*) old_location)->new_location = new_location;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the referer
|
heap->movedcount += 1;
|
||||||
*referer = new_location;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect the reference to the type.
|
||||||
|
if((Object*) new_location->type != new_location)
|
||||||
|
Heap_CollectReference((Object**) &new_location->type, heap);
|
||||||
|
|
||||||
|
// Collect all of the references to
|
||||||
|
// extensions allocate using the GC'd
|
||||||
|
// heap.
|
||||||
|
Object_WalkExtensions(new_location,
|
||||||
|
Heap_CollectExtension, heap);
|
||||||
|
|
||||||
|
// Now collect all of the children.
|
||||||
|
Object_WalkReferences(new_location,
|
||||||
|
Heap_CollectReference, heap);
|
||||||
|
|
||||||
|
// Update the referer
|
||||||
|
*referer = new_location;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+148
-148
@@ -102,22 +102,22 @@ Object *Object_NewBuffer(int size, Heap *heap, Error *error)
|
|||||||
unsigned char *body;
|
unsigned char *body;
|
||||||
|
|
||||||
if(size > THRESHOLD)
|
if(size > THRESHOLD)
|
||||||
{
|
{
|
||||||
body = malloc(sizeof(unsigned char) * size);
|
body = malloc(sizeof(unsigned char) * size);
|
||||||
|
|
||||||
if(body == NULL)
|
if(body == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
body = Heap_RawMalloc(heap, sizeof(unsigned char) * size, error);
|
body = Heap_RawMalloc(heap, sizeof(unsigned char) * size, error);
|
||||||
|
|
||||||
if(body == NULL)
|
if(body == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->size = size;
|
obj->size = size;
|
||||||
obj->body = body;
|
obj->body = body;
|
||||||
@@ -141,112 +141,112 @@ static _Bool buffer_free(Object *self, Error *error)
|
|||||||
Object *Object_SliceBuffer(Object *buffer, int offset, int length, Heap *heap, Error *error)
|
Object *Object_SliceBuffer(Object *buffer, int offset, int length, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
if(buffer->type != &t_buffer && buffer->type != &t_buffer_slice)
|
if(buffer->type != &t_buffer && buffer->type != &t_buffer_slice)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Not a buffer or a buffer slice");
|
Error_Report(error, 0, "Not a buffer or a buffer slice");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferSliceObject *slice;
|
BufferSliceObject *slice;
|
||||||
|
|
||||||
if(buffer->type == &t_buffer)
|
if(buffer->type == &t_buffer)
|
||||||
|
{
|
||||||
|
BufferObject *original = (BufferObject*) buffer;
|
||||||
|
|
||||||
|
if(offset == 0 && length == original->size)
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
slice = (BufferSliceObject*) Heap_Malloc(heap, &t_buffer_slice, error);
|
||||||
|
|
||||||
|
if(slice == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(offset < 0 || offset >= original->size)
|
||||||
{
|
{
|
||||||
BufferObject *original = (BufferObject*) buffer;
|
Error_Report(error, 0, "offset out of range");
|
||||||
|
return NULL;
|
||||||
if(offset == 0 && length == original->size)
|
|
||||||
return buffer;
|
|
||||||
|
|
||||||
slice = (BufferSliceObject*) Heap_Malloc(heap, &t_buffer_slice, error);
|
|
||||||
|
|
||||||
if(slice == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if(offset < 0 || offset >= original->size)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "offset out of range");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(length < 0 || length >= original->size)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "length out of range");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(offset + length > original->size)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "slice out of range");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
slice->sliced = original;
|
|
||||||
slice->offset = offset;
|
|
||||||
slice->length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(length < 0 || length >= original->size)
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "length out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(offset + length > original->size)
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "slice out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
slice->sliced = original;
|
||||||
|
slice->offset = offset;
|
||||||
|
slice->length = length;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
assert(buffer->type == &t_buffer_slice);
|
||||||
|
|
||||||
|
slice = (BufferSliceObject*) Heap_Malloc(heap, &t_buffer_slice, error);
|
||||||
|
|
||||||
|
if(slice == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
BufferSliceObject *original = (BufferSliceObject*) buffer;
|
||||||
|
|
||||||
|
if(offset < 0 || offset >= original->length)
|
||||||
{
|
{
|
||||||
assert(buffer->type == &t_buffer_slice);
|
Error_Report(error, 0, "offset out of range");
|
||||||
|
return NULL;
|
||||||
slice = (BufferSliceObject*) Heap_Malloc(heap, &t_buffer_slice, error);
|
|
||||||
|
|
||||||
if(slice == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
BufferSliceObject *original = (BufferSliceObject*) buffer;
|
|
||||||
|
|
||||||
if(offset < 0 || offset >= original->length)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "offset out of range");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(length < 0 || length >= original->length)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "length out of range");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(offset + length > original->length)
|
|
||||||
{
|
|
||||||
Error_Report(error, 0, "slice out of range");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
slice->sliced = original->sliced;
|
|
||||||
slice->offset = original->offset + offset;
|
|
||||||
slice->length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(length < 0 || length >= original->length)
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "length out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(offset + length > original->length)
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "slice out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
slice->sliced = original->sliced;
|
||||||
|
slice->offset = original->offset + offset;
|
||||||
|
slice->length = length;
|
||||||
|
}
|
||||||
|
|
||||||
return (Object*) slice;
|
return (Object*) slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error)
|
void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error)
|
||||||
{
|
{
|
||||||
if(obj->type != &t_buffer && obj->type != &t_buffer_slice)
|
if(obj->type != &t_buffer && obj->type != &t_buffer_slice)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Not a buffer or a buffer slice");
|
Error_Report(error, 0, "Not a buffer or a buffer slice");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(obj->type == &t_buffer)
|
if(obj->type == &t_buffer)
|
||||||
{
|
{
|
||||||
BufferObject *buffer = (BufferObject*) obj;
|
BufferObject *buffer = (BufferObject*) obj;
|
||||||
|
|
||||||
if(size)
|
if(size)
|
||||||
*size = buffer->size;
|
*size = buffer->size;
|
||||||
|
|
||||||
return buffer->body;
|
return buffer->body;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(obj->type == &t_buffer_slice);
|
assert(obj->type == &t_buffer_slice);
|
||||||
|
|
||||||
BufferSliceObject *slice = (BufferSliceObject*) obj;
|
BufferSliceObject *slice = (BufferSliceObject*) obj;
|
||||||
|
|
||||||
if(size)
|
if(size)
|
||||||
*size = slice->length;
|
*size = slice->length;
|
||||||
|
|
||||||
return slice->sliced->body + slice->offset;
|
return slice->sliced->body + slice->offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error)
|
static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error)
|
||||||
@@ -258,10 +258,10 @@ static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error
|
|||||||
assert(error != NULL);
|
assert(error != NULL);
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
@@ -269,10 +269,10 @@ static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error
|
|||||||
BufferObject *buffer = (BufferObject*) self;
|
BufferObject *buffer = (BufferObject*) self;
|
||||||
|
|
||||||
if(idx < 0 || idx >= buffer->size)
|
if(idx < 0 || idx >= buffer->size)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char byte = buffer->body[idx];
|
unsigned char byte = buffer->body[idx];
|
||||||
|
|
||||||
@@ -288,10 +288,10 @@ static Object *slice_select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
assert(error != NULL);
|
assert(error != NULL);
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
@@ -299,10 +299,10 @@ static Object *slice_select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
BufferSliceObject *slice = (BufferSliceObject*) self;
|
BufferSliceObject *slice = (BufferSliceObject*) self;
|
||||||
|
|
||||||
if(idx < 0 || idx >= slice->length)
|
if(idx < 0 || idx >= slice->length)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char byte = slice->sliced->body[slice->offset + idx];
|
unsigned char byte = slice->sliced->body[slice->offset + idx];
|
||||||
|
|
||||||
@@ -321,27 +321,27 @@ static _Bool buffer_insert(Object *self, Object *key, Object *val, Heap *heap, E
|
|||||||
BufferObject *buffer = (BufferObject*) self;
|
BufferObject *buffer = (BufferObject*) self;
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
|
|
||||||
if(idx < 0 || idx >= buffer->size)
|
if(idx < 0 || idx >= buffer->size)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long int qword = Object_ToInt(val, error);
|
long long int qword = Object_ToInt(val, error);
|
||||||
|
|
||||||
if(qword > 255 || qword < 0)
|
if(qword > 255 || qword < 0)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Not in range [0, 255]");
|
Error_Report(error, 0, "Not in range [0, 255]");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char byte = qword & 0xff;
|
unsigned char byte = qword & 0xff;
|
||||||
|
|
||||||
@@ -364,27 +364,27 @@ static _Bool slice_insert(Object *self, Object *key, Object *val, Heap *heap, Er
|
|||||||
BufferSliceObject *slice = (BufferSliceObject*) self;
|
BufferSliceObject *slice = (BufferSliceObject*) self;
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
|
|
||||||
if(idx < 0 || idx >= slice->length)
|
if(idx < 0 || idx >= slice->length)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long int qword = Object_ToInt(val, error);
|
long long int qword = Object_ToInt(val, error);
|
||||||
|
|
||||||
if(qword > 255 || qword < 0)
|
if(qword > 255 || qword < 0)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Not in range [0, 255]");
|
Error_Report(error, 0, "Not in range [0, 255]");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char byte = qword & 0xff;
|
unsigned char byte = qword & 0xff;
|
||||||
|
|
||||||
@@ -414,26 +414,26 @@ static void print_bytes(FILE *fp, unsigned char *addr, int size)
|
|||||||
fprintf(fp, "[");
|
fprintf(fp, "[");
|
||||||
|
|
||||||
for(int i = 0; i < size; i += 1)
|
for(int i = 0; i < size; i += 1)
|
||||||
{
|
{
|
||||||
unsigned char byte, low, high;
|
unsigned char byte, low, high;
|
||||||
|
|
||||||
byte = addr[i];
|
byte = addr[i];
|
||||||
low = byte & 0xf;
|
low = byte & 0xf;
|
||||||
high = byte >> 4;
|
high = byte >> 4;
|
||||||
|
|
||||||
assert(low < 16);
|
assert(low < 16);
|
||||||
assert(high < 16);
|
assert(high < 16);
|
||||||
|
|
||||||
char c1, c2;
|
char c1, c2;
|
||||||
|
|
||||||
c1 = low < 10 ? low + '0' : low - 10 + 'A';
|
c1 = low < 10 ? low + '0' : low - 10 + 'A';
|
||||||
c2 = high < 10 ? high + '0' : high - 10 + 'A';
|
c2 = high < 10 ? high + '0' : high - 10 + 'A';
|
||||||
|
|
||||||
fprintf(fp, "%c%c", c2, c1);
|
fprintf(fp, "%c%c", c2, c1);
|
||||||
|
|
||||||
if(i+1 < size)
|
if(i+1 < size)
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
}
|
}
|
||||||
fprintf(fp, "]");
|
fprintf(fp, "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -58,10 +58,10 @@ Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *er
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if(parent != NULL && parent->type != &t_closure)
|
if(parent != NULL && parent->type != &t_closure)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Object is not a closure");
|
Error_Report(error, 0, "Object is not a closure");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj->prev = (ClosureObject*) parent;
|
obj->prev = (ClosureObject*) parent;
|
||||||
obj->vars = new_map;
|
obj->vars = new_map;
|
||||||
@@ -76,14 +76,14 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err)
|
|||||||
Object *selected = NULL;
|
Object *selected = NULL;
|
||||||
|
|
||||||
while(closure != NULL && selected == NULL)
|
while(closure != NULL && selected == NULL)
|
||||||
{
|
{
|
||||||
selected = Object_Select(closure->vars, key, heap, err);
|
selected = Object_Select(closure->vars, key, heap, err);
|
||||||
|
|
||||||
if(err->occurred)
|
if(err->occurred)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
closure = closure->prev;
|
closure = closure->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -64,10 +64,10 @@ Object *Object_FromDIR(DIR *handle, Heap *heap, Error *error)
|
|||||||
DIR *Object_ToDIR(Object *obj, Error *error)
|
DIR *Object_ToDIR(Object *obj, Error *error)
|
||||||
{
|
{
|
||||||
if(!Object_IsDir(obj))
|
if(!Object_IsDir(obj))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Object is not a directory");
|
Error_Report(error, 0, "Object is not a directory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((DirObject*) obj)->dir;
|
return ((DirObject*) obj)->dir;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,10 +52,10 @@ _Bool Object_IsFile(Object *obj)
|
|||||||
FILE *Object_ToStream(Object *obj, Error *error)
|
FILE *Object_ToStream(Object *obj, Error *error)
|
||||||
{
|
{
|
||||||
if(!Object_IsFile(obj))
|
if(!Object_IsFile(obj))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Object is not a file");
|
Error_Report(error, 0, "Object is not a file");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((FileObject*) obj)->fp;
|
return ((FileObject*) obj)->fp;
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-35
@@ -89,10 +89,10 @@ static Object *copy(Object *self, Heap *heap, Error *err)
|
|||||||
if(ls2 == NULL) return NULL;
|
if(ls2 == NULL) return NULL;
|
||||||
|
|
||||||
for(int i = 0; i < ls->count; i += 1)
|
for(int i = 0; i < ls->count; i += 1)
|
||||||
{
|
{
|
||||||
ls2->vals[i] = Object_Copy(ls->vals[i], heap, err);
|
ls2->vals[i] = Object_Copy(ls->vals[i], heap, err);
|
||||||
if(err->occurred) return NULL;
|
if(err->occurred) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ls2->count = ls->count;
|
ls2->count = ls->count;
|
||||||
|
|
||||||
@@ -168,10 +168,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
assert(error != NULL);
|
assert(error != NULL);
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
@@ -179,10 +179,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
ListObject *list = (ListObject*) self;
|
ListObject *list = (ListObject*) self;
|
||||||
|
|
||||||
if(idx < 0 || idx >= list->count)
|
if(idx < 0 || idx >= list->count)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list->vals[idx];
|
return list->vals[idx];
|
||||||
}
|
}
|
||||||
@@ -223,33 +223,33 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
ListObject *list = (ListObject*) self;
|
ListObject *list = (ListObject*) self;
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
|
|
||||||
if(idx < 0 || idx > list->count)
|
if(idx < 0 || idx > list->count)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(idx == list->count)
|
if(idx == list->count)
|
||||||
{
|
{
|
||||||
if(list->count == list->capacity)
|
if(list->count == list->capacity)
|
||||||
if(!grow(list, heap, error))
|
if(!grow(list, heap, error))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
list->vals[list->count] = val;
|
list->vals[list->count] = val;
|
||||||
list->count += 1;
|
list->count += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list->vals[idx] = val;
|
list->vals[idx] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -267,11 +267,11 @@ static void print(Object *self, FILE *fp)
|
|||||||
|
|
||||||
fprintf(fp, "[");
|
fprintf(fp, "[");
|
||||||
for(int i = 0; i < list->count; i += 1)
|
for(int i = 0; i < list->count; i += 1)
|
||||||
{
|
{
|
||||||
Object_Print(list->vals[i], fp);
|
Object_Print(list->vals[i], fp);
|
||||||
|
|
||||||
if(i+1 < list->count)
|
if(i+1 < list->count)
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
}
|
}
|
||||||
fprintf(fp, "]");
|
fprintf(fp, "]");
|
||||||
}
|
}
|
||||||
+115
-115
@@ -75,22 +75,22 @@ static Object *copy(Object *self, Heap *heap, Error *err)
|
|||||||
if(m2 == NULL) return NULL;
|
if(m2 == NULL) return NULL;
|
||||||
|
|
||||||
for(int i = 0; i < m1->count; i += 1)
|
for(int i = 0; i < m1->count; i += 1)
|
||||||
{
|
{
|
||||||
Object *key, *key_cpy;
|
Object *key, *key_cpy;
|
||||||
Object *val, *val_cpy;
|
Object *val, *val_cpy;
|
||||||
|
|
||||||
key = m1->keys[i];
|
key = m1->keys[i];
|
||||||
val = m1->vals[i];
|
val = m1->vals[i];
|
||||||
|
|
||||||
key_cpy = Object_Copy(key, heap, err);
|
key_cpy = Object_Copy(key, heap, err);
|
||||||
if(key_cpy == NULL) return NULL;
|
if(key_cpy == NULL) return NULL;
|
||||||
|
|
||||||
val_cpy = Object_Copy(val, heap, err);
|
val_cpy = Object_Copy(val, heap, err);
|
||||||
if(val_cpy == NULL) return NULL;
|
if(val_cpy == NULL) return NULL;
|
||||||
|
|
||||||
if(!Object_Insert(m2, key_cpy, val_cpy, heap, err))
|
if(!Object_Insert(m2, key_cpy, val_cpy, heap, err))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Object*) m2;
|
return (Object*) m2;
|
||||||
}
|
}
|
||||||
@@ -103,8 +103,8 @@ static int hash(Object *self)
|
|||||||
// The hash of the map is the sum of the
|
// The hash of the map is the sum of the
|
||||||
// hashes of each key and each item.
|
// hashes of each key and each item.
|
||||||
for(int i = 0; i < m->count; i += 1)
|
for(int i = 0; i < m->count; i += 1)
|
||||||
h += Object_Hash(m->keys[i])
|
h += Object_Hash(m->keys[i])
|
||||||
+ Object_Hash(m->vals[i]);
|
+ Object_Hash(m->vals[i]);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,10 +151,10 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp),
|
|||||||
MapObject *map = (MapObject*) self;
|
MapObject *map = (MapObject*) self;
|
||||||
|
|
||||||
for(int i = 0; i < map->count; i += 1)
|
for(int i = 0; i < map->count; i += 1)
|
||||||
{
|
{
|
||||||
callback(&map->keys[i], userp);
|
callback(&map->keys[i], userp);
|
||||||
callback(&map->vals[i], userp);
|
callback(&map->vals[i], userp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp)
|
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp)
|
||||||
@@ -187,36 +187,36 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
int i = hash & mask;
|
int i = hash & mask;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
|
{
|
||||||
|
int k = map->mapper[i];
|
||||||
|
|
||||||
|
if(k == -1)
|
||||||
{
|
{
|
||||||
int k = map->mapper[i];
|
// Empty slot.
|
||||||
|
// This key is not present.
|
||||||
if(k == -1)
|
return NULL;
|
||||||
{
|
|
||||||
// Empty slot.
|
|
||||||
// This key is not present.
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Found an item.
|
|
||||||
// Is it the right one?
|
|
||||||
|
|
||||||
assert(k >= 0);
|
|
||||||
|
|
||||||
if(Object_Compare(key, map->keys[k], error))
|
|
||||||
// Found it!
|
|
||||||
return map->vals[k];
|
|
||||||
|
|
||||||
if(error->occurred)
|
|
||||||
// Key doesn't implement compare.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Not the one we wanted.
|
|
||||||
}
|
|
||||||
|
|
||||||
pert >>= 5;
|
|
||||||
i = (i * 5 + pert + 1) & mask;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Found an item.
|
||||||
|
// Is it the right one?
|
||||||
|
|
||||||
|
assert(k >= 0);
|
||||||
|
|
||||||
|
if(Object_Compare(key, map->keys[k], error))
|
||||||
|
// Found it!
|
||||||
|
return map->vals[k];
|
||||||
|
|
||||||
|
if(error->occurred)
|
||||||
|
// Key doesn't implement compare.
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Not the one we wanted.
|
||||||
|
}
|
||||||
|
|
||||||
|
pert >>= 5;
|
||||||
|
i = (i * 5 + pert + 1) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -237,42 +237,42 @@ static _Bool grow(MapObject *map, Heap *heap, Error *error)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for(int i = 0; i < map->count; i += 1)
|
for(int i = 0; i < map->count; i += 1)
|
||||||
{
|
{
|
||||||
keys[i] = map->keys[i];
|
keys[i] = map->keys[i];
|
||||||
vals[i] = map->vals[i];
|
vals[i] = map->vals[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < new_mapper_size; i += 1)
|
for(int i = 0; i < new_mapper_size; i += 1)
|
||||||
mapper[i] = -1;
|
mapper[i] = -1;
|
||||||
|
|
||||||
// Rehash everything.
|
// Rehash everything.
|
||||||
for(int i = 0; i < map->count; i += 1)
|
for(int i = 0; i < map->count; i += 1)
|
||||||
|
{
|
||||||
|
// This won't trigger an error because the key
|
||||||
|
// surely has a hash method since we already
|
||||||
|
// hashed it once.
|
||||||
|
int hash = Object_Hash(keys[i]);
|
||||||
|
|
||||||
|
int mask = new_mapper_size - 1;
|
||||||
|
int pert = hash;
|
||||||
|
|
||||||
|
int j = hash & mask;
|
||||||
|
|
||||||
|
while(1)
|
||||||
{
|
{
|
||||||
// This won't trigger an error because the key
|
if(mapper[j] == -1)
|
||||||
// surely has a hash method since we already
|
{
|
||||||
// hashed it once.
|
// No collision.
|
||||||
int hash = Object_Hash(keys[i]);
|
// Insert here.
|
||||||
|
mapper[j] = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
int mask = new_mapper_size - 1;
|
// Collided. Find a new place.
|
||||||
int pert = hash;
|
pert >>= 5;
|
||||||
|
j = (j * 5 + pert + 1) & mask;
|
||||||
int j = hash & mask;
|
|
||||||
|
|
||||||
while(1)
|
|
||||||
{
|
|
||||||
if(mapper[j] == -1)
|
|
||||||
{
|
|
||||||
// No collision.
|
|
||||||
// Insert here.
|
|
||||||
mapper[j] = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collided. Find a new place.
|
|
||||||
pert >>= 5;
|
|
||||||
j = (j * 5 + pert + 1) & mask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Done.
|
// Done.
|
||||||
map->mapper = mapper;
|
map->mapper = mapper;
|
||||||
@@ -304,45 +304,45 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
int i = hash & mask;
|
int i = hash & mask;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
|
{
|
||||||
|
int k = map->mapper[i];
|
||||||
|
|
||||||
|
if(k == -1)
|
||||||
{
|
{
|
||||||
int k = map->mapper[i];
|
// Empty slot. We can insert it here.
|
||||||
|
Object *key_copy = Object_Copy(key, heap, error);
|
||||||
|
|
||||||
if(k == -1)
|
if(key_copy == NULL)
|
||||||
{
|
return NULL;
|
||||||
// Empty slot. We can insert it here.
|
|
||||||
Object *key_copy = Object_Copy(key, heap, error);
|
|
||||||
|
|
||||||
if(key_copy == NULL)
|
map->mapper[i] = map->count;
|
||||||
return NULL;
|
map->keys[map->count] = key_copy;
|
||||||
|
map->vals[map->count] = val;
|
||||||
map->mapper[i] = map->count;
|
map->count += 1;
|
||||||
map->keys[map->count] = key_copy;
|
return 1;
|
||||||
map->vals[map->count] = val;
|
|
||||||
map->count += 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(k >= 0);
|
|
||||||
|
|
||||||
if(Object_Compare(key, map->keys[k], error))
|
|
||||||
{
|
|
||||||
// Already inserted.
|
|
||||||
// Overwrite the value.
|
|
||||||
map->vals[k] = val;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(error->occurred)
|
|
||||||
// Key doesn't implement compare.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Collision.
|
|
||||||
}
|
|
||||||
|
|
||||||
pert >>= 5;
|
|
||||||
i = (i * 5 + pert + 1) & mask;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(k >= 0);
|
||||||
|
|
||||||
|
if(Object_Compare(key, map->keys[k], error))
|
||||||
|
{
|
||||||
|
// Already inserted.
|
||||||
|
// Overwrite the value.
|
||||||
|
map->vals[k] = val;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(error->occurred)
|
||||||
|
// Key doesn't implement compare.
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Collision.
|
||||||
|
}
|
||||||
|
|
||||||
|
pert >>= 5;
|
||||||
|
i = (i * 5 + pert + 1) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
UNREACHABLE;
|
UNREACHABLE;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -361,13 +361,13 @@ static void print(Object *self, FILE *fp)
|
|||||||
|
|
||||||
fprintf(fp, "{");
|
fprintf(fp, "{");
|
||||||
for(int i = 0; i < map->count; i += 1)
|
for(int i = 0; i < map->count; i += 1)
|
||||||
{
|
{
|
||||||
Object_Print(map->keys[i], fp);
|
Object_Print(map->keys[i], fp);
|
||||||
fprintf(fp, ": ");
|
fprintf(fp, ": ");
|
||||||
Object_Print(map->vals[i], fp);
|
Object_Print(map->vals[i], fp);
|
||||||
|
|
||||||
if(i+1 < map->count)
|
if(i+1 < map->count)
|
||||||
fprintf(fp, ", ");
|
fprintf(fp, ", ");
|
||||||
}
|
}
|
||||||
fprintf(fp, "}");
|
fprintf(fp, "}");
|
||||||
}
|
}
|
||||||
+21
-18
@@ -68,6 +68,9 @@ static TypeObject t_string = {
|
|||||||
|
|
||||||
static int char_index_to_offset(StringObject *str, int idx)
|
static int char_index_to_offset(StringObject *str, int idx)
|
||||||
{
|
{
|
||||||
|
if(str->count == str->bytes)
|
||||||
|
return idx;
|
||||||
|
|
||||||
// Iterate over a string to find the first byte of
|
// Iterate over a string to find the first byte of
|
||||||
// the utf-8 character number [idx].
|
// the utf-8 character number [idx].
|
||||||
|
|
||||||
@@ -75,13 +78,13 @@ static int char_index_to_offset(StringObject *str, int idx)
|
|||||||
last_code_len = 0;
|
last_code_len = 0;
|
||||||
|
|
||||||
while(idx > 0)
|
while(idx > 0)
|
||||||
{
|
{
|
||||||
last_code_len = utf8_sequence_to_utf32_codepoint(str->body + scanned_bytes, str->bytes - scanned_bytes, NULL);
|
last_code_len = utf8_sequence_to_utf32_codepoint(str->body + scanned_bytes, str->bytes - scanned_bytes, NULL);
|
||||||
scanned_bytes += last_code_len;
|
scanned_bytes += last_code_len;
|
||||||
idx -= 1;
|
idx -= 1;
|
||||||
|
|
||||||
assert(scanned_bytes <= str->bytes);
|
assert(scanned_bytes <= str->bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(idx == 0);
|
assert(idx == 0);
|
||||||
return scanned_bytes;
|
return scanned_bytes;
|
||||||
@@ -93,10 +96,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
assert(key != NULL && heap != NULL && error != NULL);
|
assert(key != NULL && heap != NULL && error != NULL);
|
||||||
|
|
||||||
if(!Object_IsInt(key))
|
if(!Object_IsInt(key))
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Non integer key");
|
Error_Report(error, 0, "Non integer key");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = Object_ToInt(key, error);
|
int idx = Object_ToInt(key, error);
|
||||||
assert(error->occurred == 0);
|
assert(error->occurred == 0);
|
||||||
@@ -104,10 +107,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
StringObject *str = (StringObject*) self;
|
StringObject *str = (StringObject*) self;
|
||||||
|
|
||||||
if(idx < 0 || idx >= str->count)
|
if(idx < 0 || idx >= str->count)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Out of range index");
|
Error_Report(error, 0, "Out of range index");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int byteoffset = char_index_to_offset(str, idx);
|
int byteoffset = char_index_to_offset(str, idx);
|
||||||
int codelength = utf8_sequence_to_utf32_codepoint(str->body + byteoffset, str->bytes - byteoffset, NULL);
|
int codelength = utf8_sequence_to_utf32_codepoint(str->body + byteoffset, str->bytes - byteoffset, NULL);
|
||||||
@@ -143,10 +146,10 @@ Object *Object_FromString(const char *str, int len, Heap *heap, Error *error)
|
|||||||
int count = utf8_strlen(str, len);
|
int count = utf8_strlen(str, len);
|
||||||
|
|
||||||
if(count < 0)
|
if(count < 0)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Invalid UTF-8 sequence");
|
Error_Report(error, 0, "Invalid UTF-8 sequence");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringObject *strobj = Heap_Malloc(heap, &t_string, error);
|
StringObject *strobj = Heap_Malloc(heap, &t_string, error);
|
||||||
|
|
||||||
|
|||||||
+72
-72
@@ -86,10 +86,10 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err)
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->deepsize == NULL)
|
if(type->deepsize == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->deepsize(obj);
|
return type->deepsize(obj);
|
||||||
}
|
}
|
||||||
@@ -112,10 +112,10 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err)
|
|||||||
assert(type != NULL);
|
assert(type != NULL);
|
||||||
|
|
||||||
if(type->copy == NULL)
|
if(type->copy == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->copy(obj, heap, err);
|
return type->copy(obj, heap, err);
|
||||||
}
|
}
|
||||||
@@ -129,10 +129,10 @@ Object *Object_Call(Object *obj, Object **argv, unsigned int argc, Heap *heap, E
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->call == NULL)
|
if(type->call == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->call(obj, argv, argc, heap, err);
|
return type->call(obj, argv, argc, heap, err);
|
||||||
}
|
}
|
||||||
@@ -160,10 +160,10 @@ Object *Object_Select(Object *coll, Object *key, Heap *heap, Error *err)
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->select == NULL)
|
if(type->select == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->select(coll, key, heap, err);
|
return type->select(coll, key, heap, err);
|
||||||
}
|
}
|
||||||
@@ -178,10 +178,10 @@ Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err)
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->delete == NULL)
|
if(type->delete == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->delete(coll, key, heap, err);
|
return type->delete(coll, key, heap, err);
|
||||||
}
|
}
|
||||||
@@ -196,10 +196,10 @@ _Bool Object_Insert(Object *coll, Object *key, Object *val, Heap *heap, Error *e
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->insert == NULL)
|
if(type->insert == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->insert(coll, key, val, heap, err);
|
return type->insert(coll, key, val, heap, err);
|
||||||
}
|
}
|
||||||
@@ -213,10 +213,10 @@ int Object_Count(Object *coll, Error *err)
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->count == NULL)
|
if(type->count == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->count(coll);
|
return type->count(coll);
|
||||||
}
|
}
|
||||||
@@ -230,10 +230,10 @@ Object *Object_Next(Object *iter, Heap *heap, Error *err)
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->next == NULL)
|
if(type->next == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->next(iter, heap, err);
|
return type->next(iter, heap, err);
|
||||||
}
|
}
|
||||||
@@ -247,10 +247,10 @@ Object *Object_Prev(Object *iter, Heap *heap, Error *err)
|
|||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->prev == NULL)
|
if(type->prev == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->prev(iter, heap, err);
|
return type->prev(iter, heap, err);
|
||||||
}
|
}
|
||||||
@@ -289,19 +289,19 @@ long long int Object_ToInt(Object *obj, Error *err)
|
|||||||
assert(obj);
|
assert(obj);
|
||||||
|
|
||||||
if(!Object_IsInt(obj))
|
if(!Object_IsInt(obj))
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object is not an integer");
|
Error_Report(err, 0, "Object is not an integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeObject *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_int == NULL)
|
if(type->to_int == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->to_int(obj, err);
|
return type->to_int(obj, err);
|
||||||
}
|
}
|
||||||
@@ -312,19 +312,19 @@ _Bool Object_ToBool(Object *obj, Error *err)
|
|||||||
assert(obj);
|
assert(obj);
|
||||||
|
|
||||||
if(!Object_IsBool(obj))
|
if(!Object_IsBool(obj))
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object is not a boolean");
|
Error_Report(err, 0, "Object is not a boolean");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeObject *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_bool == NULL)
|
if(type->to_bool == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->to_bool(obj, err);
|
return type->to_bool(obj, err);
|
||||||
}
|
}
|
||||||
@@ -335,19 +335,19 @@ double Object_ToFloat(Object *obj, Error *err)
|
|||||||
assert(obj);
|
assert(obj);
|
||||||
|
|
||||||
if(!Object_IsFloat(obj))
|
if(!Object_IsFloat(obj))
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object is not a floating");
|
Error_Report(err, 0, "Object is not a floating");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeObject *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_float == NULL)
|
if(type->to_float == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->to_float(obj, err);
|
return type->to_float(obj, err);
|
||||||
}
|
}
|
||||||
@@ -358,19 +358,19 @@ const char *Object_ToString(Object *obj, int *size, Heap *heap, Error *err)
|
|||||||
assert(obj != NULL);
|
assert(obj != NULL);
|
||||||
|
|
||||||
if(!Object_IsString(obj))
|
if(!Object_IsString(obj))
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object is not a string");
|
Error_Report(err, 0, "Object is not a string");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeObject *type = Object_GetType(obj);
|
const TypeObject *type = Object_GetType(obj);
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
if(type->to_string == NULL)
|
if(type->to_string == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type->to_string(obj, size, heap, err);
|
return type->to_string(obj, size, heap, err);
|
||||||
}
|
}
|
||||||
@@ -385,10 +385,10 @@ _Bool Object_Compare(Object *obj1, Object *obj2, Error *error)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(obj1->type->op_eql == NULL)
|
if(obj1->type->op_eql == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 0, "Object %s doesn't implement %s", Object_GetName(obj1), __func__);
|
Error_Report(error, 0, "Object %s doesn't implement %s", Object_GetName(obj1), __func__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj1->type->op_eql(obj1, obj2);
|
return obj1->type->op_eql(obj1, obj2);
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-34
@@ -59,9 +59,7 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp),
|
|||||||
|
|
||||||
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
|
static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error)
|
||||||
{
|
{
|
||||||
assert(self != NULL);
|
assert(self != NULL && heap != NULL && error != NULL);
|
||||||
assert(heap != NULL);
|
|
||||||
assert(error != NULL);
|
|
||||||
|
|
||||||
FunctionObject *func = (FunctionObject*) self;
|
FunctionObject *func = (FunctionObject*) self;
|
||||||
|
|
||||||
@@ -76,36 +74,36 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
|||||||
int expected_argc = func->argc;
|
int expected_argc = func->argc;
|
||||||
|
|
||||||
if(expected_argc < (int) argc)
|
if(expected_argc < (int) argc)
|
||||||
{
|
{
|
||||||
// Nothing to be done. By using
|
// Nothing to be done. By using
|
||||||
// the right argc the additional
|
// the right argc the additional
|
||||||
// arguments are ignored implicitly.
|
// arguments are ignored implicitly.
|
||||||
argv2 = argv;
|
argv2 = argv;
|
||||||
}
|
}
|
||||||
else if(expected_argc > (int) argc)
|
else if(expected_argc > (int) argc)
|
||||||
|
{
|
||||||
|
// Some arguments are missing.
|
||||||
|
argv2 = malloc(sizeof(Object*) * expected_argc);
|
||||||
|
|
||||||
|
if(argv2 == NULL)
|
||||||
{
|
{
|
||||||
// Some arguments are missing.
|
Error_Report(error, 1, "No memory");
|
||||||
argv2 = malloc(sizeof(Object*) * expected_argc);
|
return NULL;
|
||||||
|
|
||||||
if(argv2 == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the provided arguments.
|
|
||||||
for(int i = 0; i < (int) argc; i += 1)
|
|
||||||
argv2[i] = argv[i];
|
|
||||||
|
|
||||||
// Set the unspecified arguments to none.
|
|
||||||
for(int i = argc; i < expected_argc; i += 1)
|
|
||||||
{
|
|
||||||
argv2[i] = Object_NewNone(heap, error);
|
|
||||||
|
|
||||||
if(argv2[i] == NULL)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the provided arguments.
|
||||||
|
for(int i = 0; i < (int) argc; i += 1)
|
||||||
|
argv2[i] = argv[i];
|
||||||
|
|
||||||
|
// Set the unspecified arguments to none.
|
||||||
|
for(int i = argc; i < expected_argc; i += 1)
|
||||||
|
{
|
||||||
|
argv2[i] = Object_NewNone(heap, error);
|
||||||
|
|
||||||
|
if(argv2[i] == NULL)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
// The right amount of arguments was provided.
|
// The right amount of arguments was provided.
|
||||||
argv2 = argv;
|
argv2 = argv;
|
||||||
@@ -176,10 +174,10 @@ Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, in
|
|||||||
Executable *exe_copy = Executable_Copy(exe);
|
Executable *exe_copy = Executable_Copy(exe);
|
||||||
|
|
||||||
if(exe_copy == NULL)
|
if(exe_copy == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "Failed to copy executable");
|
Error_Report(error, 1, "Failed to copy executable");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
func->runtime = runtime;
|
func->runtime = runtime;
|
||||||
func->exe = exe_copy;
|
func->exe = exe_copy;
|
||||||
|
|||||||
+38
-38
@@ -64,48 +64,48 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap,
|
|||||||
int expected_argc = func->argc;
|
int expected_argc = func->argc;
|
||||||
|
|
||||||
if(expected_argc < 0 || expected_argc == (int) argc)
|
if(expected_argc < 0 || expected_argc == (int) argc)
|
||||||
{
|
{
|
||||||
// The function is variadic or the right
|
// The function is variadic or the right
|
||||||
// amount of arguments was provided.
|
// amount of arguments was provided.
|
||||||
argv2 = argv;
|
argv2 = argv;
|
||||||
argc2 = argc;
|
argc2 = argc;
|
||||||
}
|
}
|
||||||
else if(expected_argc < (int) argc)
|
else if(expected_argc < (int) argc)
|
||||||
{
|
{
|
||||||
// Nothing to be done. By using
|
// Nothing to be done. By using
|
||||||
// the right argc the additional
|
// the right argc the additional
|
||||||
// arguments are ignored implicitly.
|
// arguments are ignored implicitly.
|
||||||
argv2 = argv;
|
argv2 = argv;
|
||||||
argc2 = expected_argc;
|
argc2 = expected_argc;
|
||||||
}
|
}
|
||||||
else if(expected_argc > (int) argc)
|
else if(expected_argc > (int) argc)
|
||||||
|
{
|
||||||
|
// Some arguments are missing.
|
||||||
|
argv2 = malloc(sizeof(Object*) * expected_argc);
|
||||||
|
argc2 = expected_argc;
|
||||||
|
|
||||||
|
if(argv2 == NULL)
|
||||||
{
|
{
|
||||||
// Some arguments are missing.
|
Error_Report(error, 1, "No memory");
|
||||||
argv2 = malloc(sizeof(Object*) * expected_argc);
|
return NULL;
|
||||||
argc2 = expected_argc;
|
|
||||||
|
|
||||||
if(argv2 == NULL)
|
|
||||||
{
|
|
||||||
Error_Report(error, 1, "No memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the provided arguments.
|
|
||||||
for(int i = 0; i < (int) argc; i += 1)
|
|
||||||
argv2[i] = argv[i];
|
|
||||||
|
|
||||||
// Set the unspecified arguments to none.
|
|
||||||
for(int i = argc; i < expected_argc; i += 1)
|
|
||||||
{
|
|
||||||
argv2[i] = Object_NewNone(heap, error);
|
|
||||||
|
|
||||||
if(argv2[i] == NULL)
|
|
||||||
{
|
|
||||||
free(argv2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the provided arguments.
|
||||||
|
for(int i = 0; i < (int) argc; i += 1)
|
||||||
|
argv2[i] = argv[i];
|
||||||
|
|
||||||
|
// Set the unspecified arguments to none.
|
||||||
|
for(int i = argc; i < expected_argc; i += 1)
|
||||||
|
{
|
||||||
|
argv2[i] = Object_NewNone(heap, error);
|
||||||
|
|
||||||
|
if(argv2[i] == NULL)
|
||||||
|
{
|
||||||
|
free(argv2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else UNREACHABLE;
|
else UNREACHABLE;
|
||||||
|
|
||||||
assert(func->callback != NULL);
|
assert(func->callback != NULL);
|
||||||
|
|||||||
+15
-15
@@ -120,22 +120,22 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
|||||||
|
|
||||||
for(int i = 0; map->slots[i].name != NULL; i += 1)
|
for(int i = 0; map->slots[i].name != NULL; i += 1)
|
||||||
if(!strcmp(name, map->slots[i].name))
|
if(!strcmp(name, map->slots[i].name))
|
||||||
|
{
|
||||||
|
StaticMapSlot slot = map->slots[i];
|
||||||
|
Object *obj;
|
||||||
|
switch(slot.kind)
|
||||||
{
|
{
|
||||||
StaticMapSlot slot = map->slots[i];
|
case SM_BOOL: return Object_FromBool(slot.as_bool, heap, error);
|
||||||
Object *obj;
|
case SM_INT: return Object_FromInt(slot.as_int, heap, error);
|
||||||
switch(slot.kind)
|
case SM_FLOAT: return Object_FromFloat(slot.as_float, heap, error);
|
||||||
{
|
case SM_FUNCT: return Object_FromNativeFunction(map->runt, slot.as_funct, slot.argc, heap, error);
|
||||||
case SM_BOOL: return Object_FromBool(slot.as_bool, heap, error);
|
case SM_STRING: return Object_FromString(slot.as_string, slot.length, heap, error);
|
||||||
case SM_INT: return Object_FromInt(slot.as_int, heap, error);
|
case SM_SMAP: return Object_NewStaticMap(slot.as_smap, map->runt, error);
|
||||||
case SM_FLOAT: return Object_FromFloat(slot.as_float, heap, error);
|
case SM_NONE: return Object_NewNone(heap, error);
|
||||||
case SM_FUNCT: return Object_FromNativeFunction(map->runt, slot.as_funct, slot.argc, heap, error);
|
case SM_TYPE: return (Object*) slot.as_type;
|
||||||
case SM_STRING: return Object_FromString(slot.as_string, slot.length, heap, error);
|
default: assert(0); break;
|
||||||
case SM_SMAP: return Object_NewStaticMap(slot.as_smap, map->runt, error);
|
|
||||||
case SM_NONE: return Object_NewNone(heap, error);
|
|
||||||
case SM_TYPE: return (Object*) slot.as_type;
|
|
||||||
default: assert(0); break;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
+906
-907
File diff suppressed because it is too large
Load Diff
+32
-32
@@ -80,11 +80,11 @@ BPAlloc *BPAlloc_Init2(int first_size, int chunk_size,
|
|||||||
first_size = chunk_size;
|
first_size = chunk_size;
|
||||||
|
|
||||||
if(fn_malloc == NULL)
|
if(fn_malloc == NULL)
|
||||||
{
|
{
|
||||||
userp = NULL;
|
userp = NULL;
|
||||||
fn_malloc = default_fn_malloc;
|
fn_malloc = default_fn_malloc;
|
||||||
fn_free = default_fn_free;
|
fn_free = default_fn_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *temp = fn_malloc(userp, sizeof(BPAlloc) + sizeof(BPAllocChunk) + first_size + PADDING);
|
void *temp = fn_malloc(userp, sizeof(BPAlloc) + sizeof(BPAllocChunk) + first_size + PADDING);
|
||||||
|
|
||||||
@@ -124,11 +124,11 @@ BPAlloc *BPAlloc_Init3(void *mem, int mem_size, int chunk_size,
|
|||||||
chunk_size = CHUNK_SIZE;
|
chunk_size = CHUNK_SIZE;
|
||||||
|
|
||||||
if(fn_malloc == NULL)
|
if(fn_malloc == NULL)
|
||||||
{
|
{
|
||||||
userp = NULL;
|
userp = NULL;
|
||||||
fn_malloc = default_fn_malloc;
|
fn_malloc = default_fn_malloc;
|
||||||
fn_free = default_fn_free;
|
fn_free = default_fn_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
int required = sizeof(BPAlloc)
|
int required = sizeof(BPAlloc)
|
||||||
+ sizeof(BPAllocChunk)
|
+ sizeof(BPAllocChunk)
|
||||||
@@ -170,14 +170,14 @@ void BPAlloc_Free(BPAlloc *alloc)
|
|||||||
BPAllocChunk *chunk = alloc->tail;
|
BPAllocChunk *chunk = alloc->tail;
|
||||||
|
|
||||||
while(chunk->prev)
|
while(chunk->prev)
|
||||||
{
|
{
|
||||||
BPAllocChunk *prev = chunk->prev;
|
BPAllocChunk *prev = chunk->prev;
|
||||||
|
|
||||||
if(alloc->fn_free)
|
if(alloc->fn_free)
|
||||||
alloc->fn_free(alloc->userp, chunk);
|
alloc->fn_free(alloc->userp, chunk);
|
||||||
|
|
||||||
chunk = prev;
|
chunk = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(alloc->flags & FG_STATIC))
|
if(!(alloc->flags & FG_STATIC))
|
||||||
if(alloc->fn_free)
|
if(alloc->fn_free)
|
||||||
@@ -195,26 +195,26 @@ void *BPAlloc_Malloc(BPAlloc *alloc, int req_size)
|
|||||||
alloc->used = (alloc->used & ~7) + 8;
|
alloc->used = (alloc->used & ~7) + 8;
|
||||||
|
|
||||||
if(alloc->used + req_size > alloc->size)
|
if(alloc->used + req_size > alloc->size)
|
||||||
{
|
{
|
||||||
// If the chunk size is lower than the
|
// If the chunk size is lower than the
|
||||||
// requested size, then set the chunk
|
// requested size, then set the chunk
|
||||||
// size to the requested size.
|
// size to the requested size.
|
||||||
int chunk_size = MAX(alloc->minsize, req_size + PADDING);
|
int chunk_size = MAX(alloc->minsize, req_size + PADDING);
|
||||||
|
|
||||||
assert(alloc->fn_malloc != NULL);
|
assert(alloc->fn_malloc != NULL);
|
||||||
BPAllocChunk *chunk = alloc->fn_malloc(alloc->userp, sizeof(BPAllocChunk) + chunk_size);
|
BPAllocChunk *chunk = alloc->fn_malloc(alloc->userp, sizeof(BPAllocChunk) + chunk_size);
|
||||||
|
|
||||||
if(chunk == NULL)
|
if(chunk == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
chunk->prev = alloc->tail;
|
chunk->prev = alloc->tail;
|
||||||
alloc->tail = chunk;
|
alloc->tail = chunk;
|
||||||
alloc->size = chunk_size;
|
alloc->size = chunk_size;
|
||||||
alloc->used = PADDING;
|
alloc->used = PADDING;
|
||||||
|
|
||||||
if(alloc->used & 7)
|
if(alloc->used & 7)
|
||||||
alloc->used = (alloc->used & ~7) + 8;
|
alloc->used = (alloc->used & ~7) + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *addr = alloc->tail->body + alloc->used;
|
void *addr = alloc->tail->body + alloc->used;
|
||||||
|
|
||||||
|
|||||||
+45
-45
@@ -109,42 +109,42 @@ _Bool BucketList_Append(BucketList *blist, const void *data, int size)
|
|||||||
int not_copied_yet = size;
|
int not_copied_yet = size;
|
||||||
|
|
||||||
while(not_copied_yet > 0)
|
while(not_copied_yet > 0)
|
||||||
|
{
|
||||||
|
// Copy until there's nothing left
|
||||||
|
// or until the current bucket is
|
||||||
|
// full. If the bucket is already
|
||||||
|
// full, add another one.
|
||||||
|
|
||||||
|
int left_in_bucket = blist->tail->size - blist->tail->used;
|
||||||
|
|
||||||
|
if(left_in_bucket == 0)
|
||||||
{
|
{
|
||||||
// Copy until there's nothing left
|
Bucket *new_bucket = make_bucket(blist->alloc, MIN_BUCKET_SIZE);
|
||||||
// or until the current bucket is
|
|
||||||
// full. If the bucket is already
|
|
||||||
// full, add another one.
|
|
||||||
|
|
||||||
int left_in_bucket = blist->tail->size - blist->tail->used;
|
if(new_bucket == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(left_in_bucket == 0)
|
append_bucket(blist, new_bucket);
|
||||||
{
|
|
||||||
Bucket *new_bucket = make_bucket(blist->alloc, MIN_BUCKET_SIZE);
|
|
||||||
|
|
||||||
if(new_bucket == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
append_bucket(blist, new_bucket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decide how much to copy.
|
|
||||||
int copying = MIN(not_copied_yet, left_in_bucket);
|
|
||||||
|
|
||||||
// Copy into the bucket.
|
|
||||||
{
|
|
||||||
char *dst = blist->tail->body + blist->tail->used;
|
|
||||||
|
|
||||||
if(data == NULL)
|
|
||||||
memset(dst, 0, copying);
|
|
||||||
else
|
|
||||||
memcpy(dst, data + size - not_copied_yet, copying);
|
|
||||||
|
|
||||||
blist->tail->used += copying;
|
|
||||||
}
|
|
||||||
|
|
||||||
not_copied_yet -= copying;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decide how much to copy.
|
||||||
|
int copying = MIN(not_copied_yet, left_in_bucket);
|
||||||
|
|
||||||
|
// Copy into the bucket.
|
||||||
|
{
|
||||||
|
char *dst = blist->tail->body + blist->tail->used;
|
||||||
|
|
||||||
|
if(data == NULL)
|
||||||
|
memset(dst, 0, copying);
|
||||||
|
else
|
||||||
|
memcpy(dst, data + size - not_copied_yet, copying);
|
||||||
|
|
||||||
|
blist->tail->used += copying;
|
||||||
|
}
|
||||||
|
|
||||||
|
not_copied_yet -= copying;
|
||||||
|
}
|
||||||
|
|
||||||
blist->size += size;
|
blist->size += size;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -158,16 +158,16 @@ void *BucketList_Append2(BucketList *blist, const void *data, int size)
|
|||||||
// current bucket, add another one with
|
// current bucket, add another one with
|
||||||
// enough space.
|
// enough space.
|
||||||
if(blist->tail->used + size > blist->tail->size)
|
if(blist->tail->used + size > blist->tail->size)
|
||||||
{
|
{
|
||||||
int bucket_size = MAX(MIN_BUCKET_SIZE, size);
|
int bucket_size = MAX(MIN_BUCKET_SIZE, size);
|
||||||
|
|
||||||
Bucket *new_bucket = make_bucket(blist->alloc, bucket_size);
|
Bucket *new_bucket = make_bucket(blist->alloc, bucket_size);
|
||||||
|
|
||||||
if(new_bucket == NULL)
|
if(new_bucket == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
append_bucket(blist, new_bucket);
|
append_bucket(blist, new_bucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *addr = blist->tail->body + blist->tail->used;
|
void *addr = blist->tail->body + blist->tail->used;
|
||||||
|
|
||||||
@@ -195,15 +195,15 @@ void BucketList_Copy(BucketList *blist, void *dest, int len)
|
|||||||
Bucket *bucket = blist->head;
|
Bucket *bucket = blist->head;
|
||||||
|
|
||||||
while(bucket && copied < len)
|
while(bucket && copied < len)
|
||||||
{
|
{
|
||||||
int copying = MIN(len - copied, bucket->used);
|
int copying = MIN(len - copied, bucket->used);
|
||||||
assert(copying >= 0);
|
assert(copying >= 0);
|
||||||
|
|
||||||
memcpy((char*) dest + copied, bucket->body, copying);
|
memcpy((char*) dest + copied, bucket->body, copying);
|
||||||
|
|
||||||
copied += copying;
|
copied += copying;
|
||||||
bucket = bucket->next;
|
bucket = bucket->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BPAlloc *BucketList_GetAlloc(BucketList *blist)
|
BPAlloc *BucketList_GetAlloc(BucketList *blist)
|
||||||
|
|||||||
+18
-18
@@ -87,29 +87,29 @@ void _Error_Report2(Error *err, _Bool internal,
|
|||||||
assert(p > -1);
|
assert(p > -1);
|
||||||
|
|
||||||
if((unsigned int) p > sizeof(err->message2)-1)
|
if((unsigned int) p > sizeof(err->message2)-1)
|
||||||
{
|
{
|
||||||
char *temp = malloc(p+1);
|
char *temp = malloc(p+1);
|
||||||
|
|
||||||
if(temp == NULL)
|
if(temp == NULL)
|
||||||
{
|
|
||||||
err->truncated = 1;
|
|
||||||
err->message = err->message2;
|
|
||||||
err->length = sizeof(err->message2)-1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snprintf(temp, p+1, fmt, va2);
|
|
||||||
err->truncated = 0;
|
|
||||||
err->message = temp;
|
|
||||||
err->length = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
err->truncated = 0;
|
err->truncated = 1;
|
||||||
err->message = err->message2;
|
err->message = err->message2;
|
||||||
|
err->length = sizeof(err->message2)-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(temp, p+1, fmt, va2);
|
||||||
|
err->truncated = 0;
|
||||||
|
err->message = temp;
|
||||||
err->length = p;
|
err->length = p;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err->truncated = 0;
|
||||||
|
err->message = err->message2;
|
||||||
|
err->length = p;
|
||||||
|
}
|
||||||
|
|
||||||
va_end(va2);
|
va_end(va2);
|
||||||
|
|
||||||
|
|||||||
+21
-21
@@ -87,14 +87,14 @@ void Promise_Resolve(Promise *promise, const void *data, int size)
|
|||||||
|
|
||||||
Gap *gap = promise->gaps;
|
Gap *gap = promise->gaps;
|
||||||
while(gap)
|
while(gap)
|
||||||
{
|
{
|
||||||
memcpy(gap->dest, data, size);
|
memcpy(gap->dest, data, size);
|
||||||
|
|
||||||
if(gap->callback)
|
if(gap->callback)
|
||||||
gap->callback(gap->userp);
|
gap->callback(gap->userp);
|
||||||
|
|
||||||
gap = gap->next;
|
gap = gap->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise->gaps = NULL;
|
promise->gaps = NULL;
|
||||||
}
|
}
|
||||||
@@ -112,25 +112,25 @@ _Bool Promise_Subscribe2(Promise *promise, void *dest, void *userp, void (*callb
|
|||||||
assert(dest != NULL);
|
assert(dest != NULL);
|
||||||
|
|
||||||
if(promise->set == 0)
|
if(promise->set == 0)
|
||||||
{
|
{
|
||||||
Gap *gap = BPAlloc_Malloc(promise->alloc, sizeof(Gap));
|
Gap *gap = BPAlloc_Malloc(promise->alloc, sizeof(Gap));
|
||||||
|
|
||||||
if(gap == NULL)
|
if(gap == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
gap->next = promise->gaps;
|
gap->next = promise->gaps;
|
||||||
gap->dest = dest;
|
gap->dest = dest;
|
||||||
gap->userp = userp;
|
gap->userp = userp;
|
||||||
gap->callback = callback;
|
gap->callback = callback;
|
||||||
promise->gaps = gap;
|
promise->gaps = gap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(dest, promise->body, promise->size);
|
memcpy(dest, promise->body, promise->size);
|
||||||
|
|
||||||
if(callback)
|
if(callback)
|
||||||
callback(userp);
|
callback(userp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
+37
-37
@@ -86,36 +86,36 @@ Source *Source_FromFile(const char *file, Error *error)
|
|||||||
fp = fopen(file, "rb");
|
fp = fopen(file, "rb");
|
||||||
|
|
||||||
if(fp == NULL)
|
if(fp == NULL)
|
||||||
{
|
{
|
||||||
if(errno == ENOENT)
|
if(errno == ENOENT)
|
||||||
Error_Report(error, 0, "File \"%s\" doesn't exist", file);
|
Error_Report(error, 0, "File \"%s\" doesn't exist", file);
|
||||||
else
|
else
|
||||||
Error_Report(error, 1, "Call to fopen failed (%s, errno = %d)", strerror(errno), errno);
|
Error_Report(error, 1, "Call to fopen failed (%s, errno = %d)", strerror(errno), errno);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fseek(fp, 0, SEEK_END))
|
if(fseek(fp, 0, SEEK_END))
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
|
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = ftell(fp);
|
size = ftell(fp);
|
||||||
|
|
||||||
if(size < 0)
|
if(size < 0)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "Call to ftell failed (%s, errno = %d)", strerror(errno), errno);
|
Error_Report(error, 1, "Call to ftell failed (%s, errno = %d)", strerror(errno), errno);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fseek(fp, 0, SEEK_SET))
|
if(fseek(fp, 0, SEEK_SET))
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
|
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate the source structure.
|
// Allocate the source structure.
|
||||||
@@ -126,11 +126,11 @@ Source *Source_FromFile(const char *file, Error *error)
|
|||||||
s = malloc(sizeof(Source) + namel + size + 2);
|
s = malloc(sizeof(Source) + namel + size + 2);
|
||||||
|
|
||||||
if(s == NULL)
|
if(s == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->name = (char*) (s + 1);
|
s->name = (char*) (s + 1);
|
||||||
s->body = s->name + namel + 1;
|
s->body = s->name + namel + 1;
|
||||||
@@ -146,12 +146,12 @@ Source *Source_FromFile(const char *file, Error *error)
|
|||||||
int p = fread(s->body, 1, size, fp);
|
int p = fread(s->body, 1, size, fp);
|
||||||
|
|
||||||
if(p != size)
|
if(p != size)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "Call to fread failed, %d bytes out of %d were read (%s, errno = %d)", p, size, strerror(errno), errno);
|
Error_Report(error, 1, "Call to fread failed, %d bytes out of %d were read (%s, errno = %d)", p, size, strerror(errno), errno);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(s);
|
free(s);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->body[s->size] = '\0';
|
s->body[s->size] = '\0';
|
||||||
}
|
}
|
||||||
@@ -172,10 +172,10 @@ Source *Source_FromString(const char *name, const char *body, int size, Error *e
|
|||||||
void *memory = malloc(sizeof(Source) + namel + size + 2);
|
void *memory = malloc(sizeof(Source) + namel + size + 2);
|
||||||
|
|
||||||
if(memory == NULL)
|
if(memory == NULL)
|
||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Source *s = memory;
|
Source *s = memory;
|
||||||
s->name = (char*) (s + 1);
|
s->name = (char*) (s + 1);
|
||||||
|
|||||||
+8
-8
@@ -135,15 +135,15 @@ _Bool Stack_Push(Stack *s, void *item)
|
|||||||
Stack *Stack_Copy(Stack *s, _Bool readonly)
|
Stack *Stack_Copy(Stack *s, _Bool readonly)
|
||||||
{
|
{
|
||||||
if(Stack_IsReadOnlyCopy(s))
|
if(Stack_IsReadOnlyCopy(s))
|
||||||
{
|
{
|
||||||
// Reference is readonly,
|
// Reference is readonly,
|
||||||
// so the copy must be
|
// so the copy must be
|
||||||
// readonly.
|
// readonly.
|
||||||
readonly = 1;
|
readonly = 1;
|
||||||
|
|
||||||
// Remove readonly bit.
|
// Remove readonly bit.
|
||||||
s = unmark(s);
|
s = unmark(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->refs += 1;
|
s->refs += 1;
|
||||||
|
|
||||||
|
|||||||
+110
-110
@@ -60,46 +60,46 @@
|
|||||||
int utf8_sequence_from_utf32_codepoint(char *utf8_data, int nbytes, uint32_t utf32_code)
|
int utf8_sequence_from_utf32_codepoint(char *utf8_data, int nbytes, uint32_t utf32_code)
|
||||||
{
|
{
|
||||||
if(utf32_code < 128)
|
if(utf32_code < 128)
|
||||||
{
|
{
|
||||||
if(nbytes < 1)
|
if(nbytes < 1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
utf8_data[0] = utf32_code;
|
utf8_data[0] = utf32_code;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(utf32_code < 2048)
|
if(utf32_code < 2048)
|
||||||
{
|
{
|
||||||
if(nbytes < 2)
|
if(nbytes < 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
utf8_data[0] = 0xc0 | (utf32_code >> 6);
|
utf8_data[0] = 0xc0 | (utf32_code >> 6);
|
||||||
utf8_data[1] = 0x80 | (utf32_code & 0x3f);
|
utf8_data[1] = 0x80 | (utf32_code & 0x3f);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(utf32_code < 65536)
|
if(utf32_code < 65536)
|
||||||
{
|
{
|
||||||
if(nbytes < 3)
|
if(nbytes < 3)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
utf8_data[0] = 0xe0 | (utf32_code >> 12);
|
utf8_data[0] = 0xe0 | (utf32_code >> 12);
|
||||||
utf8_data[1] = 0x80 | ((utf32_code >> 6) & 0x3f);
|
utf8_data[1] = 0x80 | ((utf32_code >> 6) & 0x3f);
|
||||||
utf8_data[2] = 0x80 | (utf32_code & 0x3f);
|
utf8_data[2] = 0x80 | (utf32_code & 0x3f);
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(utf32_code <= 0x10ffff)
|
if(utf32_code <= 0x10ffff)
|
||||||
{
|
{
|
||||||
if(nbytes < 4)
|
if(nbytes < 4)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
utf8_data[0] = 0xf0 | (utf32_code >> 18);
|
utf8_data[0] = 0xf0 | (utf32_code >> 18);
|
||||||
utf8_data[1] = 0x80 | ((utf32_code >> 12) & 0x3f);
|
utf8_data[1] = 0x80 | ((utf32_code >> 12) & 0x3f);
|
||||||
utf8_data[2] = 0x80 | ((utf32_code >> 6) & 0x3f);
|
utf8_data[2] = 0x80 | ((utf32_code >> 6) & 0x3f);
|
||||||
utf8_data[3] = 0x80 | (utf32_code & 0x3f);
|
utf8_data[3] = 0x80 | (utf32_code & 0x3f);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code is out of range for UTF-8.
|
// Code is out of range for UTF-8.
|
||||||
return -1;
|
return -1;
|
||||||
@@ -148,71 +148,71 @@ int utf8_sequence_to_utf32_codepoint(const char *utf8_data, int nbytes, uint32_t
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(utf8_data[0] & 0x80)
|
if(utf8_data[0] & 0x80)
|
||||||
{
|
{
|
||||||
// May be UTF-8.
|
// May be UTF-8.
|
||||||
|
|
||||||
if((unsigned char) utf8_data[0] >= 0xF0)
|
if((unsigned char) utf8_data[0] >= 0xF0)
|
||||||
{
|
{
|
||||||
// 4 bytes.
|
// 4 bytes.
|
||||||
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||||
|
|
||||||
if(nbytes < 4)
|
if(nbytes < 4)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
uint32_t temp
|
uint32_t temp
|
||||||
= (((uint32_t) utf8_data[0] & 0x07) << 18)
|
= (((uint32_t) utf8_data[0] & 0x07) << 18)
|
||||||
| (((uint32_t) utf8_data[1] & 0x3f) << 12)
|
| (((uint32_t) utf8_data[1] & 0x3f) << 12)
|
||||||
| (((uint32_t) utf8_data[2] & 0x3f) << 6)
|
| (((uint32_t) utf8_data[2] & 0x3f) << 6)
|
||||||
| (((uint32_t) utf8_data[3] & 0x3f));
|
| (((uint32_t) utf8_data[3] & 0x3f));
|
||||||
|
|
||||||
if(temp > 0x10ffff)
|
if(temp > 0x10ffff)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
*utf32_code = temp;
|
*utf32_code = temp;
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((unsigned char) utf8_data[0] >= 0xE0)
|
if((unsigned char) utf8_data[0] >= 0xE0)
|
||||||
{
|
{
|
||||||
// 3 bytes.
|
// 3 bytes.
|
||||||
// 1110xxxx 10xxxxxx 10xxxxxx
|
// 1110xxxx 10xxxxxx 10xxxxxx
|
||||||
|
|
||||||
if(nbytes < 3)
|
if(nbytes < 3)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
uint32_t temp
|
uint32_t temp
|
||||||
= (((uint32_t) utf8_data[0] & 0x0f) << 12)
|
= (((uint32_t) utf8_data[0] & 0x0f) << 12)
|
||||||
| (((uint32_t) utf8_data[1] & 0x3f) << 6)
|
| (((uint32_t) utf8_data[1] & 0x3f) << 6)
|
||||||
| (((uint32_t) utf8_data[2] & 0x3f));
|
| (((uint32_t) utf8_data[2] & 0x3f));
|
||||||
|
|
||||||
if(temp > 0x10ffff)
|
if(temp > 0x10ffff)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
*utf32_code = temp;
|
*utf32_code = temp;
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((unsigned char) utf8_data[0] >= 0xC0)
|
if((unsigned char) utf8_data[0] >= 0xC0)
|
||||||
{
|
{
|
||||||
// 2 bytes.
|
// 2 bytes.
|
||||||
// 110xxxxx 10xxxxxx
|
// 110xxxxx 10xxxxxx
|
||||||
|
|
||||||
if(nbytes < 2)
|
if(nbytes < 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
*utf32_code
|
*utf32_code
|
||||||
= (((uint32_t) utf8_data[0] & 0x1f) << 6)
|
= (((uint32_t) utf8_data[0] & 0x1f) << 6)
|
||||||
| (((uint32_t) utf8_data[1] & 0x3f));
|
| (((uint32_t) utf8_data[1] & 0x3f));
|
||||||
|
|
||||||
assert(*utf32_code <= 0x10ffff);
|
assert(*utf32_code <= 0x10ffff);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1 byte
|
// 1 byte
|
||||||
// 10xxxxxx
|
// 10xxxxxx
|
||||||
*utf32_code = (uint32_t) utf8_data[0] & 0x3f;
|
*utf32_code = (uint32_t) utf8_data[0] & 0x3f;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's ASCII
|
// It's ASCII
|
||||||
// 0xxxxxxx
|
// 0xxxxxxx
|
||||||
@@ -255,40 +255,40 @@ int utf8_strlen(const char *utf8_data, int nbytes)
|
|||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(i < nbytes)
|
while(i < nbytes)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if ASSUME_ASCII
|
#if ASSUME_ASCII
|
||||||
{
|
{
|
||||||
int ASCII_start = i;
|
int ASCII_start = i;
|
||||||
|
|
||||||
// Skip through ASCII
|
// Skip through ASCII
|
||||||
while(i < nbytes && (utf8_data[i] & 0x80) == 0)
|
while(i < nbytes && (utf8_data[i] & 0x80) == 0)
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|
||||||
int ASCII_end = i;
|
int ASCII_end = i;
|
||||||
|
|
||||||
len += (ASCII_end - ASCII_start);
|
len += (ASCII_end - ASCII_start);
|
||||||
|
|
||||||
// Either we scanned through all of the
|
// Either we scanned through all of the
|
||||||
// string, or we encountered some unicode.
|
// string, or we encountered some unicode.
|
||||||
|
|
||||||
if(i == nbytes)
|
if(i == nbytes)
|
||||||
// String ended.
|
// String ended.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Found unicode.
|
// Found unicode.
|
||||||
{
|
{
|
||||||
int n = utf8_sequence_to_utf32_codepoint(utf8_data + i, nbytes - i, NULL);
|
int n = utf8_sequence_to_utf32_codepoint(utf8_data + i, nbytes - i, NULL);
|
||||||
|
|
||||||
if(n < 1)
|
if(n < 1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
i += n;
|
i += n;
|
||||||
len += 1;
|
len += 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,11 +347,11 @@ int utf8_prev(const char *utf8_data, int nbytes, int idx, uint32_t *utf32_code)
|
|||||||
// to go faster.
|
// to go faster.
|
||||||
|
|
||||||
if((utf8_data[tail] & 0x80) == 0)
|
if((utf8_data[tail] & 0x80) == 0)
|
||||||
{
|
{
|
||||||
if(utf32_code)
|
if(utf32_code)
|
||||||
*utf32_code = utf8_data[tail];
|
*utf32_code = utf8_data[tail];
|
||||||
return tail;
|
return tail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -362,11 +362,11 @@ int utf8_prev(const char *utf8_data, int nbytes, int idx, uint32_t *utf32_code)
|
|||||||
idx -= 1;
|
idx -= 1;
|
||||||
|
|
||||||
if(idx == -1)
|
if(idx == -1)
|
||||||
{
|
{
|
||||||
// No head sequence byte was found,
|
// No head sequence byte was found,
|
||||||
// so this isn't valid UTF-8.
|
// so this isn't valid UTF-8.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The index of the head byte.
|
// The index of the head byte.
|
||||||
int head = idx;
|
int head = idx;
|
||||||
|
|||||||
Reference in New Issue
Block a user