#include "tokenlist.h" #include "error.h" #include "lexer.h" #include error_t *tokenlist_alloc(tokenlist_t **output) { *output = nullptr; tokenlist_t *list = calloc(1, sizeof(tokenlist_t)); if (list == nullptr) return err_allocation_failed; list->head = nullptr; list->tail = nullptr; *output = list; return nullptr; } error_t *tokenlist_entry_alloc(tokenlist_entry_t **output) { *output = nullptr; tokenlist_entry_t *entry = calloc(1, sizeof(tokenlist_entry_t)); if (entry == nullptr) return err_allocation_failed; entry->next = nullptr; entry->prev = nullptr; *output = entry; return nullptr; } void tokenlist_append(tokenlist_t *list, tokenlist_entry_t *entry) { if (list->head == nullptr) { list->head = entry; list->tail = entry; entry->next = nullptr; entry->prev = nullptr; } else { entry->prev = list->tail; entry->next = nullptr; list->tail->next = entry; list->tail = entry; } } void tokenlist_entry_free(tokenlist_entry_t *entry) { lexer_token_cleanup(&entry->token); free(entry); } void tokenlist_free(tokenlist_t *list) { if (list == nullptr) return; tokenlist_entry_t *current = list->head; while (current) { tokenlist_entry_t *next = current->next; tokenlist_entry_free(current); current = next; } free(list); } error_t *tokenlist_fill(tokenlist_t *list, lexer_t *lex) { error_t *err = nullptr; lexer_token_t token = {}; while ((err = lexer_next(lex, &token)) == nullptr) { tokenlist_entry_t *entry; err = tokenlist_entry_alloc(&entry); if (err) { lexer_token_cleanup(&token); return err; } entry->token = token; tokenlist_append(list, entry); } if (err != err_eof) return err; return nullptr; } bool is_trivia(tokenlist_entry_t *trivia) { switch (trivia->token.id) { case TOKEN_WHITESPACE: case TOKEN_COMMENT: case TOKEN_NEWLINE: return true; default: return false; } } tokenlist_entry_t *tokenlist_skip_trivia(tokenlist_entry_t *current) { while (current && is_trivia(current)) current = current->next; return current; } tokenlist_entry_t *tokenlist_next(tokenlist_entry_t *current) { if (!current) return nullptr; return tokenlist_skip_trivia(current->next); }