blob: 01eb4b46a133af09da466e56a46af9dad04b283c [file] [log] [blame]
/**
* @file chunk_list.c
* Manages and navigates the list of chunks.
*
* @author Ben Gardner
* @license GPL v2+
*/
#ifndef CHUNK_LIST_H_INCLUDED
#define CHUNK_LIST_H_INCLUDED
#include "uncrustify_types.h"
#include "char_table.h"
/**
* Specifies how to handle proprocessors.
* CNAV_ALL (default)
* - return the true next/prev
*
* CNAV_PREPROC
* - If not in a preprocessor, skip over any encountered preprocessor stuff
* - If in a preprocessor, fail to leave (return NULL)
*/
enum chunk_nav_t
{
CNAV_ALL,
CNAV_PREPROC,
};
chunk_t *chunk_dup(const chunk_t *pc_in);
chunk_t *chunk_add(const chunk_t *pc_in);
chunk_t *chunk_add_after(const chunk_t *pc_in, chunk_t *ref);
chunk_t *chunk_add_before(const chunk_t *pc_in, chunk_t *ref);
void chunk_del(chunk_t *pc);
void chunk_move_after(chunk_t *pc_in, chunk_t *ref);
chunk_t *chunk_get_head(void);
chunk_t *chunk_get_tail(void);
chunk_t *chunk_get_next(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
void chunk_swap(chunk_t *pc1, chunk_t *pc2);
void chunk_swap_lines(chunk_t *pc1, chunk_t *pc2);
chunk_t *chunk_first_on_line(chunk_t *pc);
chunk_t *chunk_get_next_nl(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_nc(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_nnl(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_ncnl(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_ncnlnp(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_nisq(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_nblank(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_nblank(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_nl(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_nc(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_nnl(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_ncnl(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_ncnlnp(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_type(chunk_t *cur, c_token_t type, int level, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_type(chunk_t *cur, c_token_t type, int level, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_str(chunk_t *cur, const char *str, int len, int level, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_str(chunk_t *cur, const char *str, int len, int level, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_next_nvb(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
chunk_t *chunk_get_prev_nvb(chunk_t *cur, chunk_nav_t nav = CNAV_ALL);
/**
* Skips to the closing match for the current paren/brace/square.
*
* @param cur The opening or closing paren/brace/square
* @return NULL or the matching paren/brace/square
*/
static_inline
chunk_t *chunk_skip_to_match(chunk_t *cur, chunk_nav_t nav = CNAV_ALL)
{
if (cur &&
((cur->type == CT_PAREN_OPEN) ||
(cur->type == CT_SPAREN_OPEN) ||
(cur->type == CT_FPAREN_OPEN) ||
(cur->type == CT_TPAREN_OPEN) ||
(cur->type == CT_BRACE_OPEN) ||
(cur->type == CT_VBRACE_OPEN) ||
(cur->type == CT_ANGLE_OPEN) ||
(cur->type == CT_SQUARE_OPEN)))
{
return chunk_get_next_type(cur, (c_token_t)(cur->type + 1), cur->level, nav);
}
return cur;
}
static_inline
chunk_t *chunk_skip_to_match_rev(chunk_t *cur, chunk_nav_t nav = CNAV_ALL)
{
if (cur &&
((cur->type == CT_PAREN_CLOSE) ||
(cur->type == CT_SPAREN_CLOSE) ||
(cur->type == CT_FPAREN_CLOSE) ||
(cur->type == CT_TPAREN_CLOSE) ||
(cur->type == CT_BRACE_CLOSE) ||
(cur->type == CT_VBRACE_CLOSE) ||
(cur->type == CT_ANGLE_CLOSE) ||
(cur->type == CT_SQUARE_CLOSE)))
{
return chunk_get_prev_type(cur, (c_token_t)(cur->type - 1), cur->level, nav);
}
return cur;
}
static_inline
bool chunk_is_comment(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_COMMENT) ||
(pc->type == CT_COMMENT_MULTI) ||
(pc->type == CT_COMMENT_CPP)));
}
static_inline
bool chunk_is_single_line_comment(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_COMMENT) ||
(pc->type == CT_COMMENT_CPP)));
}
static_inline
bool chunk_is_newline(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_NEWLINE) ||
(pc->type == CT_NL_CONT)));
}
static_inline
bool chunk_is_semicolon(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_SEMICOLON) ||
(pc->type == CT_VSEMICOLON)));
}
static_inline
bool chunk_is_blank(chunk_t *pc)
{
return((pc != NULL) && (pc->len() == 0));
}
static_inline
bool chunk_is_preproc(chunk_t *pc)
{
return((pc != NULL) && ((pc->flags & PCF_IN_PREPROC) != 0));
}
static_inline
bool chunk_is_type(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_TYPE) ||
(pc->type == CT_PTR_TYPE) ||
(pc->type == CT_BYREF) ||
(pc->type == CT_DC_MEMBER) ||
(pc->type == CT_QUALIFIER) ||
(pc->type == CT_STRUCT) ||
(pc->type == CT_ENUM) ||
(pc->type == CT_UNION)));
}
static_inline
bool chunk_is_token(chunk_t *pc, c_token_t c_token)
{
return((pc != NULL) && (pc->type == c_token));
}
static_inline
bool chunk_is_str(chunk_t *pc, const char *str, int len)
{
return((pc != NULL) && (pc->len() == len) && (memcmp(pc->text(), str, len) == 0));
}
static_inline
bool chunk_is_str_case(chunk_t *pc, const char *str, int len)
{
return((pc != NULL) && (pc->len() == len) && (strncasecmp(pc->text(), str, len) == 0));
}
static_inline
bool chunk_is_word(chunk_t *pc)
{
return((pc != NULL) && (pc->len() >= 1) && CharTable::IsKw1(pc->str[0]));
}
static_inline
bool chunk_is_star(chunk_t *pc)
{
return((pc != NULL) && (pc->len() == 1) && (pc->str[0] == '*') && (pc->type != CT_OPERATOR_VAL));
}
static_inline
bool chunk_is_addr(chunk_t *pc)
{
return((pc != NULL) &&
((pc->type == CT_BYREF) ||
((pc->len() == 1) && (pc->str[0] == '&') && (pc->type != CT_OPERATOR_VAL))));
}
bool chunk_is_newline_between(chunk_t *start, chunk_t *end);
static_inline
bool chunk_is_closing_brace(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_BRACE_CLOSE) ||
(pc->type == CT_VBRACE_CLOSE)));
}
static_inline
bool chunk_is_opening_brace(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_BRACE_OPEN) ||
(pc->type == CT_VBRACE_OPEN)));
}
static_inline
bool chunk_is_vbrace(chunk_t *pc)
{
return((pc != NULL) && ((pc->type == CT_VBRACE_CLOSE) ||
(pc->type == CT_VBRACE_OPEN)));
}
static_inline
bool chunk_is_paren_open(chunk_t *pc)
{
return((pc != NULL) &&
((pc->type == CT_PAREN_OPEN) ||
(pc->type == CT_SPAREN_OPEN) ||
(pc->type == CT_TPAREN_OPEN) ||
(pc->type == CT_FPAREN_OPEN)));
}
static_inline
bool chunk_is_paren_close(chunk_t *pc)
{
return((pc != NULL) &&
((pc->type == CT_PAREN_CLOSE) ||
(pc->type == CT_SPAREN_CLOSE) ||
(pc->type == CT_TPAREN_CLOSE) ||
(pc->type == CT_FPAREN_CLOSE)));
}
/**
* Returns true if either chunk is null or both have the same preproc flags.
* If this is true, you can remove a newline/nl_cont between the two.
*/
static_inline
bool chunk_same_preproc(chunk_t *pc1, chunk_t *pc2)
{
return((pc1 == NULL) || (pc2 == NULL) ||
((pc1->flags & PCF_IN_PREPROC) == (pc2->flags & PCF_IN_PREPROC)));
}
/**
* Returns true if it is safe to delete the newline token.
* The prev and next chunks must have the same PCF_IN_PREPROC flag AND
* the newline can't be after a C++ comment.
*/
static_inline
bool chunk_safe_to_del_nl(chunk_t *nl)
{
chunk_t *tmp = chunk_get_prev(nl);
if ((tmp != NULL) && (tmp->type == CT_COMMENT_CPP))
{
return(false);
}
return(chunk_same_preproc(chunk_get_prev(nl), chunk_get_next(nl)));
}
/**
* Handle for (... in ...) in Objective-C.
* Returns true if pc->prev points to a CT_FOR and we find a CT_IN before the closing parenthesis.
*/
static_inline
bool chunk_is_forin(chunk_t *pc)
{
if ((cpd.lang_flags & LANG_OC) && pc && (pc->type == CT_SPAREN_OPEN))
{
chunk_t *prev = chunk_get_prev_ncnl(pc);
if (prev->type == CT_FOR)
{
chunk_t *next = pc;
while (next && (next->type != CT_SPAREN_CLOSE) && (next->type != CT_IN))
{
next = chunk_get_next_ncnl(next);
}
if (next->type == CT_IN)
{
return true;
}
}
}
return false;
}
void set_chunk_type(chunk_t *pc, c_token_t tt);
void set_chunk_parent(chunk_t *pc, c_token_t tt);
#endif /* CHUNK_LIST_H_INCLUDED */