From 07137b50c6081791ee1c96947c0e623d0000695e Mon Sep 17 00:00:00 2001 From: cozis Date: Mon, 4 Apr 2022 00:07:33 +0200 Subject: [PATCH] new curly bracket coding convention --- examples/json.noja | 77 +- src/builtins/basic.c | 119 +- src/builtins/files.c | 186 +-- src/builtins/math.c | 90 +- src/common/executable.c | 338 +++--- src/compiler/compile.c | 1111 +++++++++--------- src/compiler/parse.c | 2245 ++++++++++++++++++------------------- src/main.c | 277 +++-- src/objects/heap.c | 310 ++--- src/objects/o_buffer.c | 298 ++--- src/objects/o_closure.c | 20 +- src/objects/o_dir.c | 8 +- src/objects/o_file.c | 8 +- src/objects/o_list.c | 70 +- src/objects/o_map.c | 226 ++-- src/objects/o_string.c | 39 +- src/objects/objects.c | 144 +-- src/runtime/o_func.c | 66 +- src/runtime/o_nfunc.c | 76 +- src/runtime/o_staticmap.c | 30 +- src/runtime/runtime.c | 1813 +++++++++++++++--------------- src/utils/bpalloc.c | 64 +- src/utils/bucketlist.c | 90 +- src/utils/error.c | 36 +- src/utils/promise.c | 42 +- src/utils/source.c | 74 +- src/utils/stack.c | 16 +- src/utils/utf8.c | 222 ++-- 28 files changed, 4036 insertions(+), 4059 deletions(-) diff --git a/examples/json.noja b/examples/json.noja index 0409aa9..8efd9e5 100644 --- a/examples/json.noja +++ b/examples/json.noja @@ -42,10 +42,10 @@ fun parse(str) { return none; } - return parseAnyValue(ctx); + return parseAny(ctx); } -fun parseArrayValue(ctx) { +fun parseArray(ctx) { assert(current(ctx) == '['); @@ -67,7 +67,7 @@ fun parseArrayValue(ctx) { while true: { - child = parseAnyValue(ctx); + child = parseAny(ctx); if child == none: return none; @@ -103,7 +103,7 @@ fun parseArrayValue(ctx) { return arr; } -fun parseObjectValue(ctx) { +fun parseObject(ctx) { assert(current(ctx) == '{'); @@ -130,7 +130,7 @@ fun parseObjectValue(ctx) { return none; } - key = parseStringValue(ctx); + key = parseString(ctx); if key == none: return none; @@ -146,7 +146,7 @@ fun parseObjectValue(ctx) { skip(ctx, isSpace); - child = parseAnyValue(ctx); + child = parseAny(ctx); if child == none: return none; @@ -182,7 +182,7 @@ fun parseObjectValue(ctx) { return obj; } -fun parseStringValue(ctx) { +fun parseString(ctx) { next(ctx); # Skip the '"'. @@ -207,7 +207,7 @@ fun parseStringValue(ctx) { return buff; } -fun parseNumberValue(ctx) { +fun parseNumber(ctx) { assert(isDigit(current(ctx))); @@ -251,49 +251,50 @@ fun parseNumberValue(ctx) { return parsed; } -fun parseAnyValue(ctx) { +fun parseAny(ctx) { + + print('Parsing value\n'); assert(not ended(ctx)); if current(ctx) == '[': - return parseArrayValue(ctx); + return parseArray(ctx); if current(ctx) == '{': - return parseObjectValue(ctx); + return parseObject(ctx); if current(ctx) == '"': - return parseStringValue(ctx); + return parseString(ctx); if isDigit(current(ctx)): - return parseNumberValue(ctx); + return parseNumber(ctx); error("Not implemented yet"); } -tests = [ - '', - '1', - '10', - '1.10', - '"jeje"', - '[]', - '[1,2,3]', - ' [ ] ', - ' [ 1 , 2 , 3 ]', - '{}', - ' { } ', - '{"hoy":4}', - ' { "hoy" : 4 } ', - 'a' -]; +#tests = ['', '1', '10', '1.10', '"jeje"', '[]', '[1,2,3]', ' [ ] ', ' [ 1 , 2 , 3 ]', '{}', ' { } ', '{"hoy":4}', ' { "hoy" : 4 } ']; -i = 0; -while i < count(tests): { - r = parse(tests[i]); - if r == none: - print('\nTest ', i, ' failed\n'); - else - print(tests[i], ' -> ', r, '\n'); - i = i + 1; -} +#i = 0; +#while i < count(tests): { +# r = parse(tests[i]); +# if r == none: +# print('\nTest ', i, ' failed\n'); +# else +# print(tests[i], ' -> ', r, '\n'); +# 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)); diff --git a/src/builtins/basic.c b/src/builtins/basic.c index 45fb1da..b803e26 100644 --- a/src/builtins/basic.c +++ b/src/builtins/basic.c @@ -64,10 +64,10 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E uint32_t ret = 0; if(!Object_IsString(argv[0])) - { - Error_Report(error, 0, "Argument #%d is not a string", 1); - return NULL; - } + { + Error_Report(error, 0, "Argument #%d is not a string", 1); + return NULL; + } const char *string; int n; @@ -76,10 +76,10 @@ static Object *bin_unicode(Runtime *runtime, Object **argv, unsigned int argc, E return NULL; if(n == 0) - { - Error_Report(error, 0, "Argument #%d is an empty string", 1); - return NULL; - } + { + Error_Report(error, 0, "Argument #%d is an empty string", 1); + return NULL; + } 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; 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') - break; + if(tmp == NULL) + { + if(str != maybe) free(str); + Error_Report(error, 1, "No memory"); + return NULL; + } - if(size == cap) - { - 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 = tmp; + cap = newcap; } + str[size++] = c; + } + str[size] = '\0'; 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) if(!Object_ToBool(argv[i], error)) - { - if(!error->occurred) - Error_Report(error, 0, "Assertion failed"); - return NULL; - } + { + if(!error->occurred) + Error_Report(error, 0, "Assertion failed"); + return NULL; + } 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; 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; - } - - total_count += Object_Count(argv[i], error); - - if(error->occurred) - 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; + } + char starting[128]; char *buffer = starting; if(total_count > sizeof(starting)-1) - { - buffer = malloc(total_count+1); + { + buffer = malloc(total_count+1); - if(buffer == NULL) - { - Error_Report(error, 1, "No memory"); - return NULL; - } + if(buffer == NULL) + { + Error_Report(error, 1, "No memory"); + return NULL; } + } Object *result = NULL; for(unsigned int i = 0, written = 0; i < argc; i += 1) - { - int n; - const char *s; + { + int n; + 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) - goto done; - - memcpy(buffer + written, s, n); - written += n; - } + memcpy(buffer + written, s, n); + written += n; + } buffer[total_count] = '\0'; diff --git a/src/builtins/files.c b/src/builtins/files.c index 49b0f52..15638a2 100644 --- a/src/builtins/files.c +++ b/src/builtins/files.c @@ -43,16 +43,16 @@ static Object *bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, assert(argc == 2); 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0])); + return NULL; + } 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected second argument to be an int, but it's a %s", Object_GetName(argv[1])); + return NULL; + } Heap *heap = Runtime_GetHeap(runtime); @@ -71,24 +71,24 @@ static Object *bin_openFile(Runtime *runtime, Object **argv, unsigned int argc, const char *mode2; switch(mode) - { - case MD_READ: - mode2 = "r"; - break; + { + case MD_READ: + mode2 = "r"; + break; - case MD_READ | MD_WRITE: - mode2 = "w+"; - break; + case MD_READ | MD_WRITE: + mode2 = "w+"; + break; - case MD_READ | MD_APPEND: - case MD_READ | MD_WRITE | MD_APPEND: - mode2 = "a"; - break; + case MD_READ | MD_APPEND: + case MD_READ | MD_WRITE | MD_APPEND: + mode2 = "a"; + break; - default: - assert(0); - break; - } + default: + assert(0); + break; + } fp = fopen(path, mode2); @@ -108,16 +108,16 @@ static Object *bin_read(Runtime *runtime, Object **argv, unsigned int argc, Erro // Arg 2: count 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0])); + return NULL; + } 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1])); + return NULL; + } Heap *heap = Runtime_GetHeap(runtime); @@ -129,26 +129,26 @@ static Object *bin_read(Runtime *runtime, Object **argv, unsigned int argc, Erro int read_size; if(Object_IsNone(argv[2])) - { - read_size = buff_size; - } + { + read_size = buff_size; + } 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) - 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])); + 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; + } 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 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected first argument to be a file, but it's a %s", Object_GetName(argv[0])); + return NULL; + } 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected second argument to be a buffer, but it's a %s", Object_GetName(argv[1])); + return NULL; + } Heap *heap = Runtime_GetHeap(runtime); @@ -190,26 +190,26 @@ static Object *bin_write(Runtime *runtime, Object **argv, unsigned int argc, Err int write_size; if(Object_IsNone(argv[2])) - { - write_size = buff_size; - } + { + write_size = buff_size; + } 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) - 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])); + 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; + } 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 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected first argument to be a string, but it's a %s", Object_GetName(argv[0])); + return NULL; + } 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); if(error->occurred) - { - (void) closedir(dir); - return NULL; - } + { + (void) closedir(dir); + return NULL; + } return dob; } @@ -263,10 +263,10 @@ static Object *bin_nextDirItem(Runtime *runtime, Object **argv, unsigned int arg // Arg 0: path 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])); - return NULL; - } + { + Error_Report(error, 0, "Expected first argument to be a directory, but it's a %s", Object_GetName(argv[0])); + return NULL; + } 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); if(ent == NULL) - { - if(errno == 0) - // Nothing left to read. - return Object_NewNone(heap, error); + { + if(errno == 0) + // Nothing left to read. + return Object_NewNone(heap, error); - // An error occurred. - Error_Report(error, 1, "Failed to read directory item"); - return NULL; - } + // An error occurred. + Error_Report(error, 1, "Failed to read directory item"); + return NULL; + } return Object_FromString(ent->d_name, -1, heap, error); } diff --git a/src/builtins/math.c b/src/builtins/math.c index 68835e6..211f745 100644 --- a/src/builtins/math.c +++ b/src/builtins/math.c @@ -33,54 +33,54 @@ #include "math.h" #define WRAP_FUNC(name) \ - static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \ - { \ - assert(argc == 1); \ - \ - if(Object_IsFloat(argv[0])) \ - { \ - double v = Object_ToFloat(argv[0], error); \ - \ - if(error->occurred) \ - return NULL; \ - \ - return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \ - } \ - else \ - { \ - Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\ - return NULL; \ - } \ + static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \ + { \ + assert(argc == 1); \ + \ + if(Object_IsFloat(argv[0])) \ + { \ + double v = Object_ToFloat(argv[0], error); \ + \ + if(error->occurred) \ + return NULL; \ + \ + return Object_FromFloat(name(v), Runtime_GetHeap(runtime), error); \ + } \ + else \ + { \ + Error_Report(error, 0, "Expected first argument to be a float, but it's a %s", Object_GetName(argv[0]));\ + return NULL; \ + } \ } #define WRAP_FUNC_2(name) \ - static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \ - { \ - assert(argc == 2); \ - \ - 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]));\ - return NULL; \ - } \ - \ - 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]));\ - return NULL; \ - } \ - \ - double v1 = Object_ToFloat(argv[0], error); \ - \ - if(error->occurred) \ - return NULL; \ - \ - double v2 = Object_ToFloat(argv[1], error); \ - \ - if(error->occurred) \ - return NULL; \ - \ - return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \ + static Object *bin_ ## name(Runtime *runtime, Object **argv, unsigned int argc, Error *error) \ + { \ + assert(argc == 2); \ + \ + 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]));\ + return NULL; \ + } \ + \ + 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]));\ + return NULL; \ + } \ + \ + double v1 = Object_ToFloat(argv[0], error); \ + \ + if(error->occurred) \ + return NULL; \ + \ + double v2 = Object_ToFloat(argv[1], error); \ + \ + if(error->occurred) \ + return NULL; \ + \ + return Object_FromFloat(name(v1, v2), Runtime_GetHeap(runtime), error); \ } WRAP_FUNC(ceil) diff --git a/src/common/executable.c b/src/common/executable.c index 2a87f16..6cbabd9 100644 --- a/src/common/executable.c +++ b/src/common/executable.c @@ -131,51 +131,51 @@ void Executable_Free(Executable *exe) assert(exe->refs >= 0); if(exe->refs == 0) - { - if(exe->src) - Source_Free(exe->src); - free(exe); - } + { + if(exe->src) + Source_Free(exe->src); + free(exe); + } } void Executable_Dump(Executable *exe) { 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; - Operand ops[MAX_OPS]; - int opc = MAX_OPS; + switch(ops[j].type) + { + 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); - - for(int j = 0; j < opc; j += 1) - { - 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"); + case OPTP_PROMISE: + UNREACHABLE; + break; + } } + + fprintf(stderr, "\n"); + } } _Bool Executable_SetSource(Executable *exe, Source *src) @@ -232,45 +232,45 @@ _Bool Executable_Fetch(Executable *exe, int index, Opcode *opcode, Operand *ops, int i; 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]; - assert(type != OPTP_PROMISE); + int data_offset = instr->operands[i].as_int; - switch(type) { + assert(data_offset < exe->headl); - case OPTP_STRING: - { - int data_offset = instr->operands[i].as_int; - - 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; - } + ops[i].type = OPTP_STRING; + ops[i].as_string = exe->head + data_offset; + 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; } @@ -298,10 +298,10 @@ Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error) assert(exeb != NULL); if(exeb->promc > 0) - { - Error_Report(error, 0, "There are still %d unfulfilled promises", exeb->promc); - return 0; - } + { + Error_Report(error, 0, "There are still %d unfulfilled promises", exeb->promc); + return 0; + } Executable *exe; { @@ -313,10 +313,10 @@ Executable *ExeBuilder_Finalize(ExeBuilder *exeb, Error *error) void *temp = malloc(sizeof(Executable) + data_size + code_size); if(temp == NULL) - { - Error_Report(error, 1, "No memory"); - return NULL; - } + { + Error_Report(error, 1, "No memory"); + return NULL; + } exe = temp; exe->headl = data_size; @@ -369,13 +369,13 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand * const InstrInfo *info = instr_table + opcode; if(opc != info->opcount) - { - // ERROR: Too many operands were provided. - Error_Report(error, 0, - "Instruction %s expects %d operands, but %d were provided", - info->name, info->opcount, opc); - return 0; - } + { + // ERROR: Too many operands were provided. + Error_Report(error, 0, + "Instruction %s expects %d operands, but %d were provided", + info->name, info->opcount, opc); + return 0; + } 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)); if(instr == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } + { + Error_Report(error, 1, "No memory"); + return 0; + } instr->opcode = opcode; instr->offset = off; instr->length = len; 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 - // match, or that the provided type is a promise with - // the same size of the expected type. + OperandType expected_type = info->optypes[i]; + OperandType provided_type = opv[i].type; + + assert(expected_type != OPTP_PROMISE); + + if(provided_type == OPTP_PROMISE) { - OperandType expected_type = info->optypes[i]; - OperandType provided_type = opv[i].type; + assert(opv[i].as_promise != NULL); - assert(expected_type != OPTP_PROMISE); - - 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) + if(expected_type == OPTP_STRING) { - 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; - + 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: + + 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; diff --git a/src/compiler/compile.c b/src/compiler/compile.c index a8789d0..be247dc 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -53,26 +53,26 @@ static Opcode exprkind_to_opcode(ExprKind kind) { switch(kind) - { - case EXPR_NOT: return OPCODE_NOT; - case EXPR_POS: return OPCODE_POS; - case EXPR_NEG: return OPCODE_NEG; - case EXPR_ADD: return OPCODE_ADD; - case EXPR_SUB: return OPCODE_SUB; - case EXPR_MUL: return OPCODE_MUL; - case EXPR_DIV: return OPCODE_DIV; - case EXPR_EQL: return OPCODE_EQL; - case EXPR_NQL: return OPCODE_NQL; - case EXPR_LSS: return OPCODE_LSS; - case EXPR_LEQ: return OPCODE_LEQ; - case EXPR_GRT: return OPCODE_GRT; - case EXPR_GEQ: return OPCODE_GEQ; - case EXPR_AND: return OPCODE_AND; - case EXPR_OR: return OPCODE_OR; - default: - UNREACHABLE; - break; - } + { + case EXPR_NOT: return OPCODE_NOT; + case EXPR_POS: return OPCODE_POS; + case EXPR_NEG: return OPCODE_NEG; + case EXPR_ADD: return OPCODE_ADD; + case EXPR_SUB: return OPCODE_SUB; + case EXPR_MUL: return OPCODE_MUL; + case EXPR_DIV: return OPCODE_DIV; + case EXPR_EQL: return OPCODE_EQL; + case EXPR_NQL: return OPCODE_NQL; + case EXPR_LSS: return OPCODE_LSS; + case EXPR_LEQ: return OPCODE_LEQ; + case EXPR_GRT: return OPCODE_GRT; + case EXPR_GEQ: return OPCODE_GEQ; + case EXPR_AND: return OPCODE_AND; + case EXPR_OR: return OPCODE_OR; + default: + UNREACHABLE; + break; + } } static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_dest, Error *error) @@ -80,552 +80,551 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de assert(node != NULL); switch(node->kind) + { + case NODE_EXPR: { - case NODE_EXPR: + ExprNode *expr = (ExprNode*) node; + switch(expr->kind) { - ExprNode *expr = (ExprNode*) node; - switch(expr->kind) - { - case EXPR_NOT: - case EXPR_POS: - case EXPR_NEG: - case EXPR_ADD: - case EXPR_SUB: - case EXPR_MUL: - case EXPR_DIV: - case EXPR_EQL: - case EXPR_NQL: - case EXPR_LSS: - case EXPR_LEQ: - case EXPR_GRT: - case EXPR_GEQ: - case EXPR_AND: - case EXPR_OR: - { - OperExprNode *oper = (OperExprNode*) expr; - - for(Node *operand = oper->head; operand; operand = operand->next) - if(!emit_instr_for_node(exeb, operand, break_dest, error)) - return 0; - - if(!ExeBuilder_Append(exeb, error, - exprkind_to_opcode(expr->kind), - NULL, 0, node->offset, node->length)) - return 0; - return 1; - } - - case EXPR_ASS: - { - OperExprNode *oper = (OperExprNode*) expr; - - Node *lop, *rop; - lop = oper->head; - rop = lop->next; - - if(!emit_instr_for_node(exeb, rop, break_dest, error)) - return 0; - - if(((ExprNode*) lop)->kind == EXPR_IDENT) - { - const char *name = ((IdentExprNode*) lop)->val; - - Operand op = { .type = OPTP_STRING, .as_string = name }; - if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length)) - return 0; - } - else if(((ExprNode*) lop)->kind == EXPR_SELECT) - { - Node *idx = ((IndexSelectionExprNode*) lop)->idx; - Node *set = ((IndexSelectionExprNode*) lop)->set; - - if(!emit_instr_for_node(exeb, set, break_dest, error)) - return 0; - - if(!emit_instr_for_node(exeb, idx, break_dest, error)) - return 0; - - if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length)) - return 0; - } - else - { - Error_Report(error, 0, "Assignment left operand can't be assigned to"); - return 0; - } - - return 1; - } - - case EXPR_INT: - { - IntExprNode *p = (IntExprNode*) expr; - Operand op = { .type = OPTP_INT, .as_int = p->val }; - return ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, node->offset, node->length); - } - - case EXPR_FLOAT: - { - FloatExprNode *p = (FloatExprNode*) expr; - Operand op = { .type = OPTP_FLOAT, .as_float = p->val }; - return ExeBuilder_Append(exeb, error, OPCODE_PUSHFLT, &op, 1, node->offset, node->length); - } - - case EXPR_STRING: - { - StringExprNode *p = (StringExprNode*) expr; - Operand op = { .type = OPTP_STRING, .as_string = p->val }; - return ExeBuilder_Append(exeb, error, OPCODE_PUSHSTR, &op, 1, node->offset, node->length); - } - - case EXPR_IDENT: - { - IdentExprNode *p = (IdentExprNode*) expr; - Operand op = { .type = OPTP_STRING, .as_string = p->val }; - return ExeBuilder_Append(exeb, error, OPCODE_PUSHVAR, &op, 1, node->offset, node->length); - } - - case EXPR_LIST: - { - // PUSHLST - // PUSHINT - // - // INSERT - - ListExprNode *l = (ListExprNode*) node; - - Operand op; - - op = (Operand) { .type = OPTP_INT, .as_int = l->itemc }; - if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHLST, &op, 1, node->offset, node->length)) - return 0; - - Node *item = l->items; - int i = 0; - - while(item) - { - op = (Operand) { .type = OPTP_INT, .as_int = i }; - if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, item->offset, item->length)) - return 0; - - if(!emit_instr_for_node(exeb, item, break_dest, error)) - return 0; - - if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) - return 0; - - i += 1; - item = item->next; - } - return 1; - } - - case EXPR_MAP: - { - MapExprNode *m = (MapExprNode*) node; - - Operand op; - - op = (Operand) { .type = OPTP_INT, .as_int = m->itemc }; - if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHMAP, &op, 1, node->offset, node->length)) - return 0; - - Node *key = m->keys; - Node *item = m->items; - - while(item) - { - if(!emit_instr_for_node(exeb, key, break_dest, error)) - return 0; - - if(!emit_instr_for_node(exeb, item, break_dest, error)) - return 0; - - if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) - return 0; - - key = key->next; - item = item->next; - } - - return 1; - } - - case EXPR_CALL: - { - CallExprNode *p = (CallExprNode*) expr; - - Node *arg = p->argv; - - while(arg) - { - if(!emit_instr_for_node(exeb, arg, break_dest, error)) - return 0; - - arg = arg->next; - } - - if(!emit_instr_for_node(exeb, p->func, break_dest, error)) - return 0; - - Operand op = { .type = OPTP_INT, .as_int = p->argc }; - return ExeBuilder_Append(exeb, error, OPCODE_CALL, &op, 1, node->offset, node->length); - } - - case EXPR_SELECT: - { - IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; - - if(!emit_instr_for_node(exeb, sel->set, break_dest, error)) - return 0; - - if(!emit_instr_for_node(exeb, sel->idx, break_dest, error)) - return 0; - - return ExeBuilder_Append(exeb, error, OPCODE_SELECT, NULL, 0, node->offset, node->length); - } - - case EXPR_NONE: - return ExeBuilder_Append(exeb, error, OPCODE_PUSHNNE, NULL, 0, node->offset, node->length); - - case EXPR_TRUE: - return ExeBuilder_Append(exeb, error, OPCODE_PUSHTRU, NULL, 0, node->offset, node->length); - - case EXPR_FALSE: - return ExeBuilder_Append(exeb, error, OPCODE_PUSHFLS, NULL, 0, node->offset, node->length); - - default: - UNREACHABLE; - break; - } - break; - } - - case NODE_BREAK: - { - if(break_dest == NULL) - { - Error_Report(error, 0, "Break not inside a loop"); - return 0; - } - Operand op = (Operand) { .type = OPTP_PROMISE, .as_promise = break_dest }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) - return 0; - return 1; - } - - case NODE_IFELSE: - { - IfElseNode *ifelse = (IfElseNode*) node; - - if(!emit_instr_for_node(exeb, ifelse->condition, break_dest, error)) - return 0; - - if(ifelse->false_branch) - { - Promise *else_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - Promise *done_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - - if(else_offset == NULL || done_offset == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } - - Operand op = { .type = OPTP_PROMISE, .as_promise = else_offset }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, node->offset, node->length)) - return 0; - - if(!emit_instr_for_node(exeb, ifelse->true_branch, break_dest, error)) - return 0; - - if(ifelse->true_branch->kind == NODE_EXPR) - { - Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->true_branch->offset, 0)) - return 0; - } - - op = (Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) - return 0; - - long long int temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(else_offset, &temp, sizeof(temp)); - - if(!emit_instr_for_node(exeb, ifelse->false_branch, break_dest, error)) - return 0; - - if(ifelse->false_branch->kind == NODE_EXPR) - { - Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->false_branch->offset, 0)) - return 0; - } - - temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(done_offset, &temp, sizeof(temp)); - - Promise_Free(else_offset); - Promise_Free(done_offset); - } - else - { - Promise *done_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - - if(done_offset == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } - - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &(Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }, 1, node->offset, node->length)) - return 0; - - if(!emit_instr_for_node(exeb, ifelse->true_branch, break_dest, error)) - return 0; - - if(ifelse->true_branch->kind == NODE_EXPR) - { - Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->true_branch->offset, 0)) - return 0; - } - - long long int temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(done_offset, &temp, sizeof(temp)); - - Promise_Free(done_offset); - } - - return 1; - } - - case NODE_WHILE: - { - WhileNode *whl = (WhileNode*) node; - - /* - * start: - * - * JUMPIFNOTANDPOP end - * - * JUMP start - * end: - */ - - Promise *start_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - Promise *end_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - - if(start_offset == NULL || end_offset == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } - - long long int temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(start_offset, &temp, sizeof(temp)); - - if(!emit_instr_for_node(exeb, whl->condition, break_dest, error)) - return 0; - - Operand op = { .type = OPTP_PROMISE, .as_promise = end_offset }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, whl->condition->offset, whl->condition->length)) - return 0; - - if(!emit_instr_for_node(exeb, whl->body, end_offset, error)) - return 0; - - if(whl->body->kind == NODE_EXPR) - { - Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, whl->body->offset, 0)) - return 0; - } - - op = (Operand) { .type = OPTP_PROMISE, .as_promise = start_offset }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) - return 0; - - temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(end_offset, &temp, sizeof(temp)); - - Promise_Free(start_offset); - Promise_Free( end_offset); - return 1; - } - - case NODE_DOWHILE: - { - DoWhileNode *dowhl = (DoWhileNode*) node; - - /* - * start: - * - * - * JUMPIFANDPOP start - */ - - Promise *end_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - if(end_offset == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } - - long long int start = ExeBuilder_InstrCount(exeb); - - if(!emit_instr_for_node(exeb, dowhl->body, end_offset, error)) - return 0; - - if(dowhl->body->kind == NODE_EXPR) - { - Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, dowhl->body->offset, 0)) - return 0; - } - - if(!emit_instr_for_node(exeb, dowhl->condition, break_dest, error)) - return 0; - - Operand op = { .type = OPTP_INT, .as_int = start }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFANDPOP, &op, 1, dowhl->condition->offset, dowhl->condition->length)) - return 0; - - long long int temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(end_offset, &temp, sizeof(temp)); - Promise_Free(end_offset); - return 1; - } - - case NODE_COMP: - { - CompoundNode *comp = (CompoundNode*) node; - - Node *stmt = comp->head; - - while(stmt) - { - if(!emit_instr_for_node(exeb, stmt, break_dest, error)) - return 0; - - if(stmt->kind == NODE_EXPR) - { - Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, stmt->offset, 0)) - return 0; - } - - stmt = stmt->next; - } - - return 1; - } - - case NODE_RETURN: - { - ReturnNode *ret = (ReturnNode*) node; - - if(!emit_instr_for_node(exeb, ret->val, break_dest, error)) - return 0; - - if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, ret->base.offset, ret->base.length)) - return 0; - - return 1; - } - - case NODE_FUNC: - { - FunctionNode *func = (FunctionNode*) node; - - Promise *func_index = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - Promise *jump_index = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); - - if(func_index == NULL || jump_index == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } - - // Push function. + case EXPR_NOT: + case EXPR_POS: + case EXPR_NEG: + case EXPR_ADD: + case EXPR_SUB: + case EXPR_MUL: + case EXPR_DIV: + case EXPR_EQL: + case EXPR_NQL: + case EXPR_LSS: + case EXPR_LEQ: + case EXPR_GRT: + case EXPR_GEQ: + case EXPR_AND: + case EXPR_OR: { - Operand ops[2] = { - { .type = OPTP_PROMISE, .as_promise = func_index }, - { .type = OPTP_INT, .as_int = func->argc }, - }; + OperExprNode *oper = (OperExprNode*) expr; - if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length)) + for(Node *operand = oper->head; operand; operand = operand->next) + if(!emit_instr_for_node(exeb, operand, break_dest, error)) + return 0; + + if(!ExeBuilder_Append(exeb, error, + exprkind_to_opcode(expr->kind), + NULL, 0, node->offset, node->length)) return 0; + return 1; } - - // Assign variable. - Operand op = (Operand) { .type = OPTP_STRING, .as_string = func->name }; - if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, func->base.offset, func->base.length)) - return 0; - // Pop function object. - op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, func->base.offset, func->base.length)) - return 0; - - // Jump after the function code. - op = (Operand) { .type = OPTP_PROMISE, .as_promise = jump_index }; - if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, func->base.offset, func->base.length)) - return 0; - - // This is the function code index. - long long int temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(func_index, &temp, sizeof(temp)); - - // Compile the function body. + case EXPR_ASS: { - // Assign the arguments. + OperExprNode *oper = (OperExprNode*) expr; - if(func->argv) - { assert(func->argv->kind == NODE_ARG); } + Node *lop, *rop; + lop = oper->head; + rop = lop->next; - ArgumentNode *arg = (ArgumentNode*) func->argv; + if(!emit_instr_for_node(exeb, rop, break_dest, error)) + return 0; + + if(((ExprNode*) lop)->kind == EXPR_IDENT) + { + const char *name = ((IdentExprNode*) lop)->val; + + Operand op = { .type = OPTP_STRING, .as_string = name }; + if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, node->offset, node->length)) + return 0; + } + else if(((ExprNode*) lop)->kind == EXPR_SELECT) + { + Node *idx = ((IndexSelectionExprNode*) lop)->idx; + Node *set = ((IndexSelectionExprNode*) lop)->set; + + if(!emit_instr_for_node(exeb, set, break_dest, error)) + return 0; + + if(!emit_instr_for_node(exeb, idx, break_dest, error)) + return 0; + + if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT2, NULL, 0, node->offset, node->length)) + return 0; + } + else + { + Error_Report(error, 0, "Assignment left operand can't be assigned to"); + return 0; + } + + return 1; + } + + case EXPR_INT: + { + IntExprNode *p = (IntExprNode*) expr; + Operand op = { .type = OPTP_INT, .as_int = p->val }; + return ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, node->offset, node->length); + } + + case EXPR_FLOAT: + { + FloatExprNode *p = (FloatExprNode*) expr; + Operand op = { .type = OPTP_FLOAT, .as_float = p->val }; + return ExeBuilder_Append(exeb, error, OPCODE_PUSHFLT, &op, 1, node->offset, node->length); + } + + case EXPR_STRING: + { + StringExprNode *p = (StringExprNode*) expr; + Operand op = { .type = OPTP_STRING, .as_string = p->val }; + return ExeBuilder_Append(exeb, error, OPCODE_PUSHSTR, &op, 1, node->offset, node->length); + } + + case EXPR_IDENT: + { + IdentExprNode *p = (IdentExprNode*) expr; + Operand op = { .type = OPTP_STRING, .as_string = p->val }; + return ExeBuilder_Append(exeb, error, OPCODE_PUSHVAR, &op, 1, node->offset, node->length); + } + + case EXPR_LIST: + { + // PUSHLST + // PUSHINT + // + // INSERT + + ListExprNode *l = (ListExprNode*) node; + + Operand op; + + op = (Operand) { .type = OPTP_INT, .as_int = l->itemc }; + if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHLST, &op, 1, node->offset, node->length)) + return 0; + + Node *item = l->items; + int i = 0; + + while(item) + { + op = (Operand) { .type = OPTP_INT, .as_int = i }; + if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHINT, &op, 1, item->offset, item->length)) + return 0; + + if(!emit_instr_for_node(exeb, item, break_dest, error)) + return 0; + + if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) + return 0; + + i += 1; + item = item->next; + } + return 1; + } + + case EXPR_MAP: + { + MapExprNode *m = (MapExprNode*) node; + + Operand op; + + op = (Operand) { .type = OPTP_INT, .as_int = m->itemc }; + if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHMAP, &op, 1, node->offset, node->length)) + return 0; + + Node *key = m->keys; + Node *item = m->items; + + while(item) + { + if(!emit_instr_for_node(exeb, key, break_dest, error)) + return 0; + + if(!emit_instr_for_node(exeb, item, break_dest, error)) + return 0; + + if(!ExeBuilder_Append(exeb, error, OPCODE_INSERT, NULL, 0, item->offset, item->length)) + return 0; + + key = key->next; + item = item->next; + } + + return 1; + } + + case EXPR_CALL: + { + CallExprNode *p = (CallExprNode*) expr; + + Node *arg = p->argv; while(arg) - { - op = (Operand) { .type = OPTP_STRING, .as_string = arg->name }; - if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, arg->base.offset, arg->base.length)) - return 0; + { + if(!emit_instr_for_node(exeb, arg, break_dest, error)) + return 0; - op = (Operand) { .type = OPTP_INT, .as_int = 1 }; - if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, arg->base.offset, arg->base.length)) - return 0; + arg = arg->next; + } - if(arg->base.next) - { assert(arg->base.next->kind == NODE_ARG); } - - arg = (ArgumentNode*) arg->base.next; - } - - if(!emit_instr_for_node(exeb, func->body, NULL, error)) + if(!emit_instr_for_node(exeb, p->func, break_dest, error)) return 0; - // Write a return instruction, just - // in case it didn't already return. - if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, func->body->offset, 0)) + Operand op = { .type = OPTP_INT, .as_int = p->argc }; + return ExeBuilder_Append(exeb, error, OPCODE_CALL, &op, 1, node->offset, node->length); + } + + case EXPR_SELECT: + { + IndexSelectionExprNode *sel = (IndexSelectionExprNode*) expr; + + if(!emit_instr_for_node(exeb, sel->set, break_dest, error)) + return 0; + + if(!emit_instr_for_node(exeb, sel->idx, break_dest, error)) + return 0; + + return ExeBuilder_Append(exeb, error, OPCODE_SELECT, NULL, 0, node->offset, node->length); + } + + case EXPR_NONE: + return ExeBuilder_Append(exeb, error, OPCODE_PUSHNNE, NULL, 0, node->offset, node->length); + + case EXPR_TRUE: + return ExeBuilder_Append(exeb, error, OPCODE_PUSHTRU, NULL, 0, node->offset, node->length); + + case EXPR_FALSE: + return ExeBuilder_Append(exeb, error, OPCODE_PUSHFLS, NULL, 0, node->offset, node->length); + + default: + UNREACHABLE; + break; + } + break; + } + + case NODE_BREAK: + { + if(break_dest == NULL) + { + Error_Report(error, 0, "Break not inside a loop"); + return 0; + } + Operand op = (Operand) { .type = OPTP_PROMISE, .as_promise = break_dest }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) + return 0; + return 1; + } + + case NODE_IFELSE: + { + IfElseNode *ifelse = (IfElseNode*) node; + + if(!emit_instr_for_node(exeb, ifelse->condition, break_dest, error)) + return 0; + + if(ifelse->false_branch) + { + Promise *else_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + Promise *done_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + + if(else_offset == NULL || done_offset == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + + Operand op = { .type = OPTP_PROMISE, .as_promise = else_offset }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, node->offset, node->length)) + return 0; + + if(!emit_instr_for_node(exeb, ifelse->true_branch, break_dest, error)) + return 0; + + if(ifelse->true_branch->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->true_branch->offset, 0)) + return 0; + } + + op = (Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) + return 0; + + long long int temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(else_offset, &temp, sizeof(temp)); + + if(!emit_instr_for_node(exeb, ifelse->false_branch, break_dest, error)) + return 0; + + if(ifelse->false_branch->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->false_branch->offset, 0)) return 0; } - // This is the first index after the function code. temp = ExeBuilder_InstrCount(exeb); - Promise_Resolve(jump_index, &temp, sizeof(temp)); + Promise_Resolve(done_offset, &temp, sizeof(temp)); - Promise_Free(func_index); - Promise_Free(jump_index); - return 1; + Promise_Free(else_offset); + Promise_Free(done_offset); + } + else + { + Promise *done_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + + if(done_offset == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &(Operand) { .type = OPTP_PROMISE, .as_promise = done_offset }, 1, node->offset, node->length)) + return 0; + + if(!emit_instr_for_node(exeb, ifelse->true_branch, break_dest, error)) + return 0; + + if(ifelse->true_branch->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, ifelse->true_branch->offset, 0)) + return 0; + } + + long long int temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(done_offset, &temp, sizeof(temp)); + + Promise_Free(done_offset); } - default: - UNREACHABLE; - return 0; + return 1; } + + case NODE_WHILE: + { + WhileNode *whl = (WhileNode*) node; + + /* + * start: + * + * JUMPIFNOTANDPOP end + * + * JUMP start + * end: + */ + + Promise *start_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + Promise *end_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + + if(start_offset == NULL || end_offset == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + + long long int temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(start_offset, &temp, sizeof(temp)); + + if(!emit_instr_for_node(exeb, whl->condition, break_dest, error)) + return 0; + + Operand op = { .type = OPTP_PROMISE, .as_promise = end_offset }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFNOTANDPOP, &op, 1, whl->condition->offset, whl->condition->length)) + return 0; + + if(!emit_instr_for_node(exeb, whl->body, end_offset, error)) + return 0; + + if(whl->body->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, whl->body->offset, 0)) + return 0; + } + + op = (Operand) { .type = OPTP_PROMISE, .as_promise = start_offset }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, node->offset, node->length)) + return 0; + + temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(end_offset, &temp, sizeof(temp)); + + Promise_Free(start_offset); + Promise_Free( end_offset); + return 1; + } + + case NODE_DOWHILE: + { + DoWhileNode *dowhl = (DoWhileNode*) node; + + /* + * start: + * + * + * JUMPIFANDPOP start + */ + + Promise *end_offset = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + if(end_offset == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + + long long int start = ExeBuilder_InstrCount(exeb); + + if(!emit_instr_for_node(exeb, dowhl->body, end_offset, error)) + return 0; + + if(dowhl->body->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, dowhl->body->offset, 0)) + return 0; + } + + if(!emit_instr_for_node(exeb, dowhl->condition, break_dest, error)) + return 0; + + Operand op = { .type = OPTP_INT, .as_int = start }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMPIFANDPOP, &op, 1, dowhl->condition->offset, dowhl->condition->length)) + return 0; + + long long int temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(end_offset, &temp, sizeof(temp)); + Promise_Free(end_offset); + return 1; + } + + case NODE_COMP: + { + CompoundNode *comp = (CompoundNode*) node; + + Node *stmt = comp->head; + + while(stmt) + { + if(!emit_instr_for_node(exeb, stmt, break_dest, error)) + return 0; + + if(stmt->kind == NODE_EXPR) + { + Operand op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, stmt->offset, 0)) + return 0; + } + stmt = stmt->next; + } + + return 1; + } + + case NODE_RETURN: + { + ReturnNode *ret = (ReturnNode*) node; + + if(!emit_instr_for_node(exeb, ret->val, break_dest, error)) + return 0; + + if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, ret->base.offset, ret->base.length)) + return 0; + + return 1; + } + + case NODE_FUNC: + { + FunctionNode *func = (FunctionNode*) node; + + Promise *func_index = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + Promise *jump_index = Promise_New(ExeBuilder_GetAlloc(exeb), sizeof(long long int)); + + if(func_index == NULL || jump_index == NULL) + { + Error_Report(error, 1, "No memory"); + return 0; + } + + // Push function. + { + Operand ops[2] = { + { .type = OPTP_PROMISE, .as_promise = func_index }, + { .type = OPTP_INT, .as_int = func->argc }, + }; + + if(!ExeBuilder_Append(exeb, error, OPCODE_PUSHFUN, ops, 2, func->base.offset, func->base.length)) + return 0; + } + + // Assign variable. + Operand op = (Operand) { .type = OPTP_STRING, .as_string = func->name }; + if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, func->base.offset, func->base.length)) + return 0; + + // Pop function object. + op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, func->base.offset, func->base.length)) + return 0; + + // Jump after the function code. + op = (Operand) { .type = OPTP_PROMISE, .as_promise = jump_index }; + if(!ExeBuilder_Append(exeb, error, OPCODE_JUMP, &op, 1, func->base.offset, func->base.length)) + return 0; + + // This is the function code index. + long long int temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(func_index, &temp, sizeof(temp)); + + // Compile the function body. + { + // Assign the arguments. + + if(func->argv) + { assert(func->argv->kind == NODE_ARG); } + + ArgumentNode *arg = (ArgumentNode*) func->argv; + + while(arg) + { + op = (Operand) { .type = OPTP_STRING, .as_string = arg->name }; + if(!ExeBuilder_Append(exeb, error, OPCODE_ASS, &op, 1, arg->base.offset, arg->base.length)) + return 0; + + op = (Operand) { .type = OPTP_INT, .as_int = 1 }; + if(!ExeBuilder_Append(exeb, error, OPCODE_POP, &op, 1, arg->base.offset, arg->base.length)) + return 0; + + if(arg->base.next) + { assert(arg->base.next->kind == NODE_ARG); } + + arg = (ArgumentNode*) arg->base.next; + } + + if(!emit_instr_for_node(exeb, func->body, NULL, error)) + return 0; + + // Write a return instruction, just + // in case it didn't already return. + if(!ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, func->body->offset, 0)) + return 0; + } + + // This is the first index after the function code. + temp = ExeBuilder_InstrCount(exeb); + Promise_Resolve(jump_index, &temp, sizeof(temp)); + + Promise_Free(func_index); + Promise_Free(jump_index); + return 1; + } + + default: + UNREACHABLE; + return 0; + } UNREACHABLE; return 0; } @@ -658,29 +657,29 @@ Executable *compile(AST *ast, BPAlloc *alloc, Error *error) BPAlloc *alloc2 = alloc; if(alloc2 == NULL) - { - alloc2 = BPAlloc_Init(-1); + { + alloc2 = BPAlloc_Init(-1); - if(alloc2 == NULL) - return NULL; - } + if(alloc2 == NULL) + return NULL; + } Executable *exe = NULL; ExeBuilder *exeb = ExeBuilder_New(alloc2); if(exeb != NULL) - { - if(!emit_instr_for_node(exeb, ast->root, NULL, error)) - return 0; + { + if(!emit_instr_for_node(exeb, ast->root, NULL, error)) + return 0; - if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0)) - { - exe = ExeBuilder_Finalize(exeb, error); + if(ExeBuilder_Append(exeb, error, OPCODE_RETURN, NULL, 0, Source_GetSize(ast->src), 0)) + { + exe = ExeBuilder_Finalize(exeb, error); - if(exe != NULL) - Executable_SetSource(exe, ast->src); - } + if(exe != NULL) + Executable_SetSource(exe, ast->src); } + } if(alloc == NULL) BPAlloc_Free(alloc2); diff --git a/src/compiler/parse.c b/src/compiler/parse.c index 7046c21..9e15754 100644 --- a/src/compiler/parse.c +++ b/src/compiler/parse.c @@ -138,14 +138,10 @@ static Node *parse_dowhile_statement(Context *ctx); static inline _Bool isoper(char c) { - return c == '+' || - c == '-' || - c == '*' || - c == '/' || - c == '<' || - c == '>' || - c == '!' || - c == '='; + return c == '+' || c == '-' || + c == '*' || c == '/' || + c == '<' || c == '>' || + c == '!' || c == '='; } /* Symbol: tokenize @@ -182,198 +178,196 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error) *tail = NULL; int i = 0; while(1) + { + // Skip whitespace and comments. + while(i < len && (isspace(str[i]) || str[i] == '#')) { - // Skip whitespace and comments. - while(i < len && (isspace(str[i]) || str[i] == '#')) + while(i < len && isspace(str[i])) + i += 1; + + if(i < len && str[i] == '#') + { + i += 1; + while(i < len && str[i] != '\n') + i += 1; + } + } + + if(i == len) + break; // No more tokens left. + + Token *tok = BPAlloc_Malloc(alloc, sizeof(Token)); // Allocate a token. + + if(tok == NULL) + { + // Error: No memory. + Error_Report(error, 1, "No memory"); + return NULL; + } + + if(isalpha(str[i]) || str[i] == '_') + { + tok->kind = TIDENT; + tok->offset = i; + + while(i < len && (isalpha(str[i]) || isdigit(str[i]) || str[i] == '_')) + i += 1; + + tok->length = i - tok->offset; + + static const struct { + TokenKind kind; + int size; + const char *text; + } kwords[] = { + { TKWIF, 2, "if" }, + { TKWFUN, 3, "fun" }, + { TKWNOT, 3, "not" }, + { TKWAND, 3, "and" }, + { TKWOR, 2, "or" }, + { TKWELSE, 4, "else" }, + { TKWNONE, 4, "none" }, + { TKWTRUE, 4, "true" }, + { TKWFALSE, 5, "false" }, + { TKWRETURN, 6, "return" }, + { TKWWHILE, 5, "while" }, + { TKWBREAK, 5, "break" }, + { TKWDO, 2, "do" }, + }; + + for(unsigned int i = 0; i < sizeof(kwords)/sizeof(*kwords); i += 1) + if(kwords[i].size == tok->length && !strncmp(kwords[i].text, str + tok->offset, tok->length)) { - while(i < len && isspace(str[i])) - i += 1; - - if(i < len && str[i] == '#') - { - i += 1; - - while(i < len && str[i] != '\n') - i += 1; - } + tok->kind = kwords[i].kind; + break; } + } + else if(isdigit(str[i])) + { + tok->kind = TINT; + tok->offset = i; + + while(i < len && isdigit(str[i])) + i += 1; + + if(i+1 < len && str[i] == '.' && isdigit(str[i+1])) + { + i += 1; // Consume the dot. + + tok->kind = TFLOAT; + + while(i < len && isdigit(str[i])) + i += 1; + } + + tok->length = i - tok->offset; + } + else if(str[i] == '\'' || str[i] == '"') + { + tok->kind = TSTRING; + tok->offset = i; + + char f = str[i]; + + i += 1; // Skip the starting quote. + + while(1) + { + while(i < len && str[i] != '\\' && str[i] != f) + i += 1; + + if(str[i] == '\\') + { + i += 1; // Consume the \. + if(i < len && (str[i] == '\'' || str[i] == '"')) + i += 1; + } + else break; + } if(i == len) - break; // No more tokens left. + { + Error_Report(error, 0, "Source ended inside string literal"); + return NULL; + } - Token *tok = BPAlloc_Malloc(alloc, sizeof(Token)); // Allocate a token. - - if(tok == NULL) - { - // Error: No memory. - Error_Report(error, 1, "No memory"); - return NULL; - } + i += 1; // Consume the ' or ". - if(isalpha(str[i]) || str[i] == '_') - { - tok->kind = TIDENT; - tok->offset = i; - - while(i < len && (isalpha(str[i]) || isdigit(str[i]) || str[i] == '_')) - i += 1; - - tok->length = i - tok->offset; - - static const struct { - TokenKind kind; - int size; - const char *text; - } kwords[] = { - { TKWIF, 2, "if" }, - { TKWFUN, 3, "fun" }, - { TKWNOT, 3, "not" }, - { TKWAND, 3, "and" }, - { TKWOR, 2, "or" }, - { TKWELSE, 4, "else" }, - { TKWNONE, 4, "none" }, - { TKWTRUE, 4, "true" }, - { TKWFALSE, 5, "false" }, - { TKWRETURN, 6, "return" }, - { TKWWHILE, 5, "while" }, - { TKWBREAK, 5, "break" }, - { TKWDO, 2, "do" }, - }; - - for(unsigned int i = 0; i < sizeof(kwords)/sizeof(*kwords); i += 1) - if(kwords[i].size == tok->length && !strncmp(kwords[i].text, str + tok->offset, tok->length)) - { - tok->kind = kwords[i].kind; - break; - } - } - else if(isdigit(str[i])) - { - tok->kind = TINT; - tok->offset = i; - - while(i < len && isdigit(str[i])) - i += 1; - - if(i+1 < len && str[i] == '.' && isdigit(str[i+1])) - { - i += 1; // Consume the dot. - - tok->kind = TFLOAT; - - while(i < len && isdigit(str[i])) - i += 1; - } - - tok->length = i - tok->offset; - } - else if(str[i] == '\'' || str[i] == '"') - { - tok->kind = TSTRING; - tok->offset = i; - - char f = str[i]; - - i += 1; // Skip the starting quote. - - while(1) - { - while(i < len && str[i] != '\\' && str[i] != f) - i += 1; - - if(str[i] == '\\') - { - i += 1; // Consume the \. - - if(i < len && (str[i] == '\'' || str[i] == '"')) - i += 1; - } - else break; - } - - if(i == len) - { - Error_Report(error, 0, "Source ended inside string literal"); - return NULL; - } - - i += 1; // Consume the ' or ". - - tok->length = i - tok->offset; - } - else if(isoper(str[i])) - { - tok->offset = i; - - while(i < len && isoper(str[i])) - i += 1; - - tok->length = i - tok->offset; - - // Determine the token - - static const struct { - TokenKind kind; - int size; - const char *text; - } optable[] = { - { TADD, 1, "+" }, - { TSUB, 1, "-" }, - { TMUL, 1, "*" }, - { TDIV, 1, "/" }, - { TEQL, 2, "==" }, - { TNQL, 2, "!=" }, - { TLSS, 1, "<" }, - { TLEQ, 2, "<=" }, - { TGRT, 1, ">" }, - { TGEQ, 2, ">=" }, - { TASS, 1, "=" }, - }; - - _Bool found = 0; - for(unsigned int i = 0; i < sizeof(optable)/sizeof(*optable); i += 1) - if(optable[i].size == tok->length && !strncmp(optable[i].text, str + tok->offset, tok->length)) - { - found = 1; - tok->kind = optable[i].kind; - break; - } - - if(found == 0) - { - // Not a known operator. - tok->kind = str[tok->offset]; - tok->length = 1; - i = tok->offset + 1; - } - } - else - { - tok->kind = str[i]; - tok->offset = i; - tok->length = 1; - i += 1; - } - - // Append to the token list. - if(head) - tail->next = tok; - else - head = tok; - tok->prev = tail; - tok->next = NULL; - tail = tok; + tok->length = i - tok->offset; } + else if(isoper(str[i])) + { + tok->offset = i; + + while(i < len && isoper(str[i])) + i += 1; + + tok->length = i - tok->offset; + + // Determine the token + + static const struct { + TokenKind kind; + int size; + const char *text; + } optable[] = { + { TADD, 1, "+" }, + { TSUB, 1, "-" }, + { TMUL, 1, "*" }, + { TDIV, 1, "/" }, + { TEQL, 2, "==" }, + { TNQL, 2, "!=" }, + { TLSS, 1, "<" }, + { TLEQ, 2, "<=" }, + { TGRT, 1, ">" }, + { TGEQ, 2, ">=" }, + { TASS, 1, "=" }, + }; + + _Bool found = 0; + for(unsigned int i = 0; i < sizeof(optable)/sizeof(*optable); i += 1) + if(optable[i].size == tok->length && !strncmp(optable[i].text, str + tok->offset, tok->length)) + { + found = 1; + tok->kind = optable[i].kind; + break; + } + + if(found == 0) + { + // Not a known operator. + tok->kind = str[tok->offset]; + tok->length = 1; + i = tok->offset + 1; + } + } + else + { + tok->kind = str[i]; + tok->offset = i; + tok->length = 1; + i += 1; + } + + // Append to the token list. + if(head) + tail->next = tok; + else + head = tok; + tok->prev = tail; + tok->next = NULL; + tail = tok; + } { Token *tok = BPAlloc_Malloc(alloc, sizeof(Token)); // Allocate a token. if(tok == NULL) - { - // Error: No memory. - Error_Report(error, 1, "No memory"); - return NULL; - } + { + // Error: No memory. + Error_Report(error, 1, "No memory"); + return NULL; + } tok->kind = TDONE; tok->offset = i; @@ -536,105 +530,105 @@ static Node *parse_statement(Context *ctx) assert(ctx != NULL); switch(current(ctx)) + { + default: + break; + + case '(': + case '[': + case '+': + case '-': + case TINT: + case TFLOAT: + case TSTRING: + case TIDENT: + case TKWNOT: + case TKWNONE: + case TKWTRUE: + case TKWFALSE: + return parse_expression_statement(ctx); + + case TKWIF: + return parse_ifelse_statement(ctx); + + case '{': { - default: - break; + next(ctx); // Consume the '{'. - case '(': - case '[': - case '+': - case '-': - case TINT: - case TFLOAT: - case TSTRING: - case TIDENT: - case TKWNOT: - case TKWNONE: - case TKWTRUE: - case TKWFALSE: - return parse_expression_statement(ctx); + Node *node = parse_compound_statement(ctx, '}'); - case TKWIF: - return parse_ifelse_statement(ctx); + if(node != NULL) + next(ctx); // Consume the '}'. - case '{': - { - next(ctx); // Consume the '{'. - - Node *node = parse_compound_statement(ctx, '}'); - - if(node != NULL) - next(ctx); // Consume the '}'. - - return node; - } - - case TKWBREAK: - { - Token *token = current_token(ctx); - - next(ctx); // Consume the "break". - - if(current(ctx) != ';') - { - Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - next(ctx); // Consume the ';'. - - Node *node = BPAlloc_Malloc(ctx->alloc, sizeof(Node)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->kind = NODE_BREAK; - node->next = NULL; - node->offset = token->offset; - node->length = token->length; - return node; - } - - case TKWRETURN: - { - int offset = current_token(ctx)->offset; - - next(ctx); // Consume the "return" keyword. - - Node *val = parse_expression_statement(ctx); - - if(val == NULL) - return NULL; - - ReturnNode *node = BPAlloc_Malloc(ctx->alloc, sizeof(ReturnNode)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->base.kind = NODE_RETURN; - node->base.next = NULL; - node->base.offset = offset; - node->base.length = val->offset + val->length - offset; - node->val = val; - return (Node*) node; - } - - case TKWFUN: - return parse_function_definition(ctx); - - case TKWWHILE: - return parse_while_statement(ctx); - - case TKWDO: - return parse_dowhile_statement(ctx); + return node; } + case TKWBREAK: + { + Token *token = current_token(ctx); + + next(ctx); // Consume the "break". + + if(current(ctx) != ';') + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + next(ctx); // Consume the ';'. + + Node *node = BPAlloc_Malloc(ctx->alloc, sizeof(Node)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->kind = NODE_BREAK; + node->next = NULL; + node->offset = token->offset; + node->length = token->length; + return node; + } + + case TKWRETURN: + { + int offset = current_token(ctx)->offset; + + next(ctx); // Consume the "return" keyword. + + Node *val = parse_expression_statement(ctx); + + if(val == NULL) + return NULL; + + ReturnNode *node = BPAlloc_Malloc(ctx->alloc, sizeof(ReturnNode)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.kind = NODE_RETURN; + node->base.next = NULL; + node->base.offset = offset; + node->base.length = val->offset + val->length - offset; + node->val = val; + return (Node*) node; + } + + case TKWFUN: + return parse_function_definition(ctx); + + case TKWWHILE: + return parse_while_statement(ctx); + + case TKWDO: + return parse_dowhile_statement(ctx); + } + Error_Report(ctx->error, 0, "Got token \"%.*s\" where the start of a statement was expected", ctx->token->length, ctx->src + ctx->token->offset); return NULL; @@ -650,19 +644,19 @@ static Node *parse_expression_statement(Context *ctx) return NULL; if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended right after an expression, where a ';' was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended right after an expression, where a ';' was expected"); + return NULL; + } if(current(ctx) != ';') - { - // ERROR: Got something other than a semicolon at the end - // of statement. + { + // ERROR: Got something other than a semicolon at the end + // of statement. - Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } next(ctx); return expr; @@ -682,10 +676,10 @@ static Node *makeStringExprNode(Context *ctx, const char *str, int len) copy = BPAlloc_Malloc(ctx->alloc, len + 1); if(copy == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } memcpy(copy, str, len); copy[len] = '\0'; @@ -697,10 +691,10 @@ static Node *makeStringExprNode(Context *ctx, const char *str, int len) node = BPAlloc_Malloc(ctx->alloc, sizeof(StringExprNode)); if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } node->base.base.kind = NODE_EXPR; node->base.base.next = NULL; @@ -719,16 +713,16 @@ static Node *parse_string_primary_expression(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a string literal was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a string literal was expected"); + return NULL; + } if(current(ctx) != TSTRING) - { - Error_Report(ctx->error, 0, "Got token \"%.*s\" where a string literal was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where a string literal was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } const char *src = ctx->src; int len = ctx->token->offset + ctx->token->length - 1; @@ -741,61 +735,59 @@ static Node *parse_string_primary_expression(Context *ctx) int temp_used = 0; do + { + int segm_off, segm_len; { - int segm_off, segm_len; + segm_off = i; + while(i < len && src[i] != '\\') + i += 1; + segm_len = i - segm_off; + } + + if(temp_used + segm_len >= (int) sizeof(temp)) + { + Error_Report(ctx->error, 1, "String is too big to be rendered inside the fixed size buffer"); + return NULL; + } + + memcpy(temp + temp_used, src + segm_off, segm_len); + temp_used += segm_len; + + if(src[i] == '\\') + { + i += 1; // Consume the \. + + if(temp_used + 1 >= (int) sizeof(temp)) { - segm_off = i; - - while(i < len && src[i] != '\\') - i += 1; - - segm_len = i - segm_off; + Error_Report(ctx->error, 1, "String is too big to be rendered inside the fixed size buffer"); + return NULL; } - if(temp_used + segm_len >= (int) sizeof(temp)) + if(i == len) + { + // Append the \ as a normal char. + temp[temp_used++] = '\\'; + } + else + { + switch(src[i]) { - Error_Report(ctx->error, 1, "String is too big to be rendered inside the fixed size buffer"); + case '"': temp[temp_used++] = '"'; break; + case 'n': temp[temp_used++] = '\n'; break; + case 't': temp[temp_used++] = '\t'; break; + case 'r': temp[temp_used++] = '\r'; break; + case '\\': temp[temp_used++] = '\\'; break; + case '\'': temp[temp_used++] = '\''; break; + + default: + Error_Report(ctx->error, 0, "Invalid escape sequence \\%c", src[i]); return NULL; } - memcpy(temp + temp_used, src + segm_off, segm_len); - temp_used += segm_len; - - if(src[i] == '\\') - { - i += 1; // Consume the \. - - if(temp_used + 1 >= (int) sizeof(temp)) - { - Error_Report(ctx->error, 1, "String is too big to be rendered inside the fixed size buffer"); - return NULL; - } - - if(i == len) - { - // Append the \ as a normal char. - temp[temp_used++] = '\\'; - } - else - { - switch(src[i]) - { - case '"': temp[temp_used++] = '"'; break; - case 'n': temp[temp_used++] = '\n'; break; - case 't': temp[temp_used++] = '\t'; break; - case 'r': temp[temp_used++] = '\r'; break; - case '\\': temp[temp_used++] = '\\'; break; - case '\'': temp[temp_used++] = '\''; break; - - default: - Error_Report(ctx->error, 0, "Invalid escape sequence \\%c", src[i]); - return NULL; - } - - i += 1; // Consume the char after the \. - } - } + i += 1; // Consume the char after the \. + } } + } while(i < len); assert(temp_used < (int) sizeof(temp)); @@ -812,16 +804,16 @@ static Node *parse_list_primary_expression(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a list literal was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a list literal was expected"); + return NULL; + } if(current(ctx) != '[') - { - Error_Report(ctx->error, 0, "Got token \"%.*s\" where a list literal was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where a list literal was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } int offset = current_token(ctx)->offset; @@ -831,42 +823,42 @@ static Node *parse_list_primary_expression(Context *ctx) next(ctx); // Skip the '['. if(current(ctx) != ']') + { + Node *tail = NULL; + + while(1) { - Node *tail = NULL; + // Parse. + Node *item = parse_expression(ctx); - while(1) - { - // Parse. - Node *item = parse_expression(ctx); + if(item == NULL) + return NULL; - if(item == NULL) - return NULL; + // Append. + if(tail) + tail->next = item; + else + items = item; + tail = item; + itemc += 1; - // Append. - if(tail) - tail->next = item; - else - items = item; - tail = item; - itemc += 1; + // Get ',' or ']'. - // Get ',' or ']'. + if(current(ctx) == ']') + break; - if(current(ctx) == ']') - break; + if(current(ctx) != ',') + { + if(current(ctx) == TDONE) + Error_Report(ctx->error, 0, "Source ended inside a list literal"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside list literal, where ',' or ']' were expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } - if(current(ctx) != ',') - { - if(current(ctx) == TDONE) - Error_Report(ctx->error, 0, "Source ended inside a list literal"); - else - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside list literal, where ',' or ']' were expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - next(ctx); // Skip the ','. - } + next(ctx); // Skip the ','. } + } int length = current_token(ctx)->offset + current_token(ctx)->length @@ -879,10 +871,10 @@ static Node *parse_list_primary_expression(Context *ctx) list = BPAlloc_Malloc(ctx->alloc, sizeof(ListExprNode)); if(list == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } list->base.base.kind = NODE_EXPR; list->base.base.next = NULL; @@ -902,16 +894,16 @@ static Node *parse_map_primary_expression(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a map literal was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a map literal was expected"); + return NULL; + } if(current(ctx) != '{') - { - Error_Report(ctx->error, 0, "Got token \"%.*s\" where a map literal was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where a map literal was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } int offset = current_token(ctx)->offset; @@ -922,92 +914,91 @@ static Node *parse_map_primary_expression(Context *ctx) next(ctx); // Skip the '['. if(current(ctx) != '}') + { + Node *ktail = NULL, *tail = NULL; + + while(1) { - Node *ktail = NULL, *tail = NULL; + Node *key; + _Bool key_is_a_single_ident; + { + _Bool key_starts_with_an_ident = current(ctx) == TIDENT; - while(1) - { - Node *key; + next(ctx); - _Bool key_is_a_single_ident; - { - _Bool key_starts_with_an_ident = current(ctx) == TIDENT; + key_is_a_single_ident = key_starts_with_an_ident && (current(ctx) == TDONE || current(ctx) == ':'); - next(ctx); + prev(ctx); + } - key_is_a_single_ident = key_starts_with_an_ident && (current(ctx) == TDONE || current(ctx) == ':'); + if(key_is_a_single_ident) + { + assert(current(ctx) == TIDENT); + key = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length); - prev(ctx); - } + next(ctx); + } + else + { + key = parse_expression(ctx); + } - if(key_is_a_single_ident) - { - assert(current(ctx) == TIDENT); - key = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length); + if(key == NULL) + return NULL; - next(ctx); - } - else - { - key = parse_expression(ctx); - } + if(done(ctx)) + { + Error_Report(ctx->error, 0, "Source ended where a map key-value separator ':' was expected"); + return NULL; + } - if(key == NULL) - return NULL; + if(current(ctx) != ':') + { + Error_Report(ctx->error, 0, "Got token \"%.*s\" where a map key-value separator ':' was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } - if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a map key-value separator ':' was expected"); - return NULL; - } + next(ctx); - if(current(ctx) != ':') - { - Error_Report(ctx->error, 0, "Got token \"%.*s\" where a map key-value separator ':' was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + // Parse. + Node *item = parse_expression(ctx); - next(ctx); + if(item == NULL) + return NULL; - // Parse. - Node *item = parse_expression(ctx); + // Append. + if(tail) + { + ktail->next = key; + tail->next = item; + } + else + { + keys = key; + items = item; + } - if(item == NULL) - return NULL; + ktail = key; + tail = item; + itemc += 1; - // Append. - if(tail) - { - ktail->next = key; - tail->next = item; - } - else - { - keys = key; - items = item; - } + // Get ',' or '}'. - ktail = key; - tail = item; - itemc += 1; + if(current(ctx) == '}') + break; - // Get ',' or '}'. + if(current(ctx) != ',') + { + if(current(ctx) == TDONE) + Error_Report(ctx->error, 0, "Source ended inside a map literal"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside map literal, where ',' or '}' were expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } - if(current(ctx) == '}') - break; - - if(current(ctx) != ',') - { - if(current(ctx) == TDONE) - Error_Report(ctx->error, 0, "Source ended inside a map literal"); - else - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside map literal, where ',' or '}' were expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - next(ctx); // Skip the ','. - } + next(ctx); // Skip the ','. } + } int length = current_token(ctx)->offset + current_token(ctx)->length @@ -1020,10 +1011,10 @@ static Node *parse_map_primary_expression(Context *ctx) map = BPAlloc_Malloc(ctx->alloc, sizeof(MapExprNode)); if(map == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } map->base.base.kind = NODE_EXPR; map->base.base.next = NULL; @@ -1059,20 +1050,20 @@ static Node *makeIdentExprNode(Context *ctx) int copyl = ctx->token->length; if(copy == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } IdentExprNode *node; { node = BPAlloc_Malloc(ctx->alloc, sizeof(IdentExprNode)); if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } node->base.base.kind = NODE_EXPR; node->base.base.next = NULL; @@ -1091,234 +1082,233 @@ static Node *parse_primary_expresion(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a primary expression was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a primary expression was expected"); + return NULL; + } + switch(current(ctx)) + { + case '[': + return parse_list_primary_expression(ctx); + + case '{': + return parse_map_primary_expression(ctx); + + case '(': { - case '[': - return parse_list_primary_expression(ctx); + next(ctx); // Consume the '('. + + Node *node = parse_expression(ctx); + + if(node == NULL) + return NULL; - case '{': - return parse_map_primary_expression(ctx); - - case '(': + if(done(ctx)) { - next(ctx); // Consume the '('. - - Node *node = parse_expression(ctx); - - if(node == NULL) - return NULL; - - if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended before \")\", after sub-expression"); - return NULL; - } - - if(current(ctx) != ')') - { - Error_Report(ctx->error, 0, "Missing \")\", after sub-expression"); - return NULL; - } - - next(ctx); // Consume the ')'. - return node; + Error_Report(ctx->error, 0, "Source ended before \")\", after sub-expression"); + return NULL; } - case TINT: + if(current(ctx) != ')') { - char buffer[64]; - - if(ctx->token->length >= (int) sizeof(buffer)) - { - Error_Report(ctx->error, 1, "Integer is too big"); - return NULL; - } - - memcpy(buffer, ctx->src + ctx->token->offset, ctx->token->length); - buffer[ctx->token->length] = '\0'; - - errno = 0; - - long long int val = strtoll(buffer, NULL, 10); - - if(errno == ERANGE) - { - Error_Report(ctx->error, 1, "Integer is too big"); - return NULL; - } - else assert(errno == 0); - - IntExprNode *node; - { - node = BPAlloc_Malloc(ctx->alloc, sizeof(IntExprNode)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->base.base.kind = NODE_EXPR; - node->base.base.next = NULL; - node->base.base.offset = ctx->token->offset; - node->base.base.length = ctx->token->length; - node->base.kind = EXPR_INT; - node->val = val; - } - - next(ctx); - - return (Node*) node; + Error_Report(ctx->error, 0, "Missing \")\", after sub-expression"); + return NULL; } - - case TFLOAT: - { - char buffer[64]; - - if(ctx->token->length >= (int) sizeof(buffer)) - { - Error_Report(ctx->error, 1, "Floating is too big"); - return NULL; - } - - memcpy(buffer, ctx->src + ctx->token->offset, ctx->token->length); - buffer[ctx->token->length] = '\0'; - - errno = 0; - - double val = strtod(buffer, NULL); - - if(errno == ERANGE) - { - Error_Report(ctx->error, 1, "Floating is too big"); - return NULL; - } - else assert(errno == 0); - - FloatExprNode *node; - { - node = BPAlloc_Malloc(ctx->alloc, sizeof(FloatExprNode)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->base.base.kind = NODE_EXPR; - node->base.base.next = NULL; - node->base.base.offset = ctx->token->offset; - node->base.base.length = ctx->token->length; - node->base.kind = EXPR_FLOAT; - node->val = val; - } - - next(ctx); - - return (Node*) node; - } - - case TSTRING: - return parse_string_primary_expression(ctx); - - case TKWNONE: - { - next(ctx); - - ExprNode *node; - { - node = BPAlloc_Malloc(ctx->alloc, sizeof(ExprNode)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->base.kind = NODE_EXPR; - node->base.next = NULL; - node->base.offset = ctx->token->offset; - node->base.length = ctx->token->length; - node->kind = EXPR_NONE; - } - - return (Node*) node; - } - - case TKWTRUE: - { - next(ctx); - - ExprNode *node; - { - node = BPAlloc_Malloc(ctx->alloc, sizeof(ExprNode)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->base.kind = NODE_EXPR; - node->base.next = NULL; - node->base.offset = ctx->token->offset; - node->base.length = ctx->token->length; - node->kind = EXPR_TRUE; - } - - return (Node*) node; - } - - case TKWFALSE: - { - next(ctx); - - ExprNode *node; - { - node = BPAlloc_Malloc(ctx->alloc, sizeof(ExprNode)); - - if(node == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - node->base.kind = NODE_EXPR; - node->base.next = NULL; - node->base.offset = ctx->token->offset; - node->base.length = ctx->token->length; - node->kind = EXPR_FALSE; - } - - return (Node*) node; - } - - case TIDENT: - { - Node *node = makeIdentExprNode(ctx); - - if(node == NULL) - return NULL; - - next(ctx); - - return (Node*) node; - } - - case TDONE: - Error_Report(ctx->error, 1, "Unexpected end of source where a primary expression was expected"); - return NULL; - - default: - Error_Report(ctx->error, 1, "Unexpected token \"%.*s\" where a primary expression was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; + next(ctx); // Consume the ')'. + return node; } + case TINT: + { + char buffer[64]; + + if(ctx->token->length >= (int) sizeof(buffer)) + { + Error_Report(ctx->error, 1, "Integer is too big"); + return NULL; + } + + memcpy(buffer, ctx->src + ctx->token->offset, ctx->token->length); + buffer[ctx->token->length] = '\0'; + + errno = 0; + + long long int val = strtoll(buffer, NULL, 10); + + if(errno == ERANGE) + { + Error_Report(ctx->error, 1, "Integer is too big"); + return NULL; + } + else assert(errno == 0); + + IntExprNode *node; + { + node = BPAlloc_Malloc(ctx->alloc, sizeof(IntExprNode)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.base.kind = NODE_EXPR; + node->base.base.next = NULL; + node->base.base.offset = ctx->token->offset; + node->base.base.length = ctx->token->length; + node->base.kind = EXPR_INT; + node->val = val; + } + + next(ctx); + + return (Node*) node; + } + + case TFLOAT: + { + char buffer[64]; + + if(ctx->token->length >= (int) sizeof(buffer)) + { + Error_Report(ctx->error, 1, "Floating is too big"); + return NULL; + } + + memcpy(buffer, ctx->src + ctx->token->offset, ctx->token->length); + buffer[ctx->token->length] = '\0'; + + errno = 0; + + double val = strtod(buffer, NULL); + + if(errno == ERANGE) + { + Error_Report(ctx->error, 1, "Floating is too big"); + return NULL; + } + else assert(errno == 0); + + FloatExprNode *node; + { + node = BPAlloc_Malloc(ctx->alloc, sizeof(FloatExprNode)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.base.kind = NODE_EXPR; + node->base.base.next = NULL; + node->base.base.offset = ctx->token->offset; + node->base.base.length = ctx->token->length; + node->base.kind = EXPR_FLOAT; + node->val = val; + } + + next(ctx); + + return (Node*) node; + } + + case TSTRING: + return parse_string_primary_expression(ctx); + + case TKWNONE: + { + next(ctx); + + ExprNode *node; + { + node = BPAlloc_Malloc(ctx->alloc, sizeof(ExprNode)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.kind = NODE_EXPR; + node->base.next = NULL; + node->base.offset = ctx->token->offset; + node->base.length = ctx->token->length; + node->kind = EXPR_NONE; + } + + return (Node*) node; + } + + case TKWTRUE: + { + next(ctx); + + ExprNode *node; + { + node = BPAlloc_Malloc(ctx->alloc, sizeof(ExprNode)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.kind = NODE_EXPR; + node->base.next = NULL; + node->base.offset = ctx->token->offset; + node->base.length = ctx->token->length; + node->kind = EXPR_TRUE; + } + + return (Node*) node; + } + + case TKWFALSE: + { + next(ctx); + + ExprNode *node; + { + node = BPAlloc_Malloc(ctx->alloc, sizeof(ExprNode)); + + if(node == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + node->base.kind = NODE_EXPR; + node->base.next = NULL; + node->base.offset = ctx->token->offset; + node->base.length = ctx->token->length; + node->kind = EXPR_FALSE; + } + return (Node*) node; + } + + case TIDENT: + { + Node *node = makeIdentExprNode(ctx); + + if(node == NULL) + return NULL; + + next(ctx); + + return (Node*) node; + } + + case TDONE: + Error_Report(ctx->error, 1, "Unexpected end of source where a primary expression was expected"); + return NULL; + + default: + Error_Report(ctx->error, 1, "Unexpected token \"%.*s\" where a primary expression was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + UNREACHABLE; return NULL; } @@ -1328,10 +1318,10 @@ static Node *makeIndexSelectionExprNode(Context *ctx, Node *set, Node *idx) IndexSelectionExprNode *sel = BPAlloc_Malloc(ctx->alloc, sizeof(IndexSelectionExprNode)); if(sel == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } sel->base.base.kind = NODE_EXPR; sel->base.base.next = NULL; @@ -1353,147 +1343,142 @@ static Node *parse_postfix_expression(Context *ctx) return NULL; while(1) + { + switch(current(ctx)) { - switch(current(ctx)) + case '.': + { + next(ctx); + + // We expect an identifier after the dot. + + if(done(ctx)) { - case '.': - { - next(ctx); + Error_Report(ctx->error, 0, "Source ended after dot of dot selection expression"); + return NULL; + } - // We expect an identifier after the dot. + if(current(ctx) != TIDENT) + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after fot of dot selection expression where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } - if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended after dot of dot selection expression"); - return NULL; - } + Node *idx = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length); + if(idx == NULL) + return NULL; - if(current(ctx) != TIDENT) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after fot of dot selection expression where an identifier was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + Node *sel = makeIndexSelectionExprNode(ctx, node, idx); + if(sel == NULL) + return NULL; - Node *idx = makeStringExprNode(ctx, ctx->src + ctx->token->offset, ctx->token->length); + sel->offset = node->offset; + sel->length = idx->offset + idx->length - node->offset; - if(idx == NULL) - return NULL; + next(ctx); // Get to the token after the identifier. - Node *sel = makeIndexSelectionExprNode(ctx, node, idx); + node = (Node*) sel; + break; + } - if(sel == NULL) - return NULL; + case '[': + { + Node *idx = parse_list_primary_expression(ctx); + if(idx == NULL) + return NULL; - sel->offset = node->offset; - sel->length = idx->offset + idx->length - node->offset; + ListExprNode *ls = (ListExprNode*) idx; - next(ctx); // Get to the token after the identifier. + if(ls->itemc == 0) + { + Error_Report(ctx->error, 0, "Missing index in index selection expression"); + return NULL; + } - node = (Node*) sel; - break; - } + Node *sel = makeIndexSelectionExprNode(ctx, node, ls->itemc == 1 ? ls->items : (Node*) ls); + if(sel == NULL) + return NULL; - case '[': - { - Node *idx = parse_list_primary_expression(ctx); + sel->offset = node->offset; + sel->length = idx->offset + idx->length - node->offset; - if(idx == NULL) - return NULL; + node = (Node*) sel; + break; + } - ListExprNode *ls = (ListExprNode*) idx; + case '(': + { + int offset = current_token(ctx)->offset; - if(ls->itemc == 0) - { - Error_Report(ctx->error, 0, "Missing index in index selection expression"); - return NULL; - } - - Node *sel = makeIndexSelectionExprNode(ctx, node, ls->itemc == 1 ? ls->items : (Node*) ls); - - if(sel == NULL) - return NULL; - - sel->offset = node->offset; - sel->length = idx->offset + idx->length - node->offset; - - node = (Node*) sel; - break; - } - - case '(': - { - int offset = current_token(ctx)->offset; - - Node *argv = NULL; - int argc = 0; + Node *argv = NULL; + int argc = 0; - next(ctx); // Skip the '('. + next(ctx); // Skip the '('. - if(current(ctx) != ')') - while(1) - { - // Parse. - Node *arg = parse_expression(ctx); + if(current(ctx) != ')') + while(1) + { + // Parse. + Node *arg = parse_expression(ctx); - if(arg == NULL) - return NULL; + if(arg == NULL) + return NULL; - // Append. - arg->next = argv; - argv = arg; - argc += 1; + // Append. + arg->next = argv; + argv = arg; + argc += 1; - // Get ',' or ')'. + // Get ',' or ')'. - if(current(ctx) == ')') - break; + if(current(ctx) == ')') + break; - if(current(ctx) != ',') - { - if(current(ctx) == TDONE) - Error_Report(ctx->error, 0, "Source ended inside a function argument list"); - else - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - next(ctx); // Skip the ','. - } - - int length = current_token(ctx)->offset - + current_token(ctx)->length - - offset; - - next(ctx); // Skip the ')'. - - CallExprNode *call; + if(current(ctx) != ',') { - call = BPAlloc_Malloc(ctx->alloc, sizeof(CallExprNode)); - - if(call == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - call->base.base.kind = NODE_EXPR; - call->base.base.next = NULL; - call->base.base.offset = offset; - call->base.base.length = length; - call->base.kind = EXPR_CALL; - call->func = node; - call->argv = argv; - call->argc = argc; + if(current(ctx) == TDONE) + Error_Report(ctx->error, 0, "Source ended inside a function argument list"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; } - node = (Node*) call; - break; + next(ctx); // Skip the ','. } - default: - goto done; - } // End switch. - } // End loop. + int length = current_token(ctx)->offset + + current_token(ctx)->length + - offset; + + next(ctx); // Skip the ')'. + + CallExprNode *call; + { + call = BPAlloc_Malloc(ctx->alloc, sizeof(CallExprNode)); + + if(call == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + call->base.base.kind = NODE_EXPR; + call->base.base.next = NULL; + call->base.base.offset = offset; + call->base.base.length = length; + call->base.kind = EXPR_CALL; + call->func = node; + call->argv = argv; + call->argc = argc; + } + node = (Node*) call; + break; + } + + default: + goto done; + } // End switch. + } // End loop. done: return node; @@ -1502,57 +1487,57 @@ done: static Node *parse_prefix_expression(Context *ctx) { if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a prefix expression was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a prefix expression was expected"); + return NULL; + } switch(current(ctx)) + { + case TDONE: + Error_Report(ctx->error, 1, "Unexpected end of source where a prefix expression was expected"); + return NULL; + + case '+': + case '-': + case TKWNOT: { - case TDONE: - Error_Report(ctx->error, 1, "Unexpected end of source where a prefix expression was expected"); - return NULL; + Token *unary_operator = current_token(ctx); - case '+': - case '-': - case TKWNOT: - { - Token *unary_operator = current_token(ctx); + next(ctx); - next(ctx); - - Node *operand = parse_prefix_expression(ctx); + Node *operand = parse_prefix_expression(ctx); - if(operand == NULL) + if(operand == NULL) + return NULL; + + OperExprNode *temp = BPAlloc_Malloc(ctx->alloc, sizeof(OperExprNode)); + { + if(temp == NULL) return NULL; - OperExprNode *temp = BPAlloc_Malloc(ctx->alloc, sizeof(OperExprNode)); + temp->base.base.kind = NODE_EXPR; + temp->base.base.next = NULL; + temp->base.base.offset = unary_operator->offset; + temp->base.base.length = operand->offset + operand->length - unary_operator->offset; + temp->head = operand; + temp->count = 1; + + switch(unary_operator->kind) { - if(temp == NULL) - return NULL; - - temp->base.base.kind = NODE_EXPR; - temp->base.base.next = NULL; - temp->base.base.offset = unary_operator->offset; - temp->base.base.length = operand->offset + operand->length - unary_operator->offset; - temp->head = operand; - temp->count = 1; - - switch(unary_operator->kind) - { - case '+': temp->base.kind = EXPR_POS; break; - case '-': temp->base.kind = EXPR_NEG; break; - case TKWNOT: temp->base.kind = EXPR_NOT; break; - default: assert(0); break; - } + case '+': temp->base.kind = EXPR_POS; break; + case '-': temp->base.kind = EXPR_NEG; break; + case TKWNOT: temp->base.kind = EXPR_NOT; break; + default: assert(0); break; } - return (Node*) temp; } - - default: - return parse_postfix_expression(ctx); + return (Node*) temp; } + default: + return parse_postfix_expression(ctx); + } + UNREACHABLE; return NULL; } @@ -1561,18 +1546,12 @@ static inline _Bool isbinop(Token *tok) { assert(tok != NULL); - return tok->kind == '+' || - tok->kind == '-' || - tok->kind == '*' || - tok->kind == '/' || - tok->kind == '<' || - tok->kind == '>' || - tok->kind == TLEQ || - tok->kind == TGEQ || - tok->kind == TEQL || - tok->kind == TNQL || - tok->kind == TKWAND || - tok->kind == TKWOR || + return tok->kind == '+' || tok->kind == '-' || + tok->kind == '*' || tok->kind == '/' || + tok->kind == '<' || tok->kind == '>' || + tok->kind == TLEQ || tok->kind == TGEQ || + tok->kind == TEQL || tok->kind == TNQL || + tok->kind == TKWAND || tok->kind == TKWOR || tok->kind == '='; } @@ -1588,35 +1567,35 @@ static inline int precedenceof(Token *tok) assert(tok != NULL); switch(tok->kind) - { - case '=': - return 0; + { + case '=': + return 0; - case TKWOR: - return 1; + case TKWOR: + return 1; - case TKWAND: - return 2; + case TKWAND: + return 2; - case '<': - case '>': - case TLEQ: - case TGEQ: - case TEQL: - case TNQL: - return 3; + case '<': + case '>': + case TLEQ: + case TGEQ: + case TEQL: + case TNQL: + return 3; - case '+': - case '-': - return 4; + case '+': + case '-': + return 4; - case '*': - case '/': - return 5; - - default: - return -100000000; - } + case '*': + case '/': + return 5; + + default: + return -100000000; + } UNREACHABLE; return -100000000; @@ -1625,69 +1604,69 @@ static inline int precedenceof(Token *tok) static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec) { while(isbinop(ctx->token) && precedenceof(ctx->token) >= min_prec) + { + Token *op = ctx->token; + + next(ctx); + + Node *right_expr = parse_prefix_expression(ctx); + + if(right_expr == NULL) + return NULL; + + while(isbinop(ctx->token) && (precedenceof(ctx->token) > precedenceof(op) || (precedenceof(ctx->token) == precedenceof(op) && isrightassoc(ctx->token)))) { - Token *op = ctx->token; - - next(ctx); - - Node *right_expr = parse_prefix_expression(ctx); - + right_expr = parse_expression_2(ctx, right_expr, precedenceof(op) + 1); + if(right_expr == NULL) - return NULL; + return NULL; + } - while(isbinop(ctx->token) && (precedenceof(ctx->token) > precedenceof(op) || (precedenceof(ctx->token) == precedenceof(op) && isrightassoc(ctx->token)))) - { - right_expr = parse_expression_2(ctx, right_expr, precedenceof(op) + 1); - - if(right_expr == NULL) - return NULL; - } + OperExprNode *temp; + { + temp = BPAlloc_Malloc(ctx->alloc, sizeof(OperExprNode)); - OperExprNode *temp; + if(temp == NULL) { - temp = BPAlloc_Malloc(ctx->alloc, sizeof(OperExprNode)); - - if(temp == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - temp->base.base.kind = NODE_EXPR; - temp->base.base.next = NULL; - temp->base.base.offset = left_expr->offset; - temp->base.base.length = right_expr->offset + right_expr->length - left_expr->offset; - - switch(op->kind) - { - case '+': temp->base.kind = EXPR_ADD; break; - case '-': temp->base.kind = EXPR_SUB; break; - case '*': temp->base.kind = EXPR_MUL; break; - case '/': temp->base.kind = EXPR_DIV; break; - case '<': temp->base.kind = EXPR_LSS; break; - case '>': temp->base.kind = EXPR_GRT; break; - case TLEQ: temp->base.kind = EXPR_LEQ; break; - case TGEQ: temp->base.kind = EXPR_GEQ; break; - case TEQL: temp->base.kind = EXPR_EQL; break; - case TNQL: temp->base.kind = EXPR_NQL; break; - case TKWAND: temp->base.kind = EXPR_AND; break; - case TKWOR: temp->base.kind = EXPR_OR; break; - case '=': temp->base.kind = EXPR_ASS; break; - - default: - UNREACHABLE; - break; - } - - temp->head = left_expr; - temp->head->next = right_expr; - temp->count = 2; - assert(right_expr->next == NULL); + Error_Report(ctx->error, 1, "No memory"); + return NULL; } - left_expr = (Node*) temp; + temp->base.base.kind = NODE_EXPR; + temp->base.base.next = NULL; + temp->base.base.offset = left_expr->offset; + temp->base.base.length = right_expr->offset + right_expr->length - left_expr->offset; + + switch(op->kind) + { + case '+': temp->base.kind = EXPR_ADD; break; + case '-': temp->base.kind = EXPR_SUB; break; + case '*': temp->base.kind = EXPR_MUL; break; + case '/': temp->base.kind = EXPR_DIV; break; + case '<': temp->base.kind = EXPR_LSS; break; + case '>': temp->base.kind = EXPR_GRT; break; + case TLEQ: temp->base.kind = EXPR_LEQ; break; + case TGEQ: temp->base.kind = EXPR_GEQ; break; + case TEQL: temp->base.kind = EXPR_EQL; break; + case TNQL: temp->base.kind = EXPR_NQL; break; + case TKWAND: temp->base.kind = EXPR_AND; break; + case TKWOR: temp->base.kind = EXPR_OR; break; + case '=': temp->base.kind = EXPR_ASS; break; + + default: + UNREACHABLE; + break; + } + + temp->head = left_expr; + temp->head->next = right_expr; + temp->count = 2; + assert(right_expr->next == NULL); } + left_expr = (Node*) temp; + } + return left_expr; } @@ -1709,16 +1688,16 @@ static Node *parse_ifelse_statement(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where an if-else statement was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where an if-else statement was expected"); + return NULL; + } if(current(ctx) != TKWIF) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an if-else statement was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an if-else statement was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } Token *if_token = current_token(ctx); assert(if_token != NULL); @@ -1731,16 +1710,16 @@ static Node *parse_ifelse_statement(Context *ctx) return NULL; if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended right after an if-else condition, where a ':' was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended right after an if-else condition, where a ':' was expected"); + return NULL; + } if(current(ctx) != ':') - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after an if-else condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after an if-else condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } next(ctx); // Skip the ':'. @@ -1752,25 +1731,25 @@ static Node *parse_ifelse_statement(Context *ctx) Node *false_branch = NULL; if(ctx->token->kind == TKWELSE) - { - next(ctx); // Consume the "else" token. + { + next(ctx); // Consume the "else" token. - false_branch = parse_statement(ctx); + false_branch = parse_statement(ctx); - if(false_branch == NULL) - return NULL; - } + if(false_branch == NULL) + return NULL; + } IfElseNode *ifelse; { ifelse = BPAlloc_Malloc(ctx->alloc, sizeof(IfElseNode)); if(ifelse == NULL) - { - // ERROR: No memory. - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + // ERROR: No memory. + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } ifelse->base.kind = NODE_IFELSE; ifelse->base.next = NULL; @@ -1793,34 +1772,34 @@ static Node *parse_compound_statement(Context *ctx, TokenKind end) *tail = NULL; while(current(ctx) != end && current(ctx) != TDONE) - { - Node *temp = parse_statement(ctx); + { + Node *temp = parse_statement(ctx); - if(temp == NULL) - return NULL; + if(temp == NULL) + return NULL; - *tail = temp; - tail = &temp->next; + *tail = temp; + tail = &temp->next; - end_offset = temp->offset + temp->length; - } + end_offset = temp->offset + temp->length; + } if(current(ctx) != end) - { - Error_Report(ctx->error, 0, "Source ended inside compound statement"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended inside compound statement"); + return NULL; + } CompoundNode *node; { node = BPAlloc_Malloc(ctx->alloc, sizeof(CompoundNode)); if(node == NULL) - { - // ERROR: No memory. - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + // ERROR: No memory. + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } node->base.kind = NODE_COMP; node->base.next = NULL; @@ -1837,126 +1816,126 @@ static Node *parse_function_definition(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a function definition was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a function definition was expected"); + return NULL; + } if(current(ctx) != TKWFUN) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function definition was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } int offset = current_token(ctx)->offset; if(next(ctx) != TIDENT) - { - if(done(ctx)) - Error_Report(ctx->error, 0, "Source ended where an identifier was expected as function name"); - else - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an identifier was expected as function name", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + if(done(ctx)) + Error_Report(ctx->error, 0, "Source ended where an identifier was expected as function name"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where an identifier was expected as function name", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } char *name = copy_token_text(ctx); if(name == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } if(next(ctx) != '(') - { - if(done(ctx)) - Error_Report(ctx->error, 0, "Source ended where a function argument list was expected"); - else - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function argument list was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + if(done(ctx)) + Error_Report(ctx->error, 0, "Source ended where a function argument list was expected"); + else + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function argument list was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } Node *argv = NULL; int argc = 0; if(next(ctx) != ')') + { + // Parse arguments. + + while(1) { - // Parse arguments. + if(done(ctx)) + { + Error_Report(ctx->error, 0, "Source ended inside a function argument list"); + return NULL; + } - while(1) + if(current(ctx) != TIDENT) + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function argument name was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + char *arg_name = copy_token_text(ctx); + + if(arg_name == NULL) + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } + + ArgumentNode *arg; + { + // Make argument node. + arg = BPAlloc_Malloc(ctx->alloc, sizeof(ArgumentNode)); + + if(arg == NULL) { - if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended inside a function argument list"); - return NULL; - } - - if(current(ctx) != TIDENT) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a function argument name was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - char *arg_name = copy_token_text(ctx); - - if(arg_name == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - ArgumentNode *arg; - { - // Make argument node. - arg = BPAlloc_Malloc(ctx->alloc, sizeof(ArgumentNode)); - - if(arg == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } - - arg->base.kind = NODE_ARG; - arg->base.next = NULL; - arg->base.offset = current_token(ctx)->offset; - arg->base.length = current_token(ctx)->length; - arg->name = arg_name; - } - - // Add it to the list. - argc += 1; - arg->base.next = argv; - argv = (Node*) arg; - - // Get either ',' or ')'. - - if(next(ctx) == ')') - break; - - if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended inside a function argument list"); - return NULL; - } - - if(current(ctx) != ',') - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside function argument list, where either ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } - - // Now prepare for the next identifier. - next(ctx); + Error_Report(ctx->error, 1, "No memory"); + return NULL; } + + arg->base.kind = NODE_ARG; + arg->base.next = NULL; + arg->base.offset = current_token(ctx)->offset; + arg->base.length = current_token(ctx)->length; + arg->name = arg_name; + } + + // Add it to the list. + argc += 1; + arg->base.next = argv; + argv = (Node*) arg; + + // Get either ',' or ')'. + + if(next(ctx) == ')') + break; + + if(done(ctx)) + { + Error_Report(ctx->error, 0, "Source ended inside a function argument list"); + return NULL; + } + + if(current(ctx) != ',') + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" inside function argument list, where either ',' or ')' were expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } + + // Now prepare for the next identifier. + next(ctx); } + } next(ctx); // Consume the ')'. if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended before function body"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended before function body"); + return NULL; + } Node *body = parse_statement(ctx); @@ -1969,10 +1948,10 @@ static Node *parse_function_definition(Context *ctx) func = BPAlloc_Malloc(ctx->alloc, sizeof(FunctionNode)); if(func == NULL) - { - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } func->base.kind = NODE_FUNC; func->base.next = NULL; @@ -1992,16 +1971,16 @@ static Node *parse_while_statement(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a while statement was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a while statement was expected"); + return NULL; + } if(current(ctx) != TKWWHILE) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a while statement was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a while statement was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } Token *while_token = current_token(ctx); assert(while_token != NULL); @@ -2014,16 +1993,16 @@ static Node *parse_while_statement(Context *ctx) return NULL; if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended right after a while loop condition, where a ':' was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended right after a while loop condition, where a ':' was expected"); + return NULL; + } if(current(ctx) != ':') - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after a while loop condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after a while loop condition, where a ':' was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } next(ctx); // Skip the ':'. @@ -2037,11 +2016,11 @@ static Node *parse_while_statement(Context *ctx) whl = BPAlloc_Malloc(ctx->alloc, sizeof(WhileNode)); if(whl == NULL) - { - // ERROR: No memory. - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + // ERROR: No memory. + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } whl->base.kind = NODE_WHILE; whl->base.next = NULL; @@ -2059,16 +2038,16 @@ static Node *parse_dowhile_statement(Context *ctx) assert(ctx != NULL); if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended where a do-while statement was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended where a do-while statement was expected"); + return NULL; + } if(current(ctx) != TKWDO) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a do-while statement was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" where a do-while statement was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } Token *do_token = current_token(ctx); assert(do_token != NULL); @@ -2081,16 +2060,16 @@ static Node *parse_dowhile_statement(Context *ctx) return NULL; if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended right after a do-while body, where the \"while\" keyword was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended right after a do-while body, where the \"while\" keyword was expected"); + return NULL; + } if(current(ctx) != TKWWHILE) - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after a do-while body, where the \"while\" keyword was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after a do-while body, where the \"while\" keyword was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } next(ctx); // Consume the "while" keyword. @@ -2100,16 +2079,16 @@ static Node *parse_dowhile_statement(Context *ctx) return NULL; if(done(ctx)) - { - Error_Report(ctx->error, 0, "Source ended right after a do-while condition, where a ';' was expected"); - return NULL; - } + { + Error_Report(ctx->error, 0, "Source ended right after a do-while condition, where a ';' was expected"); + return NULL; + } if(current(ctx) != ';') - { - Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after a do-while conditnion, where a ';' was expected", ctx->token->length, ctx->src + ctx->token->offset); - return NULL; - } + { + Error_Report(ctx->error, 0, "Got unexpected token \"%.*s\" after a do-while conditnion, where a ';' was expected", ctx->token->length, ctx->src + ctx->token->offset); + return NULL; + } next(ctx); // Skip the ';'. @@ -2118,11 +2097,11 @@ static Node *parse_dowhile_statement(Context *ctx) dowhl = BPAlloc_Malloc(ctx->alloc, sizeof(DoWhileNode)); if(dowhl == NULL) - { - // ERROR: No memory. - Error_Report(ctx->error, 1, "No memory"); - return NULL; - } + { + // ERROR: No memory. + Error_Report(ctx->error, 1, "No memory"); + return NULL; + } dowhl->base.kind = NODE_DOWHILE; dowhl->base.next = NULL; diff --git a/src/main.c b/src/main.c index 4e19ab6..27c202b 100644 --- a/src/main.c +++ b/src/main.c @@ -57,14 +57,14 @@ static void print_error(const char *type, Error *error) #ifdef DEBUG if(error->file != NULL) - { - if(error->line > 0 && error->func != NULL) - fprintf(stderr, " (Reported in %s:%d in %s)", error->file, error->line, error->func); - else if(error->line > 0 && error->func == NULL) - fprintf(stderr, " (Reported in %s:%d)", error->file, error->line); - else if(error->line < 1 && error->func != NULL) - fprintf(stderr, " (Reported in %s in %s)", error->file, error->func); - } + { + if(error->line > 0 && error->func != NULL) + fprintf(stderr, " (Reported in %s:%d in %s)", error->file, error->line, error->func); + else if(error->line > 0 && error->func == NULL) + fprintf(stderr, " (Reported in %s:%d)", error->file, error->line); + else if(error->line < 1 && error->func != NULL) + fprintf(stderr, " (Reported in %s in %s)", error->file, error->func); + } #endif fprintf(stderr, "\n"); @@ -78,10 +78,10 @@ static Executable *build(Source *src) BPAlloc *alloc = BPAlloc_Init(-1); if(alloc == NULL) - { - fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n"); - return 0; - } + { + fprintf(stderr, "Internal Error: Couldn't allocate bump-pointer allocator to hold the AST.\n"); + return 0; + } Error error; Error_Init(&error); @@ -91,13 +91,13 @@ static Executable *build(Source *src) AST *ast = parse(src, alloc, &error); if(ast == NULL) - { - assert(error.occurred); - print_error("Parsing", &error); - Error_Free(&error); - BPAlloc_Free(alloc); - return 0; - } + { + assert(error.occurred); + print_error("Parsing", &error); + Error_Free(&error); + BPAlloc_Free(alloc); + return 0; + } exe = compile(ast, alloc, &error); @@ -106,12 +106,12 @@ static Executable *build(Source *src) BPAlloc_Free(alloc); if(exe == NULL) - { - assert(error.occurred); - print_error("Compilation", &error); - Error_Free(&error); - return 0; - } + { + assert(error.occurred); + print_error("Compilation", &error); + Error_Free(&error); + return 0; + } return exe; } @@ -123,18 +123,18 @@ static _Bool interpret(Source *src) if(exe == NULL) return 0; - Runtime *runt = Runtime_New(-1, -1, NULL, NULL); + Runtime *runt = Runtime_New(-1, 1024*1024, NULL, NULL); if(runt == NULL) - { - Error error; - Error_Init(&error); - Error_Report(&error, 1, "Couldn't initialize runtime"); - print_error(NULL, &error); - Error_Free(&error); - Executable_Free(exe); - return 0; - } + { + Error error; + Error_Init(&error); + Error_Report(&error, 1, "Couldn't initialize runtime"); + print_error(NULL, &error); + Error_Free(&error); + Executable_Free(exe); + return 0; + } // We use a [RuntimeError] instead of a simple [Error] // 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); if(bins == NULL) - { - assert(error.base.occurred == 1); - print_error(NULL, (Error*) &error); - RuntimeError_Free(&error); - Executable_Free(exe); - Runtime_Free(runt); - return 0; - } + { + assert(error.base.occurred == 1); + print_error(NULL, (Error*) &error); + RuntimeError_Free(&error); + Executable_Free(exe); + Runtime_Free(runt); + return 0; + } Runtime_SetBuiltins(runt, bins); @@ -165,16 +165,16 @@ static _Bool interpret(Source *src) // now because it may be moved by the garbage collector. if(o == NULL) - { - print_error("Runtime", (Error*) &error); + { + print_error("Runtime", (Error*) &error); - if(error.snapshot == NULL) - fprintf(stderr, "No snapshot available.\n"); - else - Snapshot_Print(error.snapshot, stderr); + if(error.snapshot == NULL) + fprintf(stderr, "No snapshot available.\n"); + else + Snapshot_Print(error.snapshot, stderr); - RuntimeError_Free(&error); - } + RuntimeError_Free(&error); + } Runtime_Free(runt); Executable_Free(exe); @@ -201,12 +201,12 @@ static _Bool interpret_file(const char *file) Source *src = Source_FromFile(file, &error); if(src == NULL) - { - assert(error.occurred == 1); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } + { + assert(error.occurred == 1); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } _Bool r = interpret(src); @@ -222,12 +222,12 @@ static _Bool interpret_code(const char *code) Source *src = Source_FromString(NULL, code, -1, &error); if(src == NULL) - { - assert(error.occurred); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } + { + assert(error.occurred); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } _Bool r = interpret(src); @@ -243,12 +243,12 @@ static _Bool disassemble_file(const char *file) Source *src = Source_FromFile(file, &error); if(src == NULL) - { - assert(error.occurred == 1); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } + { + assert(error.occurred == 1); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } _Bool r = disassemble(src); @@ -264,12 +264,12 @@ static _Bool disassemble_code(const char *code) Source *src = Source_FromString(NULL, code, -1, &error); if(src == NULL) - { - assert(error.occurred); - print_error(NULL, &error); - Error_Free(&error); - return 0; - } + { + assert(error.occurred); + print_error(NULL, &error); + Error_Free(&error); + return 0; + } _Bool r = disassemble(src); @@ -282,82 +282,81 @@ int main(int argc, char **argv) assert(argc > 0); 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 - fprintf(stderr, "Error: Incorrect usage.\n\n"); - fprintf(stderr, usage); + Error_Report(&error, 0, "Missing source file"); + print_error(NULL, &error); + Error_Free(&error); return -1; } - if(!strcmp(argv[1], "run")) + _Bool r; + + if(!strcmp(argv[2], "inline")) { - Error error; - Error_Init(&error); - - if(argc == 2) - { - 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 = interpret_code(argv[3]); - } - else - r = interpret_file(argv[2]); - return r ? 0 : -1; + 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; + } if(!strcmp(argv[1], "dis")) - { - Error error; - Error_Init(&error); + { + Error error; + Error_Init(&error); - if(argc == 2) - { - 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; + if(argc == 2) + { + 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; + } + if(!strcmp(argv[1], "help")) - { - fprintf(stdout, usage); - return 0; - } + { + fprintf(stdout, usage); + return 0; + } fprintf(stderr, "Error: Incorrect usage.\n\n"); fprintf(stderr, usage); diff --git a/src/objects/heap.c b/src/objects/heap.c index fc127f5..28f102e 100644 --- a/src/objects/heap.c +++ b/src/objects/heap.c @@ -137,10 +137,10 @@ Heap *Heap_New(int size) heap->collecting = 0; if(heap->body == NULL) - { - free(heap); - return NULL; - } + { + free(heap); + return NULL; + } #if USING_VALGRIND VALGRIND_CREATE_MEMPOOL(heap, 0, 0); @@ -160,23 +160,23 @@ void Heap_Free(Heap *heap) Error_Init(&error); 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); - if(error.occurred) - { - // Errors occurred! We can't do anything about - // it now though. - Error_Free(&error); - Error_Init(&error); - } + // Errors occurred! We can't do anything about + // it now though. + Error_Free(&error); + Error_Init(&error); } + } while(heap->oflow) - { - OflowAlloc *prev = heap->oflow->prev; - free(heap->oflow); - heap->oflow = prev; - } + { + OflowAlloc *prev = heap->oflow->prev; + free(heap->oflow); + heap->oflow = prev; + } free(heap->pend); free(heap->body); @@ -208,42 +208,42 @@ void *Heap_Malloc(Heap *heap, TypeObject *type, Error *err) _Bool requires_destruct = type->free != NULL; if(requires_destruct) + { + // This type of object requires + // a destructor to be called. + if(heap->pend == NULL) { - // This type of object requires - // a destructor to be called. - if(heap->pend == NULL) - { - int n = 8; + int n = 8; - heap->pend = malloc(n * sizeof(PendingDestruct)); + heap->pend = malloc(n * sizeof(PendingDestruct)); - if(heap->pend == NULL) - { - Error_Report(err, 1, "No memory"); - return NULL; - } + 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); + 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); + } int size = type->size; @@ -290,23 +290,23 @@ void *Heap_RawMalloc(Heap *heap, int size, Error *err) padding = heap->used - padding; if(heap->used + size > heap->size) - { - OflowAlloc *oflow = malloc(sizeof(OflowAlloc) + size); + { + OflowAlloc *oflow = malloc(sizeof(OflowAlloc) + size); - if(oflow == 0) - return 0; + if(oflow == 0) + return 0; - oflow->prev = heap->oflow; - heap->oflow = oflow; + oflow->prev = heap->oflow; + heap->oflow = oflow; - addr = oflow->body; - } + addr = oflow->body; + } else - { - assert(heap->used + size <= heap->size); - addr = heap->body + heap->used; - heap->used += size; - } + { + assert(heap->used + size <= heap->size); + addr = heap->body + heap->used; + heap->used += size; + } heap->total += size + padding; @@ -326,10 +326,10 @@ _Bool Heap_StartCollection(Heap *heap, Error *error) void *new_body = malloc(heap->size); if(new_body == NULL) - { - Error_Report(error, 1, "No memory"); - return 0; - } + { + Error_Report(error, 1, "No memory"); + return 0; + } heap->old_body = heap->body; heap->old_used = heap->used; @@ -351,57 +351,57 @@ _Bool Heap_StopCollection(Heap *heap) assert(heap->collecting == 1); if(heap->collection_failed) - { - free(heap->old_body); - return 0; - } + { + free(heap->old_body); + return 0; + } /* Call destructors here */ { int i = 0; while(i < heap->pend_used) + { + Object *obj = heap->pend[i].object; + + if(obj->flags & Object_MOVED) { - Object *obj = heap->pend[i].object; - - 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; - } + 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; + } + } if(heap->pend_size / 2 > heap->pend_used) - { - // Downsize - void *temp = realloc(heap->pend, heap->pend_size / 2 * sizeof(PendingDestruct)); + { + // Downsize + void *temp = realloc(heap->pend, heap->pend_size / 2 * sizeof(PendingDestruct)); - if(temp != NULL) - { - heap->pend = temp; - heap->pend_size /= 2; - } + if(temp != NULL) + { + heap->pend = temp; + heap->pend_size /= 2; } + } } while(heap->old_oflow) - { - OflowAlloc *prev = heap->old_oflow->prev; - free(heap->old_oflow); - heap->old_oflow = prev; - } + { + OflowAlloc *prev = heap->old_oflow->prev; + free(heap->old_oflow); + heap->old_oflow = prev; + } 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); if(new_location == NULL) - { - heap->collection_failed = 1; - return; - } + { + heap->collection_failed = 1; + return; + } memcpy(new_location, old_location, size); @@ -453,62 +453,64 @@ void Heap_CollectReference(Object **referer, void *userp) *referer = ((MovedObject*) old_location)->new_location; else - { - Object *new_location; + { + Object *new_location; - // This object wasn't moved to - // the new heap yet. + // This object wasn't moved to + // the new heap yet. - if(old_location->flags & Object_STATIC) + if(old_location->flags & Object_STATIC) - // The object doesn't need to be moved - // since it was statically allocated. - new_location = old_location; - else + // The object doesn't need to be moved + // since it was statically allocated. + new_location = old_location; + else + { + // Get some information. + TypeObject *type = old_location->type; + int size = type->size; + + // Copy the object to a new location. + { + new_location = Heap_RawMalloc(heap, size, heap->error); + + if(new_location == NULL) { - // Get some information. - TypeObject *type = old_location->type; - 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; + heap->collection_failed = 1; + return; } - // Collect the reference to the type. - if((Object*) new_location->type != new_location) - Heap_CollectReference((Object**) &new_location->type, heap); + memcpy(new_location, old_location, size); + } - // Collect all of the references to - // extensions allocate using the GC'd - // heap. - Object_WalkExtensions(new_location, Heap_CollectExtension, heap); + // Set the old location as moved and + // leave the reference to the new + // location. + { + old_location->flags |= Object_MOVED; - // Now collect all of the children. - Object_WalkReferences(new_location, Heap_CollectReference, heap); - - // Update the referer - *referer = new_location; + assert((int) sizeof(MovedObject) <= size); + ((MovedObject*) old_location)->new_location = new_location; + } + + heap->movedcount += 1; } + + // 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; + } } \ No newline at end of file diff --git a/src/objects/o_buffer.c b/src/objects/o_buffer.c index c74d9bd..25c30a3 100644 --- a/src/objects/o_buffer.c +++ b/src/objects/o_buffer.c @@ -102,22 +102,22 @@ Object *Object_NewBuffer(int size, Heap *heap, Error *error) unsigned char *body; if(size > THRESHOLD) - { - body = malloc(sizeof(unsigned char) * size); + { + body = malloc(sizeof(unsigned char) * size); - if(body == NULL) - { - Error_Report(error, 1, "No memory"); - return NULL; - } - } - else + if(body == NULL) { - body = Heap_RawMalloc(heap, sizeof(unsigned char) * size, error); - - if(body == NULL) - return NULL; + Error_Report(error, 1, "No memory"); + return NULL; } + } + else + { + body = Heap_RawMalloc(heap, sizeof(unsigned char) * size, error); + + if(body == NULL) + return NULL; + } obj->size = size; 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) { if(buffer->type != &t_buffer && buffer->type != &t_buffer_slice) - { - Error_Report(error, 0, "Not a buffer or a buffer slice"); - return NULL; - } + { + Error_Report(error, 0, "Not a buffer or a buffer slice"); + return NULL; + } BufferSliceObject *slice; 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; - - 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; + 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; + } 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); - - 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; + 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; + } + return (Object*) slice; } void *Object_GetBufferAddrAndSize(Object *obj, int *size, Error *error) { if(obj->type != &t_buffer && obj->type != &t_buffer_slice) - { - Error_Report(error, 0, "Not a buffer or a buffer slice"); - return NULL; - } + { + Error_Report(error, 0, "Not a buffer or a buffer slice"); + return NULL; + } if(obj->type == &t_buffer) - { - BufferObject *buffer = (BufferObject*) obj; + { + BufferObject *buffer = (BufferObject*) obj; - if(size) - *size = buffer->size; + if(size) + *size = buffer->size; - return buffer->body; - } + return buffer->body; + } else - { - assert(obj->type == &t_buffer_slice); + { + assert(obj->type == &t_buffer_slice); - BufferSliceObject *slice = (BufferSliceObject*) obj; + BufferSliceObject *slice = (BufferSliceObject*) obj; - if(size) - *size = slice->length; + if(size) + *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) @@ -258,10 +258,10 @@ static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error assert(error != NULL); if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); @@ -269,10 +269,10 @@ static Object *buffer_select(Object *self, Object *key, Heap *heap, Error *error BufferObject *buffer = (BufferObject*) self; if(idx < 0 || idx >= buffer->size) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } 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); if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); @@ -299,10 +299,10 @@ static Object *slice_select(Object *self, Object *key, Heap *heap, Error *error) BufferSliceObject *slice = (BufferSliceObject*) self; if(idx < 0 || idx >= slice->length) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } 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; if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); if(idx < 0 || idx >= buffer->size) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } long long int qword = Object_ToInt(val, error); if(qword > 255 || qword < 0) - { - Error_Report(error, 0, "Not in range [0, 255]"); - return NULL; - } + { + Error_Report(error, 0, "Not in range [0, 255]"); + return NULL; + } 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; if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); if(idx < 0 || idx >= slice->length) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } long long int qword = Object_ToInt(val, error); if(qword > 255 || qword < 0) - { - Error_Report(error, 0, "Not in range [0, 255]"); - return NULL; - } + { + Error_Report(error, 0, "Not in range [0, 255]"); + return NULL; + } unsigned char byte = qword & 0xff; @@ -414,26 +414,26 @@ static void print_bytes(FILE *fp, unsigned char *addr, int size) fprintf(fp, "["); for(int i = 0; i < size; i += 1) - { - unsigned char byte, low, high; + { + unsigned char byte, low, high; - byte = addr[i]; - low = byte & 0xf; - high = byte >> 4; + byte = addr[i]; + low = byte & 0xf; + high = byte >> 4; - assert(low < 16); - assert(high < 16); + assert(low < 16); + assert(high < 16); - char c1, c2; + char c1, c2; - c1 = low < 10 ? low + '0' : low - 10 + 'A'; - c2 = high < 10 ? high + '0' : high - 10 + 'A'; + c1 = low < 10 ? low + '0' : low - 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) - fprintf(fp, ", "); - } + if(i+1 < size) + fprintf(fp, ", "); + } fprintf(fp, "]"); } diff --git a/src/objects/o_closure.c b/src/objects/o_closure.c index cc50529..06c43ec 100644 --- a/src/objects/o_closure.c +++ b/src/objects/o_closure.c @@ -58,10 +58,10 @@ Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *er return NULL; if(parent != NULL && parent->type != &t_closure) - { - Error_Report(error, 0, "Object is not a closure"); - return NULL; - } + { + Error_Report(error, 0, "Object is not a closure"); + return NULL; + } obj->prev = (ClosureObject*) parent; obj->vars = new_map; @@ -76,14 +76,14 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *err) Object *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) - return NULL; + if(err->occurred) + return NULL; - closure = closure->prev; - } + closure = closure->prev; + } return selected; } diff --git a/src/objects/o_dir.c b/src/objects/o_dir.c index a453864..85f66ee 100644 --- a/src/objects/o_dir.c +++ b/src/objects/o_dir.c @@ -64,10 +64,10 @@ Object *Object_FromDIR(DIR *handle, Heap *heap, Error *error) DIR *Object_ToDIR(Object *obj, Error *error) { if(!Object_IsDir(obj)) - { - Error_Report(error, 0, "Object is not a directory"); - return NULL; - } + { + Error_Report(error, 0, "Object is not a directory"); + return NULL; + } return ((DirObject*) obj)->dir; } diff --git a/src/objects/o_file.c b/src/objects/o_file.c index 114f1dc..b776d93 100644 --- a/src/objects/o_file.c +++ b/src/objects/o_file.c @@ -52,10 +52,10 @@ _Bool Object_IsFile(Object *obj) FILE *Object_ToStream(Object *obj, Error *error) { if(!Object_IsFile(obj)) - { - Error_Report(error, 0, "Object is not a file"); - return NULL; - } + { + Error_Report(error, 0, "Object is not a file"); + return NULL; + } return ((FileObject*) obj)->fp; } diff --git a/src/objects/o_list.c b/src/objects/o_list.c index 9a91973..21eebdc 100644 --- a/src/objects/o_list.c +++ b/src/objects/o_list.c @@ -89,10 +89,10 @@ static Object *copy(Object *self, Heap *heap, Error *err) if(ls2 == NULL) return NULL; for(int i = 0; i < ls->count; i += 1) - { - ls2->vals[i] = Object_Copy(ls->vals[i], heap, err); - if(err->occurred) return NULL; - } + { + ls2->vals[i] = Object_Copy(ls->vals[i], heap, err); + if(err->occurred) return NULL; + } ls2->count = ls->count; @@ -168,10 +168,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) assert(error != NULL); if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); @@ -179,10 +179,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) ListObject *list = (ListObject*) self; if(idx < 0 || idx >= list->count) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } 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; if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); if(idx < 0 || idx > list->count) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } if(idx == list->count) - { - if(list->count == list->capacity) - if(!grow(list, heap, error)) - return 0; + { + if(list->count == list->capacity) + if(!grow(list, heap, error)) + return 0; - list->vals[list->count] = val; - list->count += 1; - } + list->vals[list->count] = val; + list->count += 1; + } else - { - list->vals[idx] = val; - } + { + list->vals[idx] = val; + } return 1; } @@ -267,11 +267,11 @@ static void print(Object *self, FILE *fp) fprintf(fp, "["); 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) - fprintf(fp, ", "); - } + if(i+1 < list->count) + fprintf(fp, ", "); + } fprintf(fp, "]"); } \ No newline at end of file diff --git a/src/objects/o_map.c b/src/objects/o_map.c index 0365ec3..003b31d 100644 --- a/src/objects/o_map.c +++ b/src/objects/o_map.c @@ -75,22 +75,22 @@ static Object *copy(Object *self, Heap *heap, Error *err) if(m2 == NULL) return NULL; for(int i = 0; i < m1->count; i += 1) - { - Object *key, *key_cpy; - Object *val, *val_cpy; + { + Object *key, *key_cpy; + Object *val, *val_cpy; - key = m1->keys[i]; - val = m1->vals[i]; + key = m1->keys[i]; + val = m1->vals[i]; - key_cpy = Object_Copy(key, heap, err); - if(key_cpy == NULL) return NULL; + key_cpy = Object_Copy(key, heap, err); + if(key_cpy == NULL) return NULL; - val_cpy = Object_Copy(val, heap, err); - if(val_cpy == NULL) return NULL; + val_cpy = Object_Copy(val, heap, err); + if(val_cpy == NULL) return NULL; - if(!Object_Insert(m2, key_cpy, val_cpy, heap, err)) - return NULL; - } + if(!Object_Insert(m2, key_cpy, val_cpy, heap, err)) + return NULL; + } return (Object*) m2; } @@ -103,8 +103,8 @@ static int hash(Object *self) // The hash of the map is the sum of the // hashes of each key and each item. for(int i = 0; i < m->count; i += 1) - h += Object_Hash(m->keys[i]) - + Object_Hash(m->vals[i]); + h += Object_Hash(m->keys[i]) + + Object_Hash(m->vals[i]); return h; } @@ -151,10 +151,10 @@ static void walk(Object *self, void (*callback)(Object **referer, void *userp), MapObject *map = (MapObject*) self; for(int i = 0; i < map->count; i += 1) - { - callback(&map->keys[i], userp); - callback(&map->vals[i], userp); - } + { + callback(&map->keys[i], userp); + callback(&map->vals[i], 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; while(1) + { + int k = map->mapper[i]; + + if(k == -1) { - int k = map->mapper[i]; - - if(k == -1) - { - // 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; + // 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; + } UNREACHABLE; return NULL; @@ -237,42 +237,42 @@ static _Bool grow(MapObject *map, Heap *heap, Error *error) return 0; for(int i = 0; i < map->count; i += 1) - { - keys[i] = map->keys[i]; - vals[i] = map->vals[i]; - } + { + keys[i] = map->keys[i]; + vals[i] = map->vals[i]; + } for(int i = 0; i < new_mapper_size; i += 1) mapper[i] = -1; // Rehash everything. 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]); + { + // 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 mask = new_mapper_size - 1; + int pert = hash; - int j = hash & mask; + int j = hash & mask; - while(1) - { - if(mapper[j] == -1) - { - // No collision. - // Insert here. - mapper[j] = i; - break; - } + 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; - } + // Collided. Find a new place. + pert >>= 5; + j = (j * 5 + pert + 1) & mask; } + } // Done. map->mapper = mapper; @@ -304,45 +304,45 @@ static _Bool insert(Object *self, Object *key, Object *val, Heap *heap, Error *e int i = hash & mask; 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) - { - // Empty slot. We can insert it here. - Object *key_copy = Object_Copy(key, heap, error); + if(key_copy == NULL) + return NULL; - if(key_copy == NULL) - return NULL; - - map->mapper[i] = map->count; - map->keys[map->count] = key_copy; - 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; + map->mapper[i] = map->count; + map->keys[map->count] = key_copy; + 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; + } UNREACHABLE; return 0; @@ -361,13 +361,13 @@ static void print(Object *self, FILE *fp) fprintf(fp, "{"); for(int i = 0; i < map->count; i += 1) - { - Object_Print(map->keys[i], fp); - fprintf(fp, ": "); - Object_Print(map->vals[i], fp); + { + Object_Print(map->keys[i], fp); + fprintf(fp, ": "); + Object_Print(map->vals[i], fp); - if(i+1 < map->count) - fprintf(fp, ", "); - } + if(i+1 < map->count) + fprintf(fp, ", "); + } fprintf(fp, "}"); } \ No newline at end of file diff --git a/src/objects/o_string.c b/src/objects/o_string.c index fb843a8..175c083 100644 --- a/src/objects/o_string.c +++ b/src/objects/o_string.c @@ -68,6 +68,9 @@ static TypeObject t_string = { 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 // the utf-8 character number [idx]. @@ -75,13 +78,13 @@ static int char_index_to_offset(StringObject *str, int idx) last_code_len = 0; while(idx > 0) - { - last_code_len = utf8_sequence_to_utf32_codepoint(str->body + scanned_bytes, str->bytes - scanned_bytes, NULL); - scanned_bytes += last_code_len; - idx -= 1; + { + last_code_len = utf8_sequence_to_utf32_codepoint(str->body + scanned_bytes, str->bytes - scanned_bytes, NULL); + scanned_bytes += last_code_len; + idx -= 1; - assert(scanned_bytes <= str->bytes); - } + assert(scanned_bytes <= str->bytes); + } assert(idx == 0); 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); if(!Object_IsInt(key)) - { - Error_Report(error, 0, "Non integer key"); - return NULL; - } + { + Error_Report(error, 0, "Non integer key"); + return NULL; + } int idx = Object_ToInt(key, error); assert(error->occurred == 0); @@ -104,10 +107,10 @@ static Object *select(Object *self, Object *key, Heap *heap, Error *error) StringObject *str = (StringObject*) self; if(idx < 0 || idx >= str->count) - { - Error_Report(error, 0, "Out of range index"); - return NULL; - } + { + Error_Report(error, 0, "Out of range index"); + return NULL; + } int byteoffset = char_index_to_offset(str, idx); 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); if(count < 0) - { - Error_Report(error, 0, "Invalid UTF-8 sequence"); - return NULL; - } + { + Error_Report(error, 0, "Invalid UTF-8 sequence"); + return NULL; + } StringObject *strobj = Heap_Malloc(heap, &t_string, error); diff --git a/src/objects/objects.c b/src/objects/objects.c index 42adbf1..5fbf1e4 100644 --- a/src/objects/objects.c +++ b/src/objects/objects.c @@ -86,10 +86,10 @@ unsigned int Object_GetDeepSize(const Object *obj, Error *err) assert(type); if(type->deepsize == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return 0; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return 0; + } return type->deepsize(obj); } @@ -112,10 +112,10 @@ Object *Object_Copy(Object *obj, Heap *heap, Error *err) assert(type != NULL); if(type->copy == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return NULL; + } 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); if(type->call == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return NULL; + } 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); if(type->select == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); + return NULL; + } return type->select(coll, key, heap, err); } @@ -178,10 +178,10 @@ Object *Object_Delete(Object *coll, Object *key, Heap *heap, Error *err) assert(type); if(type->delete == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); + return NULL; + } 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); if(type->insert == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); - return 0; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); + return 0; + } return type->insert(coll, key, val, heap, err); } @@ -213,10 +213,10 @@ int Object_Count(Object *coll, Error *err) assert(type); if(type->count == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); - return -1; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(coll), __func__); + return -1; + } return type->count(coll); } @@ -230,10 +230,10 @@ Object *Object_Next(Object *iter, Heap *heap, Error *err) assert(type); if(type->next == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__); + return NULL; + } return type->next(iter, heap, err); } @@ -247,10 +247,10 @@ Object *Object_Prev(Object *iter, Heap *heap, Error *err) assert(type); if(type->prev == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(iter), __func__); + return NULL; + } return type->prev(iter, heap, err); } @@ -289,19 +289,19 @@ long long int Object_ToInt(Object *obj, Error *err) assert(obj); if(!Object_IsInt(obj)) - { - Error_Report(err, 0, "Object is not an integer"); - return 0; - } + { + Error_Report(err, 0, "Object is not an integer"); + return 0; + } const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_int == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return 0; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return 0; + } return type->to_int(obj, err); } @@ -312,19 +312,19 @@ _Bool Object_ToBool(Object *obj, Error *err) assert(obj); if(!Object_IsBool(obj)) - { - Error_Report(err, 0, "Object is not a boolean"); - return 0; - } + { + Error_Report(err, 0, "Object is not a boolean"); + return 0; + } const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_bool == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return 0; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return 0; + } return type->to_bool(obj, err); } @@ -335,19 +335,19 @@ double Object_ToFloat(Object *obj, Error *err) assert(obj); if(!Object_IsFloat(obj)) - { - Error_Report(err, 0, "Object is not a floating"); - return 0; - } + { + Error_Report(err, 0, "Object is not a floating"); + return 0; + } const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_float == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return 0; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return 0; + } 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); if(!Object_IsString(obj)) - { - Error_Report(err, 0, "Object is not a string"); - return NULL; - } + { + Error_Report(err, 0, "Object is not a string"); + return NULL; + } const TypeObject *type = Object_GetType(obj); assert(type); if(type->to_string == NULL) - { - Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); - return NULL; - } + { + Error_Report(err, 0, "Object %s doesn't implement %s", Object_GetName(obj), __func__); + return NULL; + } return type->to_string(obj, size, heap, err); } @@ -385,10 +385,10 @@ _Bool Object_Compare(Object *obj1, Object *obj2, Error *error) return 0; if(obj1->type->op_eql == NULL) - { - Error_Report(error, 0, "Object %s doesn't implement %s", Object_GetName(obj1), __func__); - return 0; - } + { + Error_Report(error, 0, "Object %s doesn't implement %s", Object_GetName(obj1), __func__); + return 0; + } return obj1->type->op_eql(obj1, obj2); } diff --git a/src/runtime/o_func.c b/src/runtime/o_func.c index b1cd7b6..486b094 100644 --- a/src/runtime/o_func.c +++ b/src/runtime/o_func.c @@ -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) { - assert(self != NULL); - assert(heap != NULL); - assert(error != NULL); + assert(self != NULL && heap != NULL && error != NULL); 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; if(expected_argc < (int) argc) - { - // Nothing to be done. By using - // the right argc the additional - // arguments are ignored implicitly. - argv2 = argv; - } + { + // Nothing to be done. By using + // the right argc the additional + // arguments are ignored implicitly. + argv2 = argv; + } else if(expected_argc > (int) argc) + { + // Some arguments are missing. + argv2 = malloc(sizeof(Object*) * expected_argc); + + if(argv2 == NULL) { - // Some arguments are missing. - argv2 = malloc(sizeof(Object*) * 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) - return 0; - } + 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; + } + } else // The right amount of arguments was provided. argv2 = argv; @@ -176,10 +174,10 @@ Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, in Executable *exe_copy = Executable_Copy(exe); if(exe_copy == NULL) - { - Error_Report(error, 1, "Failed to copy executable"); - return NULL; - } + { + Error_Report(error, 1, "Failed to copy executable"); + return NULL; + } func->runtime = runtime; func->exe = exe_copy; diff --git a/src/runtime/o_nfunc.c b/src/runtime/o_nfunc.c index ab598dc..623704c 100644 --- a/src/runtime/o_nfunc.c +++ b/src/runtime/o_nfunc.c @@ -64,48 +64,48 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, int expected_argc = func->argc; if(expected_argc < 0 || expected_argc == (int) argc) - { - // The function is variadic or the right - // amount of arguments was provided. - argv2 = argv; - argc2 = argc; - } + { + // The function is variadic or the right + // amount of arguments was provided. + argv2 = argv; + argc2 = argc; + } else if(expected_argc < (int) argc) - { - // Nothing to be done. By using - // the right argc the additional - // arguments are ignored implicitly. - argv2 = argv; - argc2 = expected_argc; - } + { + // Nothing to be done. By using + // the right argc the additional + // arguments are ignored implicitly. + argv2 = argv; + argc2 = expected_argc; + } else if(expected_argc > (int) argc) - { - // Some arguments are missing. - argv2 = malloc(sizeof(Object*) * expected_argc); - argc2 = expected_argc; + { + // Some arguments are missing. + argv2 = malloc(sizeof(Object*) * expected_argc); + 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; - } - } + 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; + } + } + } else UNREACHABLE; assert(func->callback != NULL); diff --git a/src/runtime/o_staticmap.c b/src/runtime/o_staticmap.c index 5c5a79a..749a76f 100644 --- a/src/runtime/o_staticmap.c +++ b/src/runtime/o_staticmap.c @@ -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) if(!strcmp(name, map->slots[i].name)) + { + StaticMapSlot slot = map->slots[i]; + Object *obj; + switch(slot.kind) { - StaticMapSlot slot = map->slots[i]; - Object *obj; - switch(slot.kind) - { - case SM_BOOL: return Object_FromBool(slot.as_bool, heap, error); - case SM_INT: return Object_FromInt(slot.as_int, heap, error); - 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_STRING: return Object_FromString(slot.as_string, slot.length, heap, error); - 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; + case SM_BOOL: return Object_FromBool(slot.as_bool, heap, error); + case SM_INT: return Object_FromInt(slot.as_int, heap, error); + 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_STRING: return Object_FromString(slot.as_string, slot.length, heap, error); + 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 NULL; } \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 4159e11..4683ee7 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -90,24 +90,24 @@ Runtime *Runtime_New2(int stack_size, Heap *heap, _Bool free_heap, void *callbac Runtime *runtime = malloc(sizeof(Runtime)); if(runtime != NULL) + { + runtime->heap = heap; + runtime->stack = Stack_New(stack_size); + + if(runtime->stack == NULL) { - runtime->heap = heap; - runtime->stack = Stack_New(stack_size); - - if(runtime->stack == NULL) - { - Heap_Free(runtime->heap); - free(runtime); - } - - runtime->free_heap = free_heap; - runtime->callback_userp = callback_userp; - runtime->callback_addr = callback_addr; - runtime->builtins = NULL; - runtime->frame = NULL; - runtime->depth = 0; + Heap_Free(runtime->heap); + free(runtime); } + runtime->free_heap = free_heap; + runtime->callback_userp = callback_userp; + runtime->callback_addr = callback_addr; + runtime->builtins = NULL; + runtime->frame = NULL; + runtime->depth = 0; + } + return runtime; } @@ -148,24 +148,24 @@ _Bool Runtime_Push(Runtime *runtime, Error *error, Object *obj) assert(obj != NULL); if(runtime->depth == 0) - { - Error_Report(error, 0, "There are no frames on the stack"); - return 0; - } + { + Error_Report(error, 0, "There are no frames on the stack"); + return 0; + } assert(runtime->frame->used <= MAX_FRAME_STACK); if(runtime->frame->used == MAX_FRAME_STACK) - { - Error_Report(error, 0, "Frame stack limit of %d reached", MAX_FRAME_STACK); - return 0; - } + { + Error_Report(error, 0, "Frame stack limit of %d reached", MAX_FRAME_STACK); + return 0; + } if(!Stack_Push(runtime->stack, obj)) - { - Error_Report(error, 0, "Out of stack"); - return 0; - } + { + Error_Report(error, 0, "Out of stack"); + return 0; + } runtime->frame->used += 1; return 1; @@ -177,18 +177,18 @@ _Bool Runtime_Pop(Runtime *runtime, Error *error, unsigned int n) assert(error != NULL); if(runtime->depth == 0) - { - Error_Report(error, 0, "There are no frames on the stack"); - return 0; - } + { + Error_Report(error, 0, "There are no frames on the stack"); + return 0; + } assert(runtime->frame->used >= 0); if((unsigned int) runtime->frame->used < n) - { - Error_Report(error, 0, "Frame has not enough values on the stack"); - return 0; - } + { + Error_Report(error, 0, "Frame has not enough values on the stack"); + return 0; + } // The frame has something on the stack, // this means that the stack isn't empty @@ -227,20 +227,20 @@ Snapshot *Snapshot_New(Runtime *runtime) snapshot->depth = 0; while(snapshot->depth < runtime->depth) - { - assert(f != NULL); + { + assert(f != NULL); - SnapshotNode *node = snapshot->nodes + snapshot->depth; + SnapshotNode *node = snapshot->nodes + snapshot->depth; - node->exe = Executable_Copy(f->exe); - node->index = f->index; + node->exe = Executable_Copy(f->exe); + node->index = f->index; - if(node->exe == NULL) - goto abort; + if(node->exe == NULL) + goto abort; - f = f->prev; - snapshot->depth += 1; - } + f = f->prev; + snapshot->depth += 1; + } assert(f == NULL); } @@ -255,11 +255,10 @@ abort: void Snapshot_Free(Snapshot *snapshot) { for(int i = 0; i < snapshot->depth; i += 1) - { - Executable *exe = snapshot->nodes[i].exe; - - Executable_Free(exe); - } + { + Executable *exe = snapshot->nodes[i].exe; + Executable_Free(exe); + } free(snapshot); } @@ -271,52 +270,52 @@ void Snapshot_Print(Snapshot *snapshot, FILE *fp) fprintf(fp, "Stack trace:\n"); for(int i = 0; i < snapshot->depth; i += 1) + { + SnapshotNode node = snapshot->nodes[i]; + + Executable *exe = node.exe; + Source *src = Executable_GetSource(exe); + + const char *name; { - SnapshotNode node = snapshot->nodes[i]; + name = NULL; - Executable *exe = node.exe; - Source *src = Executable_GetSource(exe); + if(src != NULL) + name = Source_GetName(src); - const char *name; - { - name = NULL; - - if(src != NULL) - name = Source_GetName(src); - - if(name == NULL) - name = "(unnamed)"; - } - - int line; - { - if(src == NULL) - line = 0; - else - { - line = 1; - - const char *body = Source_GetBody(src); - int offset = Executable_GetInstrOffset(exe, node.index); - - int i = 0; - - while(i < offset) - { - if(body[i] == '\n') - line += 1; - - i += 1; - } - } - } - - if(line == 0) - fprintf(fp, "\t#%d %s\n", i, name); - else - fprintf(fp, "\t#%d %s:%d\n", i, name, line); + if(name == NULL) + name = "(unnamed)"; } + int line; + { + if(src == NULL) + line = 0; + else + { + line = 1; + + const char *body = Source_GetBody(src); + int offset = Executable_GetInstrOffset(exe, node.index); + + int i = 0; + + while(i < offset) + { + if(body[i] == '\n') + line += 1; + + i += 1; + } + } + } + + if(line == 0) + fprintf(fp, "\t#%d %s\n", i, name); + else + fprintf(fp, "\t#%d %s:%d\n", i, name, line); + } + //fprintf(fp, " (Snapshot can't be printed yet)\n"); } @@ -327,103 +326,103 @@ static Object *do_math_op(Object *lop, Object *rop, Opcode opcode, Heap *heap, E #define APPLY(x, y, z, id) \ switch(opcode) \ - { \ - case OPCODE_ADD: (z) = (x) + (y); break; \ - case OPCODE_SUB: (z) = (x) - (y); break; \ - case OPCODE_MUL: (z) = (x) * (y); break; \ - case OPCODE_DIV: (z) = (x) / (y); break; \ - default: assert(0); break; \ - } + { \ + case OPCODE_ADD: (z) = (x) + (y); break; \ + case OPCODE_SUB: (z) = (x) - (y); break; \ + case OPCODE_MUL: (z) = (x) * (y); break; \ + case OPCODE_DIV: (z) = (x) / (y); break; \ + default: assert(0); break; \ + } Object *res; if(Object_IsInt(lop)) + { + long long int raw_lop = Object_ToInt(lop, error); + + if(error->occurred) + return NULL; + + if(Object_IsInt(rop)) { - long long int raw_lop = Object_ToInt(lop, error); + // int + int + long long int raw_rop = Object_ToInt(rop, error); if(error->occurred) return NULL; - if(Object_IsInt(rop)) - { - // int + int - long long int raw_rop = Object_ToInt(rop, error); + long long int raw_res; - if(error->occurred) - return NULL; + APPLY(raw_lop, raw_rop, raw_res, id) - long long int raw_res; - - APPLY(raw_lop, raw_rop, raw_res, id) - - res = Object_FromInt(raw_res, heap, error); - } - else if(Object_IsFloat(rop)) - { - // int + float - double raw_rop = Object_ToFloat(rop, error); - - if(error->occurred) - return NULL; - - double raw_res; - - APPLY((double) raw_lop, raw_rop, raw_res, id) - - res = Object_FromFloat(raw_res, heap, error); - } - else - { - Error_Report(error, 0, "Arithmetic operation on a non-numeric object"); - return NULL; - } + res = Object_FromInt(raw_res, heap, error); } - else if(Object_IsFloat(lop)) + else if(Object_IsFloat(rop)) { - double raw_lop = Object_ToFloat(lop, error); + // int + float + double raw_rop = Object_ToFloat(rop, error); if(error->occurred) return NULL; - if(Object_IsInt(rop)) - { - // float + int - long long int raw_rop = Object_ToInt(rop, error); + double raw_res; - if(error->occurred) - return NULL; + APPLY((double) raw_lop, raw_rop, raw_res, id) - double raw_res; - - APPLY(raw_lop, (double) raw_rop, raw_res, id) - - res = Object_FromFloat(raw_res, heap, error); - } - else if(Object_IsFloat(rop)) - { - // float + float - double raw_rop = Object_ToFloat(rop, error); - - if(error->occurred) - return NULL; - - double raw_res; - - APPLY(raw_lop, raw_rop, raw_res, id) - - res = Object_FromFloat(raw_res, heap, error); - } - else - { - Error_Report(error, 0, "Arithmetic operation on a non-numeric object"); - return NULL; - } + res = Object_FromFloat(raw_res, heap, error); } - else + else { Error_Report(error, 0, "Arithmetic operation on a non-numeric object"); return NULL; } + } + else if(Object_IsFloat(lop)) + { + double raw_lop = Object_ToFloat(lop, error); + + if(error->occurred) + return NULL; + + if(Object_IsInt(rop)) + { + // float + int + long long int raw_rop = Object_ToInt(rop, error); + + if(error->occurred) + return NULL; + + double raw_res; + + APPLY(raw_lop, (double) raw_rop, raw_res, id) + + res = Object_FromFloat(raw_res, heap, error); + } + else if(Object_IsFloat(rop)) + { + // float + float + double raw_rop = Object_ToFloat(rop, error); + + if(error->occurred) + return NULL; + + double raw_res; + + APPLY(raw_lop, raw_rop, raw_res, id) + + res = Object_FromFloat(raw_res, heap, error); + } + else + { + Error_Report(error, 0, "Arithmetic operation on a non-numeric object"); + return NULL; + } + } + else + { + Error_Report(error, 0, "Arithmetic operation on a non-numeric object"); + return NULL; + } #undef APPLY @@ -437,87 +436,87 @@ static Object *do_relational_op(Object *lop, Object *rop, Opcode opcode, Heap *h #define APPLY(x, y, z, id) \ switch(opcode) \ - { \ - case OPCODE_LSS: (z) = (x) < (y); break; \ - case OPCODE_GRT: (z) = (x) > (y); break; \ - case OPCODE_LEQ: (z) = (x) <= (y); break; \ - case OPCODE_GEQ: (z) = (x) >= (y); break; \ - default: assert(0); break; \ - } + { \ + case OPCODE_LSS: (z) = (x) < (y); break; \ + case OPCODE_GRT: (z) = (x) > (y); break; \ + case OPCODE_LEQ: (z) = (x) <= (y); break; \ + case OPCODE_GEQ: (z) = (x) >= (y); break; \ + default: assert(0); break; \ + } _Bool res; if(Object_IsInt(lop)) + { + long long int raw_lop = Object_ToInt(lop, error); + + if(error->occurred) + return NULL; + + if(Object_IsInt(rop)) { - long long int raw_lop = Object_ToInt(lop, error); + // int + int + long long int raw_rop = Object_ToInt(rop, error); if(error->occurred) return NULL; - if(Object_IsInt(rop)) - { - // int + int - long long int raw_rop = Object_ToInt(rop, error); - - if(error->occurred) - return NULL; - - APPLY(raw_lop, raw_rop, res, id) - } - else if(Object_IsFloat(rop)) - { - // int + float - double raw_rop = Object_ToFloat(rop, error); - - if(error->occurred) - return NULL; - - APPLY((double) raw_lop, raw_rop, res, id) - } - else - { - Error_Report(error, 0, "Relational operation on a non-numeric object"); - return NULL; - } + APPLY(raw_lop, raw_rop, res, id) } - else if(Object_IsFloat(lop)) + else if(Object_IsFloat(rop)) { - double raw_lop = Object_ToFloat(lop, error); + // int + float + double raw_rop = Object_ToFloat(rop, error); if(error->occurred) return NULL; - if(Object_IsInt(rop)) - { - // float + int - long long int raw_rop = Object_ToInt(rop, error); - - if(error->occurred) - return NULL; - - APPLY(raw_lop, (double) raw_rop, res, id) - } - else if(Object_IsFloat(rop)) - { - // float + float - double raw_rop = Object_ToFloat(rop, error); - - if(error->occurred) - return NULL; - - APPLY(raw_lop, raw_rop, res, id) - } - else - { - Error_Report(error, 0, "Relational operation on a non-numeric object"); - return NULL; - } + APPLY((double) raw_lop, raw_rop, res, id) } - else + else { Error_Report(error, 0, "Relational operation on a non-numeric object"); return NULL; } + } + else if(Object_IsFloat(lop)) + { + double raw_lop = Object_ToFloat(lop, error); + + if(error->occurred) + return NULL; + + if(Object_IsInt(rop)) + { + // float + int + long long int raw_rop = Object_ToInt(rop, error); + + if(error->occurred) + return NULL; + + APPLY(raw_lop, (double) raw_rop, res, id) + } + else if(Object_IsFloat(rop)) + { + // float + float + double raw_rop = Object_ToFloat(rop, error); + + if(error->occurred) + return NULL; + + APPLY(raw_lop, raw_rop, res, id) + } + else + { + Error_Report(error, 0, "Relational operation on a non-numeric object"); + return NULL; + } + } + else + { + Error_Report(error, 0, "Relational operation on a non-numeric object"); + return NULL; + } #undef APPLY @@ -533,677 +532,677 @@ static _Bool step(Runtime *runtime, Error *error) int opc = sizeof(ops) / sizeof(ops[0]); if(!Executable_Fetch(runtime->frame->exe, runtime->frame->index, &opcode, ops, &opc)) - { - Error_Report(error, 1, "Invalid instruction index"); - return 0; - } + { + Error_Report(error, 1, "Invalid instruction index"); + return 0; + } runtime->frame->index += 1; switch(opcode) + { + case OPCODE_NOPE: + // Do nothing. + return 1; + + case OPCODE_POS: { - case OPCODE_NOPE: - // Do nothing. + assert(opc == 0); + + if(runtime->frame->used == 0) + { + Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute POS"); + return 0; + } + + /* Do nothing */ return 1; + } - case OPCODE_POS: + case OPCODE_NEG: + { + assert(opc == 0); + + if(runtime->frame->used == 0) { - assert(opc == 0); - - if(runtime->frame->used == 0) - { - Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute POS"); - return 0; - } - - /* Do nothing */ - return 1; + Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute NEG"); + return 0; } - case OPCODE_NEG: + Object *top = Stack_Top(runtime->stack, 0); + assert(top != NULL); + + if(!Runtime_Pop(runtime, error, 1)) + return 0; + + Heap *heap = Runtime_GetHeap(runtime); + assert(heap != NULL); + + if(Object_IsInt(top)) { - assert(opc == 0); - - if(runtime->frame->used == 0) - { - Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute NEG"); - return 0; - } - - Object *top = Stack_Top(runtime->stack, 0); - assert(top != NULL); - - if(!Runtime_Pop(runtime, error, 1)) - return 0; - - Heap *heap = Runtime_GetHeap(runtime); - assert(heap != NULL); - - if(Object_IsInt(top)) - { - long long n = Object_ToInt(top, error); - - if(error->occurred) - return 0; - - top = Object_FromInt(-n, heap, error); - } - else if(Object_IsFloat(top)) - { - double f = Object_ToFloat(top, error); - - if(error->occurred) - return 0; - - top = Object_FromFloat(-f, heap, error); - } - else - { - Error_Report(error, 0, "Negation operand on a non-numeric object"); - return 0; - } - - if(top == NULL) - return 0; - - if(!Runtime_Push(runtime, error, top)) - return 0; - return 1; - } - - case OPCODE_NOT: - { - assert(opc == 0); - - if(runtime->frame->used == 0) - { - Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute NOT"); - return 0; - } - - Object *top = Stack_Top(runtime->stack, 0); - - if(!Runtime_Pop(runtime, error, 1)) - return 0; - - assert(top != NULL); - - _Bool v = Object_ToBool(top, error); + long long n = Object_ToInt(top, error); if(error->occurred) return 0; - Object *negated = Object_FromBool(!v, runtime->heap, error); - - if(negated == NULL) - return 0; - - if(!Runtime_Push(runtime, error, negated)) - return 0; - return 1; + top = Object_FromInt(-n, heap, error); } - - case OPCODE_ADD: - case OPCODE_SUB: - case OPCODE_MUL: - case OPCODE_DIV: + else if(Object_IsFloat(top)) { - assert(opc == 0); + double f = Object_ToFloat(top, error); - Object *rop = Stack_Top(runtime->stack, 0); - Object *lop = Stack_Top(runtime->stack, -1); - - if(!Runtime_Pop(runtime, error, 2)) + if(error->occurred) return 0; - // We managed to pop rop and lop, - // so we know they're not NULL. - assert(rop != NULL); - assert(lop != NULL); - - Object *res = do_math_op(lop, rop, opcode, runtime->heap, error); - - if(res == NULL) - return 0; - - if(!Runtime_Push(runtime, error, res)) - return 0; - return 1; + top = Object_FromFloat(-f, heap, error); } - - case OPCODE_EQL: - case OPCODE_NQL: + else { - assert(opc == 0); - - Object *rop = Stack_Top(runtime->stack, 0); - Object *lop = Stack_Top(runtime->stack, -1); - - if(!Runtime_Pop(runtime, error, 2)) - return 0; - - // We managed to pop rop and lop, - // so we know they're not NULL. - assert(rop != NULL); - assert(lop != NULL); - - _Bool rawres = Object_Compare(lop, rop, error); - - if(error->occurred == 1) - return 0; - - if(opcode == OPCODE_NQL) - rawres = !rawres; - - Object *res = Object_FromBool(rawres, runtime->heap, error); - - if(res == NULL) - return 0; - - if(!Runtime_Push(runtime, error, res)) - return 0; - return 1; + Error_Report(error, 0, "Negation operand on a non-numeric object"); + return 0; } - case OPCODE_LSS: - case OPCODE_GRT: - case OPCODE_LEQ: - case OPCODE_GEQ: + if(top == NULL) + return 0; + + if(!Runtime_Push(runtime, error, top)) + return 0; + return 1; + } + + case OPCODE_NOT: + { + assert(opc == 0); + + if(runtime->frame->used == 0) { - assert(opc == 0); - - Object *rop = Stack_Top(runtime->stack, 0); - Object *lop = Stack_Top(runtime->stack, -1); - - if(!Runtime_Pop(runtime, error, 2)) - return 0; - - // We managed to pop rop and lop, - // so we know they're not NULL. - assert(rop != NULL); - assert(lop != NULL); - - Object *res = do_relational_op(lop, rop, opcode, runtime->heap, error); - - if(res == NULL) - return 0; - - if(!Runtime_Push(runtime, error, res)) - return 0; - return 1; + Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute NOT"); + return 0; } - case OPCODE_AND: - case OPCODE_OR: + Object *top = Stack_Top(runtime->stack, 0); + + if(!Runtime_Pop(runtime, error, 1)) + return 0; + + assert(top != NULL); + + _Bool v = Object_ToBool(top, error); + + if(error->occurred) + return 0; + + Object *negated = Object_FromBool(!v, runtime->heap, error); + + if(negated == NULL) + return 0; + + if(!Runtime_Push(runtime, error, negated)) + return 0; + return 1; + } + + case OPCODE_ADD: + case OPCODE_SUB: + case OPCODE_MUL: + case OPCODE_DIV: + { + assert(opc == 0); + + Object *rop = Stack_Top(runtime->stack, 0); + Object *lop = Stack_Top(runtime->stack, -1); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + // We managed to pop rop and lop, + // so we know they're not NULL. + assert(rop != NULL); + assert(lop != NULL); + + Object *res = do_math_op(lop, rop, opcode, runtime->heap, error); + + if(res == NULL) + return 0; + + if(!Runtime_Push(runtime, error, res)) + return 0; + return 1; + } + + case OPCODE_EQL: + case OPCODE_NQL: + { + assert(opc == 0); + + Object *rop = Stack_Top(runtime->stack, 0); + Object *lop = Stack_Top(runtime->stack, -1); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + // We managed to pop rop and lop, + // so we know they're not NULL. + assert(rop != NULL); + assert(lop != NULL); + + _Bool rawres = Object_Compare(lop, rop, error); + + if(error->occurred == 1) + return 0; + + if(opcode == OPCODE_NQL) + rawres = !rawres; + + Object *res = Object_FromBool(rawres, runtime->heap, error); + + if(res == NULL) + return 0; + + if(!Runtime_Push(runtime, error, res)) + return 0; + return 1; + } + + case OPCODE_LSS: + case OPCODE_GRT: + case OPCODE_LEQ: + case OPCODE_GEQ: + { + assert(opc == 0); + + Object *rop = Stack_Top(runtime->stack, 0); + Object *lop = Stack_Top(runtime->stack, -1); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + // We managed to pop rop and lop, + // so we know they're not NULL. + assert(rop != NULL); + assert(lop != NULL); + + Object *res = do_relational_op(lop, rop, opcode, runtime->heap, error); + + if(res == NULL) + return 0; + + if(!Runtime_Push(runtime, error, res)) + return 0; + return 1; + } + + case OPCODE_AND: + case OPCODE_OR: + { + assert(opc == 0); + + Object *rop = Stack_Top(runtime->stack, 0); + Object *lop = Stack_Top(runtime->stack, -1); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + // We managed to pop rop and lop, + // so we know they're not NULL. + assert(rop != NULL); + assert(lop != NULL); + + _Bool raw_rop, raw_lop, raw_res; + raw_lop = Object_ToBool(lop, error); + raw_rop = Object_ToBool(rop, error); + if(error->occurred) return 0; + + switch(opcode) { - assert(opc == 0); - - Object *rop = Stack_Top(runtime->stack, 0); - Object *lop = Stack_Top(runtime->stack, -1); - - if(!Runtime_Pop(runtime, error, 2)) - return 0; - - // We managed to pop rop and lop, - // so we know they're not NULL. - assert(rop != NULL); - assert(lop != NULL); - - _Bool raw_rop, raw_lop, raw_res; - raw_lop = Object_ToBool(lop, error); - raw_rop = Object_ToBool(rop, error); - if(error->occurred) return 0; - - switch(opcode) - { - case OPCODE_AND: raw_res = raw_lop && raw_rop; break; - case OPCODE_OR: raw_res = raw_lop || raw_rop; break; - default: assert(0); break; - } - - Object *res = Object_FromBool(raw_res, runtime->heap, error); - - if(res == NULL) - return 0; - - if(!Runtime_Push(runtime, error, res)) - return 0; - return 1; + case OPCODE_AND: raw_res = raw_lop && raw_rop; break; + case OPCODE_OR: raw_res = raw_lop || raw_rop; break; + default: assert(0); break; } - case OPCODE_ASS: + Object *res = Object_FromBool(raw_res, runtime->heap, error); + + if(res == NULL) + return 0; + + if(!Runtime_Push(runtime, error, res)) + return 0; + return 1; + } + + case OPCODE_ASS: + { + assert(opc == 1); + assert(ops[0].type == OPTP_STRING); + + if(runtime->frame->used == 0) { - assert(opc == 1); - assert(ops[0].type == OPTP_STRING); - - if(runtime->frame->used == 0) - { - Error_Report(error, 0, "Frame has not enough values on the stack"); - return 0; - } - - Object *val = Stack_Top(runtime->stack, 0); - assert(val != NULL); - - Object *key = Object_FromString(ops[0].as_string, -1, runtime->heap, error); - - if(key == NULL) - return 0; - - if(!Object_Insert(runtime->frame->locals, key, val, runtime->heap, error)) - return 0; - return 1; + Error_Report(error, 0, "Frame has not enough values on the stack"); + return 0; } - case OPCODE_POP: - { - assert(opc == 1); + Object *val = Stack_Top(runtime->stack, 0); + assert(val != NULL); - if(!Runtime_Pop(runtime, error, ops[0].as_int)) - return 0; - return 1; - } + Object *key = Object_FromString(ops[0].as_string, -1, runtime->heap, error); - case OPCODE_CALL: - { - assert(opc == 1); - assert(ops[0].type == OPTP_INT); + if(key == NULL) + return 0; - int argc = ops[0].as_int; - assert(argc >= 0); + if(!Object_Insert(runtime->frame->locals, key, val, runtime->heap, error)) + return 0; + return 1; + } - if(runtime->frame->used < argc + 1) - { - Error_Report(error, 1, "Frame doesn't own enough objects to execute call"); - return 0; - } + case OPCODE_POP: + { + assert(opc == 1); - Object *callable = Stack_Top(runtime->stack, 0); - assert(callable != NULL); + if(!Runtime_Pop(runtime, error, ops[0].as_int)) + return 0; + return 1; + } - Object *argv[8]; - - int max_argc = sizeof(argv) / sizeof(argv[0]); - if(argc > max_argc) - { - Error_Report(error, 1, "Static buffer only allows function calls with up to %d arguments", max_argc); - return 0; - } - - for(int i = 0; i < argc; i += 1) - { - argv[i] = Stack_Top(runtime->stack, -(i+1)); - assert(argv[i] != NULL); - } - - assert(error->occurred == 0); - (void) Runtime_Pop(runtime, error, argc+1); - assert(error->occurred == 0); - - Object *obj = Object_Call(callable, argv, argc, runtime->heap, error); - // NOTE: Every local object reference is invalidated from here. - - if(obj == NULL) - { - assert(error->occurred != 0); - return 0; - } - - assert(error->occurred == 0); - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_SELECT: - { - assert(opc == 0); - - if(runtime->frame->used < 2) - { - Error_Report(error, 1, "Frame has not enough values on the stack to run SELECT instruction"); - return 0; - } - - Object *col = Stack_Top(runtime->stack, -1); - Object *key = Stack_Top(runtime->stack, 0); - - assert(col != NULL && key != NULL); - - if(!Runtime_Pop(runtime, error, 2)) - return 0; - - assert(error->occurred == 0); - - Error dummy; - Error_Init(&dummy); // We want to catch the error reported by this Object_Select. - - Object *val = Object_Select(col, key, runtime->heap, &dummy); - - if(val == NULL) - { - Error_Free(&dummy); - - val = Object_NewNone(runtime->heap, error); - - if(val == NULL) - return 0; - } - - assert(error->occurred == 0); - - if(!Runtime_Push(runtime, error, val)) - return 0; - - assert(error->occurred == 0); - return 1; - } - - case OPCODE_INSERT: - { - assert(opc == 0); - - if(runtime->frame->used < 3) - { - Error_Report(error, 1, "Frame has not enough values on the stack to run INSERT instruction"); - return 0; - } - - Object *col = Stack_Top(runtime->stack, -2); - Object *key = Stack_Top(runtime->stack, -1); - Object *val = Stack_Top(runtime->stack, 0); - - assert(col != NULL && key != NULL && val != NULL); - - if(!Runtime_Pop(runtime, error, 2)) - return 0; - - if(!Object_Insert(col, key, val, runtime->heap, error)) - return 0; - return 1; - } - - case OPCODE_INSERT2: - { - assert(opc == 0); - - if(runtime->frame->used < 3) - { - Error_Report(error, 1, "Frame has not enough values on the stack to run INSERT2 instruction"); - return 0; - } - - Object *val = Stack_Top(runtime->stack, -2); - Object *col = Stack_Top(runtime->stack, -1); - Object *key = Stack_Top(runtime->stack, 0); - - assert(col != NULL && key != NULL && val != NULL); - - if(!Runtime_Pop(runtime, error, 2)) - return 0; - - if(!Object_Insert(col, key, val, runtime->heap, error)) - return 0; - return 1; - } - - case OPCODE_PUSHINT: - { - assert(opc == 1); - assert(ops[0].type == OPTP_INT); - - Object *obj = Object_FromInt(ops[0].as_int, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHFLT: - { - assert(opc == 1); - assert(ops[0].type == OPTP_FLOAT); - - Object *obj = Object_FromFloat(ops[0].as_float, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHSTR: - { - assert(opc == 1); - assert(ops[0].type == OPTP_STRING); - - Object *obj = Object_FromString(ops[0].as_string, -1, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHVAR: - { - assert(opc == 1); - assert(ops[0].type == OPTP_STRING); - - Object *key = Object_FromString(ops[0].as_string, -1, runtime->heap, error); - - if(key == NULL) - return 0; - - Object *locations[] = { - runtime->frame->locals, - runtime->frame->closure, - Runtime_GetBuiltins(runtime), - }; - - Object *obj = NULL; - - for(int p = 0; obj == NULL && (unsigned int) p < sizeof(locations)/sizeof(locations[0]); p += 1) - { - if(locations[p] == NULL) - continue; - - obj = Object_Select(locations[p], key, Runtime_GetHeap(runtime), error); - } - - if(obj == NULL) - { - if(error->occurred == 0) - // There's no such variable. - Error_Report(error, 0, "Reference to undefined variable \"%s\"", ops[0].as_string); - return 0; - } - - if(!Runtime_Push(runtime, error, obj)) - return 0; - - return 1; - } - - case OPCODE_PUSHNNE: - { - assert(opc == 0); - - Object *obj = Object_NewNone(runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHTRU: - { - assert(opc == 0); - - Object *obj = Object_FromBool(1, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHFLS: - { - assert(opc == 0); - - Object *obj = Object_FromBool(0, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHFUN: - { - assert(opc == 2); - assert(ops[0].type == OPTP_INT); - assert(ops[1].type == OPTP_INT); - - Object *closure = Object_NewClosure(runtime->frame->closure, runtime->frame->locals, Runtime_GetHeap(runtime), error); - - if(closure == NULL) - return 0; - - Object *obj = Object_FromNojaFunction(runtime, runtime->frame->exe, ops[0].as_int, ops[1].as_int, closure, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHLST: - { - assert(opc == 1); - assert(ops[0].type == OPTP_INT); - - Object *obj = Object_NewList(ops[0].as_int, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_PUSHMAP: - { - assert(opc == 1); - assert(ops[0].type == OPTP_INT); - - Object *obj = Object_NewMap(ops[0].as_int, runtime->heap, error); - - if(obj == NULL) - return 0; - - if(!Runtime_Push(runtime, error, obj)) - return 0; - return 1; - } - - case OPCODE_RETURN: - return 0; - - case OPCODE_JUMP: + case OPCODE_CALL: + { assert(opc == 1); assert(ops[0].type == OPTP_INT); - runtime->frame->index = ops[0].as_int; + + int argc = ops[0].as_int; + assert(argc >= 0); + + if(runtime->frame->used < argc + 1) + { + Error_Report(error, 1, "Frame doesn't own enough objects to execute call"); + return 0; + } + + Object *callable = Stack_Top(runtime->stack, 0); + assert(callable != NULL); + + Object *argv[8]; + + int max_argc = sizeof(argv) / sizeof(argv[0]); + if(argc > max_argc) + { + Error_Report(error, 1, "Static buffer only allows function calls with up to %d arguments", max_argc); + return 0; + } + + for(int i = 0; i < argc; i += 1) + { + argv[i] = Stack_Top(runtime->stack, -(i+1)); + assert(argv[i] != NULL); + } + + assert(error->occurred == 0); + (void) Runtime_Pop(runtime, error, argc+1); + assert(error->occurred == 0); + + Object *obj = Object_Call(callable, argv, argc, runtime->heap, error); + // NOTE: Every local object reference is invalidated from here. + + if(obj == NULL) + { + assert(error->occurred != 0); + return 0; + } + + assert(error->occurred == 0); + + if(!Runtime_Push(runtime, error, obj)) + return 0; return 1; - - case OPCODE_JUMPIFANDPOP: - { - assert(opc == 1); - assert(ops[0].type == OPTP_INT); - - long long int target = ops[0].as_int; - - if(runtime->frame->used == 0) - { - Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute JUMPIFNOTANDPOP"); - return 0; - } - - Object *top = Stack_Top(runtime->stack, 0); - - if(!Runtime_Pop(runtime, error, 1)) - return 0; - - assert(top != NULL); - - if(!Object_IsBool(top)) - { - Error_Report(error, 1, "JUMPIFNOTANDPOP expected a boolean on the stack"); - return 0; - } - - if(Object_ToBool(top, error)) // This can't fail because we know it's a bool. - runtime->frame->index = target; - - return 1; - } - - case OPCODE_JUMPIFNOTANDPOP: - { - assert(opc == 1); - assert(ops[0].type == OPTP_INT); - - long long int target = ops[0].as_int; - - if(runtime->frame->used == 0) - { - Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute JUMPIFNOTANDPOP"); - return 0; - } - - Object *top = Stack_Top(runtime->stack, 0); - - if(!Runtime_Pop(runtime, error, 1)) - return 0; - - assert(top != NULL); - - if(!Object_IsBool(top)) - { - Error_Report(error, 1, "JUMPIFNOTANDPOP expected a boolean on the stack"); - return 0; - } - - if(!Object_ToBool(top, error)) // This can't fail because we know it's a bool. - runtime->frame->index = target; - - return 1; - } - - default: - UNREACHABLE; - return 0; } + case OPCODE_SELECT: + { + assert(opc == 0); + + if(runtime->frame->used < 2) + { + Error_Report(error, 1, "Frame has not enough values on the stack to run SELECT instruction"); + return 0; + } + + Object *col = Stack_Top(runtime->stack, -1); + Object *key = Stack_Top(runtime->stack, 0); + + assert(col != NULL && key != NULL); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + assert(error->occurred == 0); + + Error dummy; + Error_Init(&dummy); // We want to catch the error reported by this Object_Select. + + Object *val = Object_Select(col, key, runtime->heap, &dummy); + + if(val == NULL) + { + Error_Free(&dummy); + + val = Object_NewNone(runtime->heap, error); + + if(val == NULL) + return 0; + } + + assert(error->occurred == 0); + + if(!Runtime_Push(runtime, error, val)) + return 0; + + assert(error->occurred == 0); + return 1; + } + + case OPCODE_INSERT: + { + assert(opc == 0); + + if(runtime->frame->used < 3) + { + Error_Report(error, 1, "Frame has not enough values on the stack to run INSERT instruction"); + return 0; + } + + Object *col = Stack_Top(runtime->stack, -2); + Object *key = Stack_Top(runtime->stack, -1); + Object *val = Stack_Top(runtime->stack, 0); + + assert(col != NULL && key != NULL && val != NULL); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + if(!Object_Insert(col, key, val, runtime->heap, error)) + return 0; + return 1; + } + + case OPCODE_INSERT2: + { + assert(opc == 0); + + if(runtime->frame->used < 3) + { + Error_Report(error, 1, "Frame has not enough values on the stack to run INSERT2 instruction"); + return 0; + } + + Object *val = Stack_Top(runtime->stack, -2); + Object *col = Stack_Top(runtime->stack, -1); + Object *key = Stack_Top(runtime->stack, 0); + + assert(col != NULL && key != NULL && val != NULL); + + if(!Runtime_Pop(runtime, error, 2)) + return 0; + + if(!Object_Insert(col, key, val, runtime->heap, error)) + return 0; + return 1; + } + + case OPCODE_PUSHINT: + { + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + + Object *obj = Object_FromInt(ops[0].as_int, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHFLT: + { + assert(opc == 1); + assert(ops[0].type == OPTP_FLOAT); + + Object *obj = Object_FromFloat(ops[0].as_float, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHSTR: + { + assert(opc == 1); + assert(ops[0].type == OPTP_STRING); + + Object *obj = Object_FromString(ops[0].as_string, -1, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHVAR: + { + assert(opc == 1); + assert(ops[0].type == OPTP_STRING); + + Object *key = Object_FromString(ops[0].as_string, -1, runtime->heap, error); + + if(key == NULL) + return 0; + + Object *locations[] = { + runtime->frame->locals, + runtime->frame->closure, + Runtime_GetBuiltins(runtime), + }; + + Object *obj = NULL; + + for(int p = 0; obj == NULL && (unsigned int) p < sizeof(locations)/sizeof(locations[0]); p += 1) + { + if(locations[p] == NULL) + continue; + + obj = Object_Select(locations[p], key, Runtime_GetHeap(runtime), error); + } + + if(obj == NULL) + { + if(error->occurred == 0) + // There's no such variable. + Error_Report(error, 0, "Reference to undefined variable \"%s\"", ops[0].as_string); + return 0; + } + + if(!Runtime_Push(runtime, error, obj)) + return 0; + + return 1; + } + + case OPCODE_PUSHNNE: + { + assert(opc == 0); + + Object *obj = Object_NewNone(runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHTRU: + { + assert(opc == 0); + + Object *obj = Object_FromBool(1, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHFLS: + { + assert(opc == 0); + + Object *obj = Object_FromBool(0, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHFUN: + { + assert(opc == 2); + assert(ops[0].type == OPTP_INT); + assert(ops[1].type == OPTP_INT); + + Object *closure = Object_NewClosure(runtime->frame->closure, runtime->frame->locals, Runtime_GetHeap(runtime), error); + + if(closure == NULL) + return 0; + + Object *obj = Object_FromNojaFunction(runtime, runtime->frame->exe, ops[0].as_int, ops[1].as_int, closure, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHLST: + { + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + + Object *obj = Object_NewList(ops[0].as_int, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_PUSHMAP: + { + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + + Object *obj = Object_NewMap(ops[0].as_int, runtime->heap, error); + + if(obj == NULL) + return 0; + + if(!Runtime_Push(runtime, error, obj)) + return 0; + return 1; + } + + case OPCODE_RETURN: + return 0; + + case OPCODE_JUMP: + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + runtime->frame->index = ops[0].as_int; + return 1; + + case OPCODE_JUMPIFANDPOP: + { + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + + long long int target = ops[0].as_int; + + if(runtime->frame->used == 0) + { + Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute JUMPIFNOTANDPOP"); + return 0; + } + + Object *top = Stack_Top(runtime->stack, 0); + + if(!Runtime_Pop(runtime, error, 1)) + return 0; + + assert(top != NULL); + + if(!Object_IsBool(top)) + { + Error_Report(error, 1, "JUMPIFNOTANDPOP expected a boolean on the stack"); + return 0; + } + + if(Object_ToBool(top, error)) // This can't fail because we know it's a bool. + runtime->frame->index = target; + + return 1; + } + + case OPCODE_JUMPIFNOTANDPOP: + { + assert(opc == 1); + assert(ops[0].type == OPTP_INT); + + long long int target = ops[0].as_int; + + if(runtime->frame->used == 0) + { + Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute JUMPIFNOTANDPOP"); + return 0; + } + + Object *top = Stack_Top(runtime->stack, 0); + + if(!Runtime_Pop(runtime, error, 1)) + return 0; + + assert(top != NULL); + + if(!Object_IsBool(top)) + { + Error_Report(error, 1, "JUMPIFNOTANDPOP expected a boolean on the stack"); + return 0; + } + + if(!Object_ToBool(top, error)) // This can't fail because we know it's a bool. + runtime->frame->index = target; + + return 1; + } + + default: + UNREACHABLE; + return 0; + } + return 1; } @@ -1217,19 +1216,19 @@ static _Bool collect(Runtime *runtime, Error *error) Heap_CollectReference(&runtime->builtins, runtime->heap); while(frame) - { - Heap_CollectReference(&frame->locals, runtime->heap); - Heap_CollectReference(&frame->closure, runtime->heap); - frame = frame->prev; - } + { + Heap_CollectReference(&frame->locals, runtime->heap); + Heap_CollectReference(&frame->closure, runtime->heap); + frame = frame->prev; + } for(unsigned int i = 0; i < Stack_Size(runtime->stack); i += 1) - { - Object **ref = (Object**) Stack_TopRef(runtime->stack, -i); - assert(ref != NULL); + { + Object **ref = (Object**) Stack_TopRef(runtime->stack, -i); + assert(ref != NULL); - Heap_CollectReference(ref, runtime->heap); - } + Heap_CollectReference(ref, runtime->heap); + } return Heap_StopCollection(runtime->heap); } @@ -1243,10 +1242,10 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object * assert(argc >= 0); if(runtime->depth == MAX_FRAMES) - { - Error_Report(error, 1, "Maximum nested call limit of %d was reached", MAX_FRAMES); - return NULL; - } + { + Error_Report(error, 1, "Maximum nested call limit of %d was reached", MAX_FRAMES); + return NULL; + } assert(runtime->depth < MAX_FRAMES); @@ -1264,10 +1263,10 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object * return NULL; if(frame.exe == NULL) - { - Error_Report(error, 1, "Failed to copy executable"); - return NULL; - } + { + Error_Report(error, 1, "Failed to copy executable"); + return NULL; + } // Add the frame to the runtime. frame.prev = runtime->frame; @@ -1286,53 +1285,53 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object * // Run the code. if(runtime->callback_addr != NULL) - { - if(!runtime->callback_addr(runtime, runtime->callback_userp)) - Error_Report(error, 0, "Forced abortion"); - else - while(step(runtime, error)) - { - if(!runtime->callback_addr(runtime, runtime->callback_userp)) - { - Error_Report(error, 0, "Forced abortion"); - break; - } - - //printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap)); - - if(Heap_GetUsagePercentage(runtime->heap) > 100) - if(!collect(runtime, error)) - break; - } - } - else - while(step(runtime, error)) + { + if(!runtime->callback_addr(runtime, runtime->callback_userp)) + Error_Report(error, 0, "Forced abortion"); + else + while(step(runtime, error)) { + if(!runtime->callback_addr(runtime, runtime->callback_userp)) + { + Error_Report(error, 0, "Forced abortion"); + break; + } + + //printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap)); + if(Heap_GetUsagePercentage(runtime->heap) > 100) if(!collect(runtime, error)) break; - - //printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap)); } + } + else + while(step(runtime, error)) + { + if(Heap_GetUsagePercentage(runtime->heap) > 100) + if(!collect(runtime, error)) + break; + + //printf("%2.2f%% percent.\n", Heap_GetUsagePercentage(runtime->heap)); + } // If an error occurred, we want to return NULL. if(error->occurred == 0) + { + // If the step function left something + // on the stack, we return that. If it + // didn't, we return some other default + // value like "none". + if(frame.used == 0) { - // If the step function left something - // on the stack, we return that. If it - // didn't, we return some other default - // value like "none". - if(frame.used == 0) - { - // Nothing to return on the stack. Set to none. - result = Object_NewNone(runtime->heap, error); - } - else - { - result = Stack_Top(runtime->stack, 0); - assert(result != NULL); - } + // Nothing to return on the stack. Set to none. + result = Object_NewNone(runtime->heap, error); } + else + { + result = Stack_Top(runtime->stack, 0); + assert(result != NULL); + } + } cleanup: // Remove the frame-owned items from the stack. diff --git a/src/utils/bpalloc.c b/src/utils/bpalloc.c index ec7041a..5108afd 100644 --- a/src/utils/bpalloc.c +++ b/src/utils/bpalloc.c @@ -80,11 +80,11 @@ BPAlloc *BPAlloc_Init2(int first_size, int chunk_size, first_size = chunk_size; if(fn_malloc == NULL) - { - userp = NULL; - fn_malloc = default_fn_malloc; - fn_free = default_fn_free; - } + { + userp = NULL; + fn_malloc = default_fn_malloc; + fn_free = default_fn_free; + } 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; if(fn_malloc == NULL) - { - userp = NULL; - fn_malloc = default_fn_malloc; - fn_free = default_fn_free; - } + { + userp = NULL; + fn_malloc = default_fn_malloc; + fn_free = default_fn_free; + } int required = sizeof(BPAlloc) + sizeof(BPAllocChunk) @@ -170,14 +170,14 @@ void BPAlloc_Free(BPAlloc *alloc) BPAllocChunk *chunk = alloc->tail; while(chunk->prev) - { - BPAllocChunk *prev = chunk->prev; + { + BPAllocChunk *prev = chunk->prev; - if(alloc->fn_free) - alloc->fn_free(alloc->userp, chunk); + if(alloc->fn_free) + alloc->fn_free(alloc->userp, chunk); - chunk = prev; - } + chunk = prev; + } if(!(alloc->flags & FG_STATIC)) if(alloc->fn_free) @@ -195,26 +195,26 @@ void *BPAlloc_Malloc(BPAlloc *alloc, int req_size) alloc->used = (alloc->used & ~7) + 8; if(alloc->used + req_size > alloc->size) - { - // If the chunk size is lower than the - // requested size, then set the chunk - // size to the requested size. - int chunk_size = MAX(alloc->minsize, req_size + PADDING); + { + // If the chunk size is lower than the + // requested size, then set the chunk + // size to the requested size. + int chunk_size = MAX(alloc->minsize, req_size + PADDING); - assert(alloc->fn_malloc != NULL); - BPAllocChunk *chunk = alloc->fn_malloc(alloc->userp, sizeof(BPAllocChunk) + chunk_size); + assert(alloc->fn_malloc != NULL); + BPAllocChunk *chunk = alloc->fn_malloc(alloc->userp, sizeof(BPAllocChunk) + chunk_size); - if(chunk == NULL) - return NULL; + if(chunk == NULL) + return NULL; - chunk->prev = alloc->tail; - alloc->tail = chunk; - alloc->size = chunk_size; - alloc->used = PADDING; + chunk->prev = alloc->tail; + alloc->tail = chunk; + alloc->size = chunk_size; + alloc->used = PADDING; - if(alloc->used & 7) - alloc->used = (alloc->used & ~7) + 8; - } + if(alloc->used & 7) + alloc->used = (alloc->used & ~7) + 8; + } void *addr = alloc->tail->body + alloc->used; diff --git a/src/utils/bucketlist.c b/src/utils/bucketlist.c index 78c374c..37f168f 100644 --- a/src/utils/bucketlist.c +++ b/src/utils/bucketlist.c @@ -109,42 +109,42 @@ _Bool BucketList_Append(BucketList *blist, const void *data, int size) int not_copied_yet = size; 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 - // or until the current bucket is - // full. If the bucket is already - // full, add another one. + Bucket *new_bucket = make_bucket(blist->alloc, MIN_BUCKET_SIZE); - int left_in_bucket = blist->tail->size - blist->tail->used; + if(new_bucket == NULL) + return 0; - if(left_in_bucket == 0) - { - 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; + 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; + } + blist->size += size; return 1; } @@ -158,16 +158,16 @@ void *BucketList_Append2(BucketList *blist, const void *data, int size) // current bucket, add another one with // enough space. 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) - return 0; + if(new_bucket == NULL) + return 0; - append_bucket(blist, new_bucket); - } + append_bucket(blist, new_bucket); + } 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; while(bucket && copied < len) - { - int copying = MIN(len - copied, bucket->used); - assert(copying >= 0); + { + int copying = MIN(len - copied, bucket->used); + assert(copying >= 0); - memcpy((char*) dest + copied, bucket->body, copying); + memcpy((char*) dest + copied, bucket->body, copying); - copied += copying; - bucket = bucket->next; - } + copied += copying; + bucket = bucket->next; + } } BPAlloc *BucketList_GetAlloc(BucketList *blist) diff --git a/src/utils/error.c b/src/utils/error.c index e79c11a..6949ca7 100644 --- a/src/utils/error.c +++ b/src/utils/error.c @@ -87,29 +87,29 @@ void _Error_Report2(Error *err, _Bool internal, assert(p > -1); if((unsigned int) p > sizeof(err->message2)-1) - { - char *temp = malloc(p+1); + { + char *temp = malloc(p+1); - 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 + if(temp == NULL) { - err->truncated = 0; + 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->message = err->message2; + err->length = p; + } va_end(va2); diff --git a/src/utils/promise.c b/src/utils/promise.c index aebe75f..ae1ae54 100644 --- a/src/utils/promise.c +++ b/src/utils/promise.c @@ -87,14 +87,14 @@ void Promise_Resolve(Promise *promise, const void *data, int size) Gap *gap = promise->gaps; while(gap) - { - memcpy(gap->dest, data, size); + { + memcpy(gap->dest, data, size); - if(gap->callback) - gap->callback(gap->userp); + if(gap->callback) + gap->callback(gap->userp); - gap = gap->next; - } + gap = gap->next; + } promise->gaps = NULL; } @@ -112,25 +112,25 @@ _Bool Promise_Subscribe2(Promise *promise, void *dest, void *userp, void (*callb assert(dest != NULL); if(promise->set == 0) - { - Gap *gap = BPAlloc_Malloc(promise->alloc, sizeof(Gap)); + { + Gap *gap = BPAlloc_Malloc(promise->alloc, sizeof(Gap)); - if(gap == NULL) - return 0; + if(gap == NULL) + return 0; - gap->next = promise->gaps; - gap->dest = dest; - gap->userp = userp; - gap->callback = callback; - promise->gaps = gap; - } + gap->next = promise->gaps; + gap->dest = dest; + gap->userp = userp; + gap->callback = callback; + promise->gaps = gap; + } else - { - memcpy(dest, promise->body, promise->size); + { + memcpy(dest, promise->body, promise->size); - if(callback) - callback(userp); - } + if(callback) + callback(userp); + } return 1; } \ No newline at end of file diff --git a/src/utils/source.c b/src/utils/source.c index a1812ee..3927195 100644 --- a/src/utils/source.c +++ b/src/utils/source.c @@ -86,36 +86,36 @@ Source *Source_FromFile(const char *file, Error *error) fp = fopen(file, "rb"); if(fp == NULL) - { - if(errno == ENOENT) - Error_Report(error, 0, "File \"%s\" doesn't exist", file); - else - Error_Report(error, 1, "Call to fopen failed (%s, errno = %d)", strerror(errno), errno); - return NULL; - } + { + if(errno == ENOENT) + Error_Report(error, 0, "File \"%s\" doesn't exist", file); + else + Error_Report(error, 1, "Call to fopen failed (%s, errno = %d)", strerror(errno), errno); + return NULL; + } if(fseek(fp, 0, SEEK_END)) - { - Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno); - fclose(fp); - return NULL; - } + { + Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno); + fclose(fp); + return NULL; + } size = ftell(fp); if(size < 0) - { - Error_Report(error, 1, "Call to ftell failed (%s, errno = %d)", strerror(errno), errno); - fclose(fp); - return NULL; - } + { + Error_Report(error, 1, "Call to ftell failed (%s, errno = %d)", strerror(errno), errno); + fclose(fp); + return NULL; + } if(fseek(fp, 0, SEEK_SET)) - { - Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno); - fclose(fp); - return NULL; - } + { + Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno); + fclose(fp); + return NULL; + } } // Allocate the source structure. @@ -126,11 +126,11 @@ Source *Source_FromFile(const char *file, Error *error) s = malloc(sizeof(Source) + namel + size + 2); if(s == NULL) - { - Error_Report(error, 1, "No memory"); - fclose(fp); - return NULL; - } + { + Error_Report(error, 1, "No memory"); + fclose(fp); + return NULL; + } s->name = (char*) (s + 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); 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); - fclose(fp); - free(s); - return NULL; - } + { + 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); + free(s); + return NULL; + } 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); if(memory == NULL) - { - Error_Report(error, 1, "No memory"); - return NULL; - } + { + Error_Report(error, 1, "No memory"); + return NULL; + } Source *s = memory; s->name = (char*) (s + 1); diff --git a/src/utils/stack.c b/src/utils/stack.c index 3533cb2..bfce68b 100644 --- a/src/utils/stack.c +++ b/src/utils/stack.c @@ -135,15 +135,15 @@ _Bool Stack_Push(Stack *s, void *item) Stack *Stack_Copy(Stack *s, _Bool readonly) { if(Stack_IsReadOnlyCopy(s)) - { - // Reference is readonly, - // so the copy must be - // readonly. - readonly = 1; + { + // Reference is readonly, + // so the copy must be + // readonly. + readonly = 1; - // Remove readonly bit. - s = unmark(s); - } + // Remove readonly bit. + s = unmark(s); + } s->refs += 1; diff --git a/src/utils/utf8.c b/src/utils/utf8.c index 8c2f12e..a7ca9fd 100644 --- a/src/utils/utf8.c +++ b/src/utils/utf8.c @@ -60,46 +60,46 @@ int utf8_sequence_from_utf32_codepoint(char *utf8_data, int nbytes, uint32_t utf32_code) { if(utf32_code < 128) - { - if(nbytes < 1) - return -1; + { + if(nbytes < 1) + return -1; - utf8_data[0] = utf32_code; - return 1; - } + utf8_data[0] = utf32_code; + return 1; + } if(utf32_code < 2048) - { - if(nbytes < 2) - return -1; + { + if(nbytes < 2) + return -1; - utf8_data[0] = 0xc0 | (utf32_code >> 6); - utf8_data[1] = 0x80 | (utf32_code & 0x3f); - return 2; - } + utf8_data[0] = 0xc0 | (utf32_code >> 6); + utf8_data[1] = 0x80 | (utf32_code & 0x3f); + return 2; + } if(utf32_code < 65536) - { - if(nbytes < 3) - return -1; + { + if(nbytes < 3) + return -1; - utf8_data[0] = 0xe0 | (utf32_code >> 12); - utf8_data[1] = 0x80 | ((utf32_code >> 6) & 0x3f); - utf8_data[2] = 0x80 | (utf32_code & 0x3f); - return 3; - } + utf8_data[0] = 0xe0 | (utf32_code >> 12); + utf8_data[1] = 0x80 | ((utf32_code >> 6) & 0x3f); + utf8_data[2] = 0x80 | (utf32_code & 0x3f); + return 3; + } if(utf32_code <= 0x10ffff) - { - if(nbytes < 4) - return -1; + { + if(nbytes < 4) + return -1; - utf8_data[0] = 0xf0 | (utf32_code >> 18); - utf8_data[1] = 0x80 | ((utf32_code >> 12) & 0x3f); - utf8_data[2] = 0x80 | ((utf32_code >> 6) & 0x3f); - utf8_data[3] = 0x80 | (utf32_code & 0x3f); - return 4; - } + utf8_data[0] = 0xf0 | (utf32_code >> 18); + utf8_data[1] = 0x80 | ((utf32_code >> 12) & 0x3f); + utf8_data[2] = 0x80 | ((utf32_code >> 6) & 0x3f); + utf8_data[3] = 0x80 | (utf32_code & 0x3f); + return 4; + } // Code is out of range for UTF-8. return -1; @@ -148,71 +148,71 @@ int utf8_sequence_to_utf32_codepoint(const char *utf8_data, int nbytes, uint32_t return -1; if(utf8_data[0] & 0x80) - { - // May be UTF-8. + { + // May be UTF-8. - if((unsigned char) utf8_data[0] >= 0xF0) - { - // 4 bytes. - // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if((unsigned char) utf8_data[0] >= 0xF0) + { + // 4 bytes. + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if(nbytes < 4) - return -1; + if(nbytes < 4) + return -1; - uint32_t temp - = (((uint32_t) utf8_data[0] & 0x07) << 18) - | (((uint32_t) utf8_data[1] & 0x3f) << 12) - | (((uint32_t) utf8_data[2] & 0x3f) << 6) - | (((uint32_t) utf8_data[3] & 0x3f)); + uint32_t temp + = (((uint32_t) utf8_data[0] & 0x07) << 18) + | (((uint32_t) utf8_data[1] & 0x3f) << 12) + | (((uint32_t) utf8_data[2] & 0x3f) << 6) + | (((uint32_t) utf8_data[3] & 0x3f)); - if(temp > 0x10ffff) - return -1; + if(temp > 0x10ffff) + return -1; - *utf32_code = temp; - return 4; - } + *utf32_code = temp; + return 4; + } if((unsigned char) utf8_data[0] >= 0xE0) - { - // 3 bytes. - // 1110xxxx 10xxxxxx 10xxxxxx + { + // 3 bytes. + // 1110xxxx 10xxxxxx 10xxxxxx - if(nbytes < 3) - return -1; + if(nbytes < 3) + return -1; - uint32_t temp - = (((uint32_t) utf8_data[0] & 0x0f) << 12) - | (((uint32_t) utf8_data[1] & 0x3f) << 6) - | (((uint32_t) utf8_data[2] & 0x3f)); - - if(temp > 0x10ffff) - return -1; + uint32_t temp + = (((uint32_t) utf8_data[0] & 0x0f) << 12) + | (((uint32_t) utf8_data[1] & 0x3f) << 6) + | (((uint32_t) utf8_data[2] & 0x3f)); + + if(temp > 0x10ffff) + return -1; - *utf32_code = temp; - return 3; - } + *utf32_code = temp; + return 3; + } if((unsigned char) utf8_data[0] >= 0xC0) - { - // 2 bytes. - // 110xxxxx 10xxxxxx + { + // 2 bytes. + // 110xxxxx 10xxxxxx - if(nbytes < 2) - return -1; + if(nbytes < 2) + return -1; - *utf32_code - = (((uint32_t) utf8_data[0] & 0x1f) << 6) - | (((uint32_t) utf8_data[1] & 0x3f)); + *utf32_code + = (((uint32_t) utf8_data[0] & 0x1f) << 6) + | (((uint32_t) utf8_data[1] & 0x3f)); - assert(*utf32_code <= 0x10ffff); - return 2; - } + assert(*utf32_code <= 0x10ffff); + return 2; + } - // 1 byte - // 10xxxxxx - *utf32_code = (uint32_t) utf8_data[0] & 0x3f; - return 1; - } + // 1 byte + // 10xxxxxx + *utf32_code = (uint32_t) utf8_data[0] & 0x3f; + return 1; + } // It's ASCII // 0xxxxxxx @@ -255,40 +255,40 @@ int utf8_strlen(const char *utf8_data, int nbytes) int i = 0; while(i < nbytes) - { + { #if ASSUME_ASCII - { - int ASCII_start = i; + { + int ASCII_start = i; - // Skip through ASCII - while(i < nbytes && (utf8_data[i] & 0x80) == 0) - i += 1; + // Skip through ASCII + while(i < nbytes && (utf8_data[i] & 0x80) == 0) + 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 - // string, or we encountered some unicode. + // Either we scanned through all of the + // string, or we encountered some unicode. - if(i == nbytes) - // String ended. - break; - } + if(i == nbytes) + // String ended. + break; + } #endif - // Found unicode. - { - int n = utf8_sequence_to_utf32_codepoint(utf8_data + i, nbytes - i, NULL); + // Found unicode. + { + int n = utf8_sequence_to_utf32_codepoint(utf8_data + i, nbytes - i, NULL); - if(n < 1) - return -1; + if(n < 1) + return -1; - i += n; - len += 1; - } + i += n; + len += 1; } + } return len; } @@ -347,11 +347,11 @@ int utf8_prev(const char *utf8_data, int nbytes, int idx, uint32_t *utf32_code) // to go faster. if((utf8_data[tail] & 0x80) == 0) - { - if(utf32_code) - *utf32_code = utf8_data[tail]; - return tail; - } + { + if(utf32_code) + *utf32_code = utf8_data[tail]; + return tail; + } } #endif @@ -362,11 +362,11 @@ int utf8_prev(const char *utf8_data, int nbytes, int idx, uint32_t *utf32_code) idx -= 1; if(idx == -1) - { - // No head sequence byte was found, - // so this isn't valid UTF-8. - return -1; - } + { + // No head sequence byte was found, + // so this isn't valid UTF-8. + return -1; + } // The index of the head byte. int head = idx;