added error builtin and json parser example

This commit is contained in:
cozis
2022-04-03 02:23:35 +02:00
parent 1d13ffc118
commit 29e80c6319
3 changed files with 261 additions and 37 deletions
+239 -34
View File
@@ -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) {
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);
}
assert(current(ctx) == '[');
if current(ctx) == '.': {
next(ctx); # Skip '['.
next(ctx);
skip(ctx, isSpace);
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;
}
+17
View File
@@ -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, {}, {} },
};
+4 -2
View File
@@ -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: