#include #include #include #include // Parse primary fzl_node_t *pa_primary(fzl_parser_t *parser) { if (!parser || !peek(parser)) return NULL; if (is(parser, FZL_TOKTYPE_STR_LITERAL) || is(parser, FZL_TOKTYPE_NUM_LITERAL) || is(parser, FZL_TOKTYPE_BOOL_LITERAL) || is(parser, FZL_TOKTYPE_NULL_LITERAL)) { fzl_token_t *tok = consume(parser); return fzl_mknode(FZL_NODETYPE_LITERAL, tok); } else if (is(parser, FZL_TOKTYPE_STR_FORMAT_START)) { consume(parser); size_t remainder = 2; size_t count = 0; fzl_node_t **entries = malloc(remainder * sizeof(fzl_node_t *)); if (!entries) { snprintf(plast_err, sizeof(plast_err), "out of memory"); return NULL; } while (peek(parser) && peek(parser)->type != FZL_TOKTYPE_STR_FORMAT_END) { if (is(parser, FZL_TOKTYPE_STR_FORMAT_END)) break; if (remainder <= count) { remainder *= 2; fzl_node_t **newentries = realloc(entries, remainder * sizeof(fzl_node_t *)); if (!newentries) { snprintf(plast_err, sizeof(plast_err), "out of memory"); for (size_t i = 0; i < count; i++) fzl_freeast(entries[i]); free(entries); return NULL; } entries = newentries; } fzl_node_t *expr = pa_expression(parser); if (expr == NULL) { for (size_t i = 0; i < count; i++) fzl_freeast(entries[i]); free(entries); return NULL; } entries[count++] = expr; } fzl_token_t *end = consume(parser); if (end->type != FZL_TOKTYPE_STR_FORMAT_END) { snprintf(plast_err, sizeof(plast_err), "'%s':%zu:%zu => unterminated format string", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); for (size_t i = 0; i < count; i++) fzl_freeast(entries[i]); free(entries); } if (count < 1) { snprintf(plast_err, sizeof(plast_err), "'%s':%zu:%zu => do you really need empty format string?", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); for (size_t i = 0; i < count; i++) fzl_freeast(entries[i]); free(entries); return NULL; } fzl_node_t *node = fzl_mknode(FZL_NODETYPE_FMT_STRING, entries[0]->token); if (!node) { snprintf(plast_err, sizeof(plast_err), "out of memory"); for (size_t i = 0; i < count; i++) fzl_freeast(entries[i]); free(entries); return NULL; } node->list.entries = entries; node->list.entry_count = count; return node; } else if (is(parser, FZL_TOKTYPE_LPAREN)) { consume(parser); fzl_node_t *node = pa_expression(parser); if (!is(parser, FZL_TOKTYPE_RPAREN)) { snprintf(plast_err, sizeof(plast_err), "'%s': expected ')' at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); fzl_freeast(node); return NULL; } consume(parser); return node; } else if (is(parser, FZL_TOKTYPE_NAME)) { fzl_token_t *name = consume(parser); if (!is(parser, FZL_TOKTYPE_NAME)) return fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); fzl_token_t *realname = consume(parser); // :D fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, name); decl->var.type = name; decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, realname); return decl; } else if (is(parser, FZL_TOKTYPE_TYPE)) { fzl_token_t *type = consume(parser); fzl_token_t *name = consume(parser); if (!name || name->type != FZL_TOKTYPE_NAME) { snprintf(plast_err, sizeof(plast_err), "'%s': expected name after type at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); return NULL; } fzl_node_t *decl = fzl_mknode(FZL_NODETYPE_DECLARATION, type); decl->var.type = type; decl->var.identifier = fzl_mknode(FZL_NODETYPE_IDENTIFIER, name); return decl; } if (!plast_err[0]) snprintf(plast_err, sizeof(plast_err), "'%s': expected expression at %ld:%ld", last_known_tok->filename, last_known_tok->ln, last_known_tok->cn); return NULL; }