harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit d3caa452677c37ba27a04041c2bde49a78a504b7
parent bd1b32af9c699be04f24ef97fedb5b0b252ccdef
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Mon, 28 Dec 2020 22:09:32 -0500

parse: implement struct literals

Diffstat:
Minclude/ast.h | 22++++++++++++++++++++++
Msrc/parse.c | 136++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 154 insertions(+), 4 deletions(-)

diff --git a/include/ast.h b/include/ast.h @@ -182,6 +182,27 @@ struct ast_expression_slice { struct ast_expression *start, *end; }; +struct ast_expression_struct; + +struct ast_field_value { + bool is_embedded; + union { + struct { + char *name; + struct ast_type *type; + struct ast_expression *initializer; + } field; + struct ast_expression *embedded; + }; + struct ast_field_value *next; +}; + +struct ast_expression_struct { + bool autofill; + struct identifier type; + struct ast_field_value *fields; +}; + struct ast_expression_unarithm { enum unarithm_operator op; struct ast_expression *operand; @@ -200,6 +221,7 @@ struct ast_expression { struct ast_expression_measure measure; struct ast_expression_return _return; struct ast_expression_slice slice; + struct ast_expression_struct _struct; struct ast_expression_unarithm unarithm; }; }; diff --git a/src/parse.c b/src/parse.c @@ -602,13 +602,13 @@ parse_type(struct parser *par) static struct ast_expression *parse_complex_expression(struct parser *par); static struct ast_expression * -parse_access(struct parser *par) +parse_access(struct parser *par, struct identifier ident) { trace(TR_PARSE, "access"); struct ast_expression *exp = xcalloc(1, sizeof(struct ast_expression)); exp->type = EXPR_ACCESS; exp->access.type = ACCESS_IDENTIFIER; - parse_identifier(par, &exp->access.ident); + exp->access.ident = ident; return exp; } @@ -727,6 +727,121 @@ parse_array_literal(struct parser *par) return exp; } +static struct ast_expression *parse_struct_literal(struct parser *par, + struct identifier ident); + +static struct ast_field_value * +parse_field_value(struct parser *par) +{ + struct ast_field_value *exp = + xcalloc(sizeof(struct ast_field_value), 1); + char *name; + struct token tok = {0}; + switch (lex(par->lex, &tok)) { + case T_NAME: + name = tok.name; + switch (lex(par->lex, &tok)) { + case T_COLON: + exp->is_embedded = false; + exp->field.name = name; + exp->field.type = parse_type(par); + want(par, T_EQUAL, NULL); + // TODO: initializer can be allocation + exp->field.initializer = parse_complex_expression(par); + trace(TR_PARSE, "%s: [type] = [expr]", name); + break; + case T_EQUAL: + exp->is_embedded = false; + exp->field.name = name; + // TODO: initializer can be allocation + exp->field.initializer = parse_simple_expression(par); + trace(TR_PARSE, "%s = [expr]", name); + break; + case T_DOUBLE_COLON: + exp->is_embedded = true; + struct identifier ident = {0}; + struct identifier *i = &ident; + parse_identifier(par, i); + while (i->ns != NULL) { + i = i->ns; + } + i->ns = xcalloc(sizeof(struct identifier), 1); + i->ns->name = name; + exp->embedded = parse_struct_literal(par, ident); + trace(TR_PARSE, "[embedded struct %s]", + identifier_unparse(&ident)); + break; + default: + unlex(par->lex, &tok); + exp->is_embedded = true; + ident.name = name; + ident.ns = NULL; + exp->embedded = parse_struct_literal(par, ident); + trace(TR_PARSE, "[embedded struct %s]", name); + break; + } + break; + case T_STRUCT: + exp->is_embedded = true; + struct identifier id = {0}; + exp->embedded = parse_struct_literal(par, id); + trace(TR_PARSE, "[embedded anonymous struct]"); + break; + default: + assert(0); + } + return exp; +} + +static struct ast_expression * +parse_struct_literal(struct parser *par, struct identifier ident) +{ + trenter(TR_PARSE, "struct-literal"); + want(par, T_LBRACE, NULL); + struct ast_expression *exp = xcalloc(sizeof(struct ast_expression), 1); + exp->type = EXPR_STRUCT; + exp->_struct.type = ident; + struct ast_field_value **next = &exp->_struct.fields; + struct token tok = {0}; + while (tok.token != T_RBRACE) { + switch (lex(par->lex, &tok)) { + case T_ELLIPSIS: + trace(TR_PARSE, "..."); + synassert(ident.name != NULL, &tok, T_RBRACE, T_EOF); + exp->_struct.autofill = true; + if (lex(par->lex, &tok) != T_COMMA) { + unlex(par->lex, &tok); + } + want(par, T_RBRACE, &tok); + unlex(par->lex, &tok); + break; + case T_NAME: + case T_STRUCT: + unlex(par->lex, &tok); + *next = parse_field_value(par); + next = &(*next)->next; + break; + default: + synassert(false, &tok, T_ELLIPSIS, T_NAME, T_RBRACE, + T_STRUCT, T_EOF); + break; + } + switch (lex(par->lex, &tok)) { + case T_COMMA: + if (lex(par->lex, &tok) != T_RBRACE) { + unlex(par->lex, &tok); + } + break; + case T_RBRACE: + break; + default: + synassert(false, &tok, T_COMMA, T_RBRACE, T_EOF); + } + } + trleave(TR_PARSE, NULL); + return exp; +} + static struct ast_expression * parse_plain_expression(struct parser *par) { @@ -745,12 +860,25 @@ parse_plain_expression(struct parser *par) return parse_constant(par); case T_NAME: unlex(par->lex, &tok); - return parse_access(par); + struct identifier ident = {0}; + parse_identifier(par, &ident); + struct token tok = {0}; + switch (lex(par->lex, &tok)) { + case T_LBRACE: + unlex(par->lex, &tok); + return parse_struct_literal(par, ident); + default: + unlex(par->lex, &tok); + return parse_access(par, ident); + } + assert(0); case T_LBRACKET: unlex(par->lex, &tok); return parse_array_literal(par); case T_STRUCT: - assert(0); // TODO: Struct literal + ident.name = NULL; + ident.ns = NULL; + return parse_struct_literal(par, ident); // nested-expression case T_LPAREN: exp = parse_complex_expression(par);