#include #include #include #include #include // Parse class definition fzl_node_t *pa_class(fzl_parser_t *parser) { if (!parser) return NULL; fzl_token_t *class = consume(parser); fzl_token_t *name = consume(parser); if (!name || name->type != FZL_TOKTYPE_NAME) { snprintf(plast_err, sizeof(plast_err), "'%s': expected class name at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); return NULL; } fzl_token_t *lbrace = consume(parser); if (!lbrace || lbrace->type != FZL_TOKTYPE_LBRACE) { snprintf(plast_err, sizeof(plast_err), "'%s': expected '{' after class name at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); return NULL; } size_t fremainder = 2; size_t fcount = 0; fzl_node_t **fields = malloc(fremainder * sizeof(fzl_node_t *)); if (!fields) { snprintf(plast_err, sizeof(plast_err), "failed to allocate space for class fields"); return NULL; } size_t mremainder = 2; size_t mcount = 0; fzl_node_t **methods = malloc(mremainder * sizeof(fzl_node_t *)); if (!methods) { snprintf(plast_err, sizeof(plast_err), "failed to allocate space for class fields"); free(fields); return NULL; } while (!is(parser, FZL_TOKTYPE_RBRACE)) { fzl_node_t *node = pa_statement(parser); if (!node) return NULL; if (node->type == FZL_NODETYPE_DECLARATION) { if (fremainder <= fcount) { fremainder *= 2; fields = realloc(fields, fremainder * sizeof(fzl_node_t *)); if (!fields) { snprintf(plast_err, sizeof(plast_err), "failed to resize fields array"); fzl_freeast(node); free(methods); return NULL; } } fields[fcount++] = node; } else if (node->type == FZL_NODETYPE_FUNCTION) { if (mremainder <= mcount) { mremainder *= 2; methods = realloc(methods, mremainder * sizeof(fzl_node_t *)); if (!methods) { snprintf(plast_err, sizeof(plast_err), "failed to resize methods array"); fzl_freeast(node); free(fields); return NULL; } } fzl_node_t **new_args = realloc(node->fn.args, (++node->fn.args_count) * sizeof(fzl_node_t *)); if (!new_args) { snprintf(plast_err, sizeof(plast_err), "failed to reallocate method args list"); free(fields); fzl_freeast(node); return NULL; } if (node->fn.args_count > 1) memmove(&new_args[1], new_args, (node->fn.args_count - 1) * sizeof(fzl_node_t *)); fzl_node_t *this_id = fzl_mknode(FZL_NODETYPE_IDENTIFIER, &this_tok); fzl_node_t *this_dec = fzl_mknode(FZL_NODETYPE_DECLARATION, name); this_dec->var.type = name; this_dec->var.identifier = this_id; new_args[0] = this_dec; node->fn.args = new_args; methods[mcount++] = node; } else { fzl_freeast(node); snprintf(plast_err, sizeof(plast_err), "'%s': unknown type of class member at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); free(fields); free(methods); return NULL; } } fzl_token_t *rbra = consume(parser); if (rbra->type != FZL_TOKTYPE_RBRACE) { snprintf(plast_err, sizeof(plast_err), "'%s': expected '}' after class definition at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); free(fields); free(methods); return NULL; } fzl_node_t *node = fzl_mknode(FZL_NODETYPE_CLASS, class); node->class.name = name; node->class.fields = fields; node->class.fields_count = fcount; node->class.methods = methods; node->class.methods_count = mcount; return node; }