changed operator priority
This commit is contained in:
@@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
fun is_space(c)
|
||||||
|
return c == ' '
|
||||||
|
or c == '\t'
|
||||||
|
or c == '\n';
|
||||||
|
|
||||||
|
fun is_digit(c)
|
||||||
|
return unicode(c) <= unicode('9')
|
||||||
|
and unicode(c) >= unicode('0');
|
||||||
|
|
||||||
|
fun skip(ctx, test)
|
||||||
|
while not ended(ctx) and test(current(ctx)):
|
||||||
|
next(ctx);
|
||||||
|
|
||||||
|
fun ended(ctx)
|
||||||
|
return ctx.i == count(ctx.str);
|
||||||
|
|
||||||
|
fun next(ctx) {
|
||||||
|
assert(ctx.i < count(ctx.str));
|
||||||
|
ctx.i = ctx.i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun current(ctx)
|
||||||
|
return ctx.str[ctx.i];
|
||||||
|
|
||||||
|
fun parse(str) {
|
||||||
|
|
||||||
|
if str == none:
|
||||||
|
str = '';
|
||||||
|
|
||||||
|
ctx = {str: str, i: 0};
|
||||||
|
|
||||||
|
skip(ctx, is_space);
|
||||||
|
|
||||||
|
if ended(ctx):
|
||||||
|
# JSON source string only contains whitespace.
|
||||||
|
return none;
|
||||||
|
|
||||||
|
return parse_any_value(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parse_any_value(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if current(ctx) == '.': {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
parse();
|
||||||
@@ -187,7 +187,7 @@ static Object *bin_strcat(Runtime *runtime, Object **argv, unsigned int argc, Er
|
|||||||
{
|
{
|
||||||
Error_Report(error, 1, "No memory");
|
Error_Report(error, 1, "No memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *result = NULL;
|
Object *result = NULL;
|
||||||
|
|||||||
+61
-39
@@ -131,6 +131,7 @@ static Node *parse_ifelse_statement(Context *ctx);
|
|||||||
static Node *parse_compound_statement(Context *ctx, TokenKind end);
|
static Node *parse_compound_statement(Context *ctx, TokenKind end);
|
||||||
static Node *parse_function_definition(Context *ctx);
|
static Node *parse_function_definition(Context *ctx);
|
||||||
static Node *parse_postfix_expression(Context *ctx);
|
static Node *parse_postfix_expression(Context *ctx);
|
||||||
|
static Node *parse_prefix_expression(Context *ctx);
|
||||||
static Node *parse_while_statement(Context *ctx);
|
static Node *parse_while_statement(Context *ctx);
|
||||||
static Node *parse_dowhile_statement(Context *ctx);
|
static Node *parse_dowhile_statement(Context *ctx);
|
||||||
|
|
||||||
@@ -865,7 +866,6 @@ static Node *parse_list_primary_expression(Context *ctx)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Node *parse_map_primary_expression(Context *ctx)
|
static Node *parse_map_primary_expression(Context *ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != NULL);
|
assert(ctx != NULL);
|
||||||
@@ -1067,42 +1067,6 @@ static Node *parse_primary_expresion(Context *ctx)
|
|||||||
|
|
||||||
switch(current(ctx))
|
switch(current(ctx))
|
||||||
{
|
{
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
case TKWNOT:
|
|
||||||
{
|
|
||||||
Token *unary_operator = current_token(ctx);
|
|
||||||
|
|
||||||
next(ctx);
|
|
||||||
|
|
||||||
Node *operand = parse_primary_expresion(ctx);
|
|
||||||
|
|
||||||
if(operand == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
OperExprNode *temp = BPAlloc_Malloc(ctx->alloc, sizeof(OperExprNode));
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (Node*) temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
return parse_list_primary_expression(ctx);
|
return parse_list_primary_expression(ctx);
|
||||||
|
|
||||||
@@ -1504,6 +1468,64 @@ done:
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
Token *unary_operator = current_token(ctx);
|
||||||
|
|
||||||
|
next(ctx);
|
||||||
|
|
||||||
|
Node *operand = parse_prefix_expression(ctx);
|
||||||
|
|
||||||
|
if(operand == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
OperExprNode *temp = BPAlloc_Malloc(ctx->alloc, sizeof(OperExprNode));
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (Node*) temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return parse_postfix_expression(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNREACHABLE;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static inline _Bool isbinop(Token *tok)
|
static inline _Bool isbinop(Token *tok)
|
||||||
{
|
{
|
||||||
assert(tok != NULL);
|
assert(tok != NULL);
|
||||||
@@ -1577,7 +1599,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
|||||||
|
|
||||||
next(ctx);
|
next(ctx);
|
||||||
|
|
||||||
Node *right_expr = parse_postfix_expression(ctx);
|
Node *right_expr = parse_prefix_expression(ctx);
|
||||||
|
|
||||||
if(right_expr == NULL)
|
if(right_expr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1640,7 +1662,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec)
|
|||||||
|
|
||||||
static Node *parse_expression(Context *ctx)
|
static Node *parse_expression(Context *ctx)
|
||||||
{
|
{
|
||||||
Node *left_expr = parse_postfix_expression(ctx);
|
Node *left_expr = parse_prefix_expression(ctx);
|
||||||
|
|
||||||
if(left_expr == NULL)
|
if(left_expr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ static void print(Object *obj, FILE *fp);
|
|||||||
static char *to_string(Object *self, int *size, Heap *heap, Error *err);
|
static char *to_string(Object *self, int *size, Heap *heap, Error *err);
|
||||||
static _Bool op_eql(Object *self, Object *other);
|
static _Bool op_eql(Object *self, Object *other);
|
||||||
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
static void walkexts(Object *self, void (*callback)(void **referer, unsigned int size, void *userp), void *userp);
|
||||||
|
static Object *select(Object *self, Object *key, Heap *heap, Error *error);
|
||||||
|
|
||||||
static TypeObject t_string = {
|
static TypeObject t_string = {
|
||||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||||
@@ -59,11 +60,61 @@ static TypeObject t_string = {
|
|||||||
.count = count,
|
.count = count,
|
||||||
.copy = copy,
|
.copy = copy,
|
||||||
.print = print,
|
.print = print,
|
||||||
|
.select = select,
|
||||||
.to_string = to_string,
|
.to_string = to_string,
|
||||||
.op_eql = op_eql,
|
.op_eql = op_eql,
|
||||||
.walkexts = walkexts,
|
.walkexts = walkexts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int char_index_to_offset(StringObject *str, int idx)
|
||||||
|
{
|
||||||
|
// Iterate over a string to find the first byte of
|
||||||
|
// the utf-8 character number [idx].
|
||||||
|
|
||||||
|
int scanned_bytes = 0,
|
||||||
|
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;
|
||||||
|
|
||||||
|
assert(scanned_bytes <= str->bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(idx == 0);
|
||||||
|
return scanned_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object *select(Object *self, Object *key, Heap *heap, Error *error)
|
||||||
|
{
|
||||||
|
assert(self != NULL && self->type == &t_string);
|
||||||
|
assert(key != NULL && heap != NULL && error != NULL);
|
||||||
|
|
||||||
|
if(!Object_IsInt(key))
|
||||||
|
{
|
||||||
|
Error_Report(error, 0, "Non integer key");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = Object_ToInt(key, error);
|
||||||
|
assert(error->occurred == 0);
|
||||||
|
|
||||||
|
StringObject *str = (StringObject*) self;
|
||||||
|
|
||||||
|
if(idx < 0 || idx >= str->count)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
return Object_FromString(str->body + byteoffset, codelength, heap, error);
|
||||||
|
}
|
||||||
|
|
||||||
static char *to_string(Object *self, int *size, Heap *heap, Error *err)
|
static char *to_string(Object *self, int *size, Heap *heap, Error *err)
|
||||||
{
|
{
|
||||||
assert(self != NULL);
|
assert(self != NULL);
|
||||||
|
|||||||
Reference in New Issue
Block a user