added error builtin and json parser example
This commit is contained in:
+239
-34
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
fun is_space(c)
|
fun isSpace(c)
|
||||||
return c == ' '
|
return c == ' '
|
||||||
or c == '\t'
|
or c == '\t'
|
||||||
or c == '\n';
|
or c == '\n';
|
||||||
|
|
||||||
fun is_digit(c)
|
fun isDigit(c)
|
||||||
return unicode(c) <= unicode('9')
|
return unicode(c) <= unicode('9')
|
||||||
and unicode(c) >= unicode('0');
|
and unicode(c) >= unicode('0');
|
||||||
|
|
||||||
@@ -35,60 +35,265 @@ fun parse(str) {
|
|||||||
|
|
||||||
ctx = {str: str, i: 0};
|
ctx = {str: str, i: 0};
|
||||||
|
|
||||||
skip(ctx, is_space);
|
skip(ctx, isSpace);
|
||||||
|
|
||||||
if ended(ctx): {
|
if ended(ctx): {
|
||||||
print('Source only contains whitespace');
|
print('Source only contains whitespace');
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parse_any_value(ctx);
|
return parseAnyValue(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parse_any_value(ctx) {
|
fun parseArrayValue(ctx) {
|
||||||
|
|
||||||
if is_digit(current(ctx)): {
|
assert(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if current(ctx) == '.': {
|
next(ctx); # Skip '['.
|
||||||
|
|
||||||
next(ctx);
|
skip(ctx, isSpace);
|
||||||
|
|
||||||
if ended(ctx):
|
if ended(ctx): {
|
||||||
# Source string ended unexpectedly after dot.
|
error("Source ended inside an array");
|
||||||
return none;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = [
|
tests = [
|
||||||
'',
|
'',
|
||||||
'1'
|
'1',
|
||||||
|
'10',
|
||||||
|
'1.10',
|
||||||
|
'"jeje"',
|
||||||
|
'[]',
|
||||||
|
'[1,2,3]',
|
||||||
|
' [ ] ',
|
||||||
|
' [ 1 , 2 , 3 ]',
|
||||||
|
'{}',
|
||||||
|
' { } ',
|
||||||
|
'{"hoy":4}',
|
||||||
|
' { "hoy" : 4 } ',
|
||||||
|
'a'
|
||||||
];
|
];
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while i < count(tests): {
|
while i < count(tests): {
|
||||||
parse(tests[i]);
|
r = parse(tests[i]);
|
||||||
|
if r == none:
|
||||||
|
print('\nTest ', i, ' failed\n');
|
||||||
|
else
|
||||||
|
print(tests[i], ' -> ', r, '\n');
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,22 @@ static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Er
|
|||||||
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
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)
|
static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||||
{
|
{
|
||||||
unsigned int total_count = 0;
|
unsigned int total_count = 0;
|
||||||
@@ -272,6 +288,7 @@ const StaticMapSlot bins_basic[] = {
|
|||||||
{ "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 },
|
{ "print", SM_FUNCT, .as_funct = bin_print, .argc = -1 },
|
||||||
{ "input", SM_FUNCT, .as_funct = bin_input, .argc = 0 },
|
{ "input", SM_FUNCT, .as_funct = bin_input, .argc = 0 },
|
||||||
{ "count", SM_FUNCT, .as_funct = bin_count, .argc = 1 },
|
{ "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 },
|
{ "assert", SM_FUNCT, .as_funct = bin_assert, .argc = -1 },
|
||||||
{ NULL, SM_END, {}, {} },
|
{ NULL, SM_END, {}, {} },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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))
|
if(!emit_instr_for_node(exeb, operand, break_dest, error))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return ExeBuilder_Append(exeb, error,
|
if(!ExeBuilder_Append(exeb, error,
|
||||||
exprkind_to_opcode(expr->kind),
|
exprkind_to_opcode(expr->kind),
|
||||||
NULL, 0, node->offset, node->length);
|
NULL, 0, node->offset, node->length))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
case EXPR_ASS:
|
case EXPR_ASS:
|
||||||
|
|||||||
Reference in New Issue
Block a user