diff --git a/examples/json.noja b/examples/json.noja index ead191d..0409aa9 100644 --- a/examples/json.noja +++ b/examples/json.noja @@ -1,10 +1,10 @@ -fun is_space(c) +fun isSpace(c) return c == ' ' or c == '\t' or c == '\n'; -fun is_digit(c) +fun isDigit(c) return unicode(c) <= unicode('9') and unicode(c) >= unicode('0'); @@ -35,60 +35,265 @@ fun parse(str) { ctx = {str: str, i: 0}; - skip(ctx, is_space); + skip(ctx, isSpace); if ended(ctx): { print('Source only contains whitespace'); return none; } - return parse_any_value(ctx); + return parseAnyValue(ctx); } -fun parse_any_value(ctx) { +fun parseArrayValue(ctx) { + + assert(current(ctx) == '['); - if is_digit(current(ctx)): { - # Number (int or float) - parsed = 0; - while not ended(ctx) and is_digit(current(ctx)): { - parsed = parsed * 10 + unicode(current(ctx)) - unicode('0'); - next(ctx); - } + next(ctx); # Skip '['. - if current(ctx) == '.': { + skip(ctx, isSpace); - next(ctx); - - if ended(ctx): - # Source string ended unexpectedly after dot. - return none; - - if not is_digit(current(ctx)): - # Got something other than a digit after dot. - return none; - - fact = 1; - while not ended(ctx) and is_digit(current(ctx)): { - fact = fact / 10.0; - parsed = parsed + fact * (unicode(current(ctx)) - unicode('0')); - next(ctx); - } - } - - return parsed; + if ended(ctx): { + error("Source ended inside an array"); + return none; } - assert(false); + arr = []; + + if current(ctx) == ']': { + next(ctx); + return arr; + } + + while true: { + + child = parseAnyValue(ctx); + + if child == none: + return none; + + arr[count(arr)] = child; + + skip(ctx, isSpace); + + if ended(ctx): { + error("Source ended inside an array"); + return none; + } + + if current(ctx) == ']': + break; + + if current(ctx) != ',': { + error("Bad character inside array"); + return none; + } + + next(ctx); # Skip ','. + + skip(ctx, isSpace); + + if ended(ctx): { + error("Source ended inside an array"); + return none; + } + } + + next(ctx); + return arr; +} + +fun parseObjectValue(ctx) { + + assert(current(ctx) == '{'); + + next(ctx); # Skip '{'. + + skip(ctx, isSpace); + + if ended(ctx): { + error("Source ended inside an object"); + return none; + } + + obj = {}; + + if current(ctx) == '}': { + next(ctx); + return {}; + } + + while true: { + + if current(ctx) != '"': { + error("Bad character where a string was expected"); + return none; + } + + key = parseStringValue(ctx); + + if key == none: + return none; + + skip(ctx, isSpace); + + if current(ctx) != ':': { + error("Bad character where ':' was expected"); + return none; + } + + next(ctx); # Skip ':'. + + skip(ctx, isSpace); + + child = parseAnyValue(ctx); + + if child == none: + return none; + + obj[key] = child; + + skip(ctx, isSpace); + + if ended(ctx): { + error("Source ended inside an arrays"); + return none; + } + + if current(ctx) == '}': + break; + + if current(ctx) != ',': { + error("Bad character inside array"); + return none; + } + + next(ctx); # Skip ','. + + skip(ctx, isSpace); + + if ended(ctx): { + error("Source ended inside an array"); + return none; + } + } + + next(ctx); + return obj; +} + +fun parseStringValue(ctx) { + + next(ctx); # Skip the '"'. + + buff = ''; + + while not ended(ctx): { + + if current(ctx) == '"': + break; + + buff = strcat(buff, current(ctx)); + + next(ctx); + } + + if ended(ctx): { + error("Source ended inside a string"); + return none; + } + + next(ctx); # Skip the '"'. + return buff; +} + +fun parseNumberValue(ctx) { + + assert(isDigit(current(ctx))); + + # Number (int or float) + + parsed = 0; + while not ended(ctx): { + if not isDigit(current(ctx)): + break; + parsed = parsed * 10 + unicode(current(ctx)) - unicode('0'); + next(ctx); + } + + if ended(ctx): + return parsed; + + if current(ctx) == '.': { + + next(ctx); + + if ended(ctx): { + error("Source string ended unexpectedly after dot"); + return none; + } + + if not isDigit(current(ctx)): { + error("Got something other than a digit after dot"); + return none; + } + + fact = 1; + while not ended(ctx): { + if not isDigit(current(ctx)): + break; + fact = fact / 10.0; + parsed = parsed + fact * (unicode(current(ctx)) - unicode('0')); + next(ctx); + } + } + + return parsed; +} + +fun parseAnyValue(ctx) { + + assert(not ended(ctx)); + + if current(ctx) == '[': + return parseArrayValue(ctx); + + if current(ctx) == '{': + return parseObjectValue(ctx); + + if current(ctx) == '"': + return parseStringValue(ctx); + + if isDigit(current(ctx)): + return parseNumberValue(ctx); + + error("Not implemented yet"); } tests = [ '', - '1' + '1', + '10', + '1.10', + '"jeje"', + '[]', + '[1,2,3]', + ' [ ] ', + ' [ 1 , 2 , 3 ]', + '{}', + ' { } ', + '{"hoy":4}', + ' { "hoy" : 4 } ', + 'a' ]; i = 0; while i < count(tests): { - parse(tests[i]); + r = parse(tests[i]); + if r == none: + print('\nTest ', i, ' failed\n'); + else + print(tests[i], ' -> ', r, '\n'); i = i + 1; } diff --git a/src/builtins/basic.c b/src/builtins/basic.c index d082445..45fb1da 100644 --- a/src/builtins/basic.c +++ b/src/builtins/basic.c @@ -158,6 +158,22 @@ static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Er return Object_NewNone(Runtime_GetHeap(runtime), error); } +static Object *bin_error(Runtime *runtime, Object **argv, unsigned int argc, Error *error) +{ + assert(argc == 1); + + int length; + const char *string; + + string = Object_ToString(argv[0], &length, Runtime_GetHeap(runtime), error); + + if(string == NULL) + return NULL; + + Error_Report(error, 0, "%s", string); + return NULL; +} + static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Error *error) { unsigned int total_count = 0; @@ -272,6 +288,7 @@ const StaticMapSlot bins_basic[] = { { "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 }, { "input", SM_FUNCT, .as_funct = bin_input, .argc = 0 }, { "count", SM_FUNCT, .as_funct = bin_count, .argc = 1 }, + { "error", SM_FUNCT, .as_funct = bin_error, .argc = 1 }, { "assert", SM_FUNCT, .as_funct = bin_assert, .argc = -1 }, { NULL, SM_END, {}, {} }, }; diff --git a/src/compiler/compile.c b/src/compiler/compile.c index ddd10fc..a8789d0 100644 --- a/src/compiler/compile.c +++ b/src/compiler/compile.c @@ -108,9 +108,11 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Promise *break_de if(!emit_instr_for_node(exeb, operand, break_dest, error)) return 0; - return ExeBuilder_Append(exeb, error, + if(!ExeBuilder_Append(exeb, error, exprkind_to_opcode(expr->kind), - NULL, 0, node->offset, node->length); + NULL, 0, node->offset, node->length)) + return 0; + return 1; } case EXPR_ASS: