added map expressions

This commit is contained in:
Francesco Cozzuto
2021-11-26 08:52:24 +01:00
parent ba9c01f261
commit ed32b1a52b
6 changed files with 179 additions and 0 deletions
+1
View File
@@ -69,6 +69,7 @@ static const InstrInfo instr_table[] = {
[OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL}, [OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL},
[OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_INT, OPTP_INT}}, [OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
[OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}}, [OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_PUSHMAP] = {"PUSHMAP", 1, (OperandType[]) {OPTP_INT}},
[OPCODE_RETURN] = {"RETURN", 0, NULL}, [OPCODE_RETURN] = {"RETURN", 0, NULL},
+1
View File
@@ -48,6 +48,7 @@ typedef enum {
OPCODE_PUSHNNE, OPCODE_PUSHNNE,
OPCODE_PUSHFUN, OPCODE_PUSHFUN,
OPCODE_PUSHLST, OPCODE_PUSHLST,
OPCODE_PUSHMAP,
OPCODE_RETURN, OPCODE_RETURN,
OPCODE_JUMPIFANDPOP, OPCODE_JUMPIFANDPOP,
OPCODE_JUMPIFNOTANDPOP, OPCODE_JUMPIFNOTANDPOP,
+8
View File
@@ -32,6 +32,7 @@ typedef enum {
EXPR_ASS, EXPR_ASS,
EXPR_INT, EXPR_INT,
EXPR_MAP,
EXPR_CALL, EXPR_CALL,
EXPR_LIST, EXPR_LIST,
EXPR_NONE, EXPR_NONE,
@@ -86,6 +87,13 @@ typedef struct {
int itemc; int itemc;
} ListExprNode; } ListExprNode;
typedef struct {
ExprNode base;
Node *keys;
Node *items;
int itemc;
} MapExprNode;
typedef struct { typedef struct {
ExprNode base; ExprNode base;
char *val; char *val;
+31
View File
@@ -167,6 +167,37 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
return 1; 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, error))
return 0;
if(!emit_instr_for_node(exeb, item, 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: case EXPR_CALL:
{ {
CallExprNode *p = (CallExprNode*) expr; CallExprNode *p = (CallExprNode*) expr;
+123
View File
@@ -848,6 +848,126 @@ static Node *parse_list_primary_expression(Context *ctx)
} }
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;
}
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;
}
int offset = current_token(ctx)->offset;
Node *keys = NULL;
Node *items = NULL;
int itemc = 0;
next(ctx); // Skip the '['.
if(current(ctx) != '}')
{
Node *ktail = NULL, *tail = NULL;
while(1)
{
Node *key = parse_expression(ctx);
if(key == NULL)
return NULL;
if(done(ctx))
{
Error_Report(ctx->error, 0, "Source ended where a map key-value separator ':' was expected");
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;
}
next(ctx);
// Parse.
Node *item = parse_expression(ctx);
if(item == NULL)
return NULL;
// Append.
if(tail)
{
ktail->next = key;
tail->next = item;
}
else
{
keys = key;
items = item;
}
ktail = key;
tail = item;
itemc += 1;
// Get ',' or '}'.
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 ','.
}
}
int length = current_token(ctx)->offset
+ current_token(ctx)->length
- offset;
next(ctx); // Skip the ']'.
MapExprNode *map;
{
map = BPAlloc_Malloc(ctx->alloc, sizeof(MapExprNode));
if(map == NULL)
{
Error_Report(ctx->error, 1, "No memory");
return NULL;
}
map->base.base.kind = NODE_EXPR;
map->base.base.next = NULL;
map->base.base.offset = offset;
map->base.base.length = length;
map->base.kind = EXPR_MAP;
map->keys = keys;
map->items = items;
map->itemc = itemc;
}
return (Node*) map;
}
static char *copy_token_text(Context *ctx) static char *copy_token_text(Context *ctx)
{ {
char *copy = BPAlloc_Malloc(ctx->alloc, ctx->token->length + 1); char *copy = BPAlloc_Malloc(ctx->alloc, ctx->token->length + 1);
@@ -905,6 +1025,9 @@ static Node *parse_primary_expresion(Context *ctx)
case '[': case '[':
return parse_list_primary_expression(ctx); return parse_list_primary_expression(ctx);
case '{':
return parse_map_primary_expression(ctx);
case '(': case '(':
{ {
next(ctx); // Consume the '('. next(ctx); // Consume the '('.
+15
View File
@@ -848,6 +848,21 @@ static _Bool step(Runtime *runtime, Error *error)
return 1; 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: case OPCODE_RETURN:
return 0; return 0;