feat: implement objects and classes

This commit is contained in:
samsonium
2026-10-16 18:11:28 +03:00
parent 683dd08181
commit bc5d887ec4
22 changed files with 848 additions and 116 deletions
+90 -53
View File
@@ -72,8 +72,9 @@ static fzl_token_t *next(fzl_parser_t *parser)
// Consume token at cursor and move to the next
static fzl_token_t *consume(fzl_parser_t *parser)
{
if (!parser || !parser->cursor)
if (!parser || !parser->cursor || !parser->cursor->token)
return NULL;
fzl_token_t *tok = parser->cursor->token;
parser->cursor = parser->cursor->next;
return tok;
@@ -222,71 +223,75 @@ fzl_node_t *parse_postfix(fzl_parser_t *parser)
return NULL;
}
if (is(parser, FZL_TOKTYPE_LPAREN))
if (is(parser, FZL_TOKTYPE_LPAREN) || is(parser, FZL_TOKTYPE_DOT))
{
while (is(parser, FZL_TOKTYPE_LPAREN))
while (is(parser, FZL_TOKTYPE_LPAREN) || is(parser, FZL_TOKTYPE_DOT))
{
consume(parser);
fzl_token_t *post = consume(parser);
size_t args_capacity = 2;
size_t args_count = 0;
fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *));
while (!is(parser, FZL_TOKTYPE_RPAREN))
if (post->type == FZL_TOKTYPE_LPAREN)
{
fzl_node_t *arg = parse_expression(parser);
if (!arg)
size_t args_capacity = 2;
size_t args_count = 0;
fzl_node_t **args = malloc(args_capacity * sizeof(fzl_node_t *));
while (!is(parser, FZL_TOKTYPE_RPAREN))
{
fzl_node_t *arg = parse_expression(parser);
if (!arg)
{
free(args);
return NULL;
}
if (args_capacity <= args_count)
{
args_capacity *= 2;
args = realloc(args, args_capacity * sizeof(fzl_node_t));
}
args[args_count] = arg;
args_count++;
if (is(parser, FZL_TOKTYPE_COMMA))
consume(parser);
}
fzl_token_t *rparen = consume(parser);
if (!rparen || rparen->type != FZL_TOKTYPE_RPAREN)
{
free(args);
snprintf(plast_err, sizeof(plast_err),
"'%s': expected ')' after argument list at %ld:%ld",
peek(parser)->filename, peek(parser)->ln, peek(parser)->cn);
return NULL;
}
if (args_capacity <= args_count)
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, left->token);
node->call.callee = left;
node->call.args = args;
node->call.args_count = args_count;
left = node;
}
else if (post->type == FZL_TOKTYPE_DOT)
{
if (!is(parser, FZL_TOKTYPE_NAME))
{
args_capacity *= 2;
args = realloc(args, args_capacity * sizeof(fzl_node_t));
snprintf(plast_err, sizeof(plast_err),
"'%s': expected name after '.' at %ld:%ld",
last_known_tok->filename, last_known_tok->ln,
last_known_tok->cn);
return NULL;
}
args[args_count] = arg;
args_count++;
fzl_token_t *name = consume(parser);
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FIELD, name);
node->memb.parent = left;
node->memb.field = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name);
if (is(parser, FZL_TOKTYPE_COMMA))
consume(parser);
left = node;
}
fzl_token_t *rparen = consume(parser);
if (!rparen || rparen->type != FZL_TOKTYPE_RPAREN)
{
free(args);
snprintf(plast_err, sizeof(plast_err),
"'%s': expected ')' after argument list at %ld:%ld",
peek(parser)->filename, peek(parser)->ln, peek(parser)->cn);
return NULL;
}
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CALL, left->token);
node->call.callee = left;
node->call.args = args;
node->call.args_count = args_count;
left = node;
}
}
else if (is(parser, FZL_TOKTYPE_DOT))
{
while (is(parser, FZL_TOKTYPE_DOT))
{
consume(parser);
fzl_node_t *right = parse_primary(parser);
if (!right)
return NULL;
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FIELD, right->token);
node->memb.parent = left;
node->memb.field = right;
left = node;
}
}
@@ -567,10 +572,33 @@ fzl_node_t *parse_or(fzl_parser_t *parser)
return left;
}
// Object construct parsing
fzl_node_t *parse_new(fzl_parser_t *parser)
{
if (!is(parser, FZL_TOKTYPE_NEW))
return parse_or(parser);
fzl_token_t *new = consume(parser);
fzl_node_t *objname = parse_or(parser);
if (objname->type != FZL_NODETYPE_IDENTIFIER &&
objname->type != FZL_NODETYPE_FIELD)
{
snprintf(plast_err, sizeof(plast_err),
"'%s': expect class name after 'new' keyword at %ld:%ld",
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
return NULL;
}
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CONSTRUCT, new);
node->construct.name = objname;
return node;
}
// Assignments parsing
fzl_node_t *parse_assignment(fzl_parser_t *parser)
{
fzl_node_t *left = parse_or(parser);
fzl_node_t *left = parse_new(parser);
if (!left)
return NULL;
@@ -1090,6 +1118,15 @@ void fzl_freeast(fzl_node_t *root)
fzl_freenode(root->class.methods[i]);
free(root->class.methods);
}
else if (root->type == FZL_NODETYPE_CONSTRUCT)
{
fzl_freenode(root->construct.name);
}
else if (root->type == FZL_NODETYPE_FIELD)
{
fzl_freenode(root->memb.field);
fzl_freenode(root->memb.parent);
}
root = root->next;
free(root);