diff options
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.72.0/src/lang_pawn.cpp')
-rw-r--r-- | debian/uncrustify-trinity/uncrustify-trinity-0.72.0/src/lang_pawn.cpp | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.72.0/src/lang_pawn.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.72.0/src/lang_pawn.cpp new file mode 100644 index 00000000..46518688 --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.72.0/src/lang_pawn.cpp @@ -0,0 +1,519 @@ +/** + * @file lang_pawn.cpp + * Special functions for pawn stuff + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "lang_pawn.h" + +#include "chunk_list.h" +#include "ChunkStack.h" +#include "language_tools.h" +#include "prototypes.h" +#include "uncrustify.h" +#include "uncrustify_types.h" + +using namespace uncrustify; + + +/** + * Checks to see if a token continues a statement to the next line. + * We need to check for 'open' braces/paren/etc because the level doesn't + * change until the token after the open. + */ +static bool pawn_continued(chunk_t *pc, size_t br_level); + + +/** + * Functions prototypes and definitions can only appear in level 0. + * + * Function prototypes start with "native", "forward", or are just a function + * with a trailing semicolon instead of a open brace (or something else) + * + * somefunc(params) <-- def + * stock somefunc(params) <-- def + * somefunc(params); <-- proto + * forward somefunc(params) <-- proto + * native somefunc[rect](params) <-- proto + * + * Functions start with 'stock', 'static', 'public', or '@' (on level 0) + * + * Variable definitions start with 'stock', 'static', 'new', or 'public'. + */ +static chunk_t *pawn_process_line(chunk_t *start); + + +//! We are on a level 0 function proto of def +static chunk_t *pawn_mark_function0(chunk_t *start, chunk_t *fcn); + + +/** + * follows a variable definition at level 0 until the end. + * Adds a semicolon at the end, if needed. + */ +static chunk_t *pawn_process_variable(chunk_t *start); + + +static chunk_t *pawn_process_func_def(chunk_t *pc); + + +chunk_t *pawn_add_vsemi_after(chunk_t *pc) +{ + LOG_FUNC_ENTRY(); + + if (chunk_is_token(pc, CT_VSEMICOLON) || chunk_is_token(pc, CT_SEMICOLON)) + { + return(pc); + } + chunk_t *next = chunk_get_next_nc(pc); + + if ( next != nullptr + && (chunk_is_token(next, CT_VSEMICOLON) || chunk_is_token(next, CT_SEMICOLON))) + { + return(pc); + } + chunk_t chunk = *pc; + + set_chunk_type(&chunk, CT_VSEMICOLON); + set_chunk_parent(&chunk, CT_NONE); + chunk.str = options::mod_pawn_semicolon() ? ";" : ""; + chunk.column += pc->len(); + + LOG_FMT(LPVSEMI, "%s: Added VSEMI on line %zu, prev='%s' [%s]\n", + __func__, pc->orig_line, pc->text(), + get_token_name(pc->type)); + + return(chunk_add_after(&chunk, pc)); +} + + +void pawn_scrub_vsemi(void) +{ + LOG_FUNC_ENTRY(); + + log_rule_B("mod_pawn_semicolon"); + + if (!options::mod_pawn_semicolon()) + { + return; + } + + for (chunk_t *pc = chunk_get_head(); pc != nullptr; pc = chunk_get_next(pc)) + { + if (pc->type != CT_VSEMICOLON) + { + continue; + } + chunk_t *prev = chunk_get_prev_ncnl(pc); + + if (chunk_is_token(prev, CT_BRACE_CLOSE)) + { + if ( get_chunk_parent_type(prev) == CT_IF + || get_chunk_parent_type(prev) == CT_ELSE + || get_chunk_parent_type(prev) == CT_SWITCH + || get_chunk_parent_type(prev) == CT_CASE + || get_chunk_parent_type(prev) == CT_WHILE_OF_DO) + { + pc->str.clear(); + } + } + } +} + + +static bool pawn_continued(chunk_t *pc, size_t br_level) +{ + LOG_FUNC_ENTRY(); + + if (pc == nullptr) + { + return(false); + } + + if ( pc->level > br_level + || chunk_is_token(pc, CT_ARITH) + || chunk_is_token(pc, CT_SHIFT) + || chunk_is_token(pc, CT_CARET) + || chunk_is_token(pc, CT_QUESTION) + || chunk_is_token(pc, CT_BOOL) + || chunk_is_token(pc, CT_ASSIGN) + || chunk_is_token(pc, CT_COMMA) + || chunk_is_token(pc, CT_COMPARE) + || chunk_is_token(pc, CT_IF) + || chunk_is_token(pc, CT_ELSE) + || chunk_is_token(pc, CT_DO) + || chunk_is_token(pc, CT_SWITCH) + || chunk_is_token(pc, CT_WHILE) + || chunk_is_token(pc, CT_BRACE_OPEN) + || chunk_is_token(pc, CT_VBRACE_OPEN) + || chunk_is_token(pc, CT_FPAREN_OPEN) + || get_chunk_parent_type(pc) == CT_IF + || get_chunk_parent_type(pc) == CT_ELSE + || get_chunk_parent_type(pc) == CT_ELSEIF + || get_chunk_parent_type(pc) == CT_DO + || get_chunk_parent_type(pc) == CT_FOR + || get_chunk_parent_type(pc) == CT_SWITCH + || get_chunk_parent_type(pc) == CT_WHILE + || get_chunk_parent_type(pc) == CT_FUNC_DEF + || get_chunk_parent_type(pc) == CT_ENUM + || pc->flags.test_any(PCF_IN_ENUM | PCF_IN_STRUCT) + || chunk_is_str(pc, ":", 1) + || chunk_is_str(pc, "+", 1) + || chunk_is_str(pc, "-", 1)) + { + return(true); + } + return(false); +} // pawn_continued + + +void pawn_prescan(void) +{ + LOG_FUNC_ENTRY(); + + /* + * Start at the beginning and step through the entire file, and clean up + * any questionable stuff + */ + bool did_nl = true; + chunk_t *pc = chunk_get_head(); + + while (pc != nullptr) + { + if ( did_nl + && pc->type != CT_PREPROC + && !chunk_is_newline(pc) + && pc->level == 0) + { + // pc now points to the start of a line + pc = pawn_process_line(pc); + } + + // note that continued lines are ignored + if (pc != nullptr) + { + did_nl = (chunk_is_token(pc, CT_NEWLINE)); + } + pc = chunk_get_next_nc(pc); + } +} + + +static chunk_t *pawn_process_line(chunk_t *start) +{ + LOG_FUNC_ENTRY(); + + //LOG_FMT(LSYS, "%s: %d - %s\n", __func__, + // start->orig_line, start->text()); + + if (chunk_is_token(start, CT_NEW) || chunk_is_str(start, "const", 5)) + { + return(pawn_process_variable(start)); + } + // if a open paren is found before an assign, then this is a function + chunk_t *fcn = nullptr; + + if (chunk_is_token(start, CT_WORD)) + { + fcn = start; + } + chunk_t *pc = start; + + while ( ((pc = chunk_get_next_nc(pc)) != nullptr) + && !chunk_is_str(pc, "(", 1) + && pc->type != CT_ASSIGN + && pc->type != CT_NEWLINE) + { + if ( pc->level == 0 + && ( chunk_is_token(pc, CT_FUNCTION) + || chunk_is_token(pc, CT_WORD) + || chunk_is_token(pc, CT_OPERATOR_VAL))) + { + fcn = pc; + } + } + + if (pc != nullptr) + { + if (chunk_is_token(pc, CT_ASSIGN)) + { + return(pawn_process_variable(pc)); + } + } + + if (fcn != nullptr) + { + //LOG_FMT(LSYS, "FUNCTION: %s\n", fcn->text()); + return(pawn_mark_function0(start, fcn)); + } + + if (chunk_is_token(start, CT_ENUM)) + { + pc = chunk_get_next_type(start, CT_BRACE_CLOSE, start->level); + return(pc); + } + //LOG_FMT(LSYS, "%s: Don't understand line %d, starting with '%s' [%s]\n", + // __func__, start->orig_line, start->text(), get_token_name(start->type)); + return(start); +} // pawn_process_line + + +static chunk_t *pawn_process_variable(chunk_t *start) +{ + LOG_FUNC_ENTRY(); + chunk_t *prev = nullptr; + chunk_t *pc = start; + + while ((pc = chunk_get_next_nc(pc)) != nullptr) + { + if ( chunk_is_token(pc, CT_NEWLINE) + && prev != nullptr // Issue 2586 + && !pawn_continued(prev, start->level)) + { + if (prev->type != CT_VSEMICOLON && prev->type != CT_SEMICOLON) + { + pawn_add_vsemi_after(prev); + } + break; + } + prev = pc; + } + return(pc); +} + + +void pawn_add_virtual_semicolons(void) +{ + LOG_FUNC_ENTRY(); + + // Add Pawn virtual semicolons + if (language_is_set(LANG_PAWN)) + { + chunk_t *prev = nullptr; + chunk_t *pc = chunk_get_head(); + + while ((pc = chunk_get_next(pc)) != nullptr) + { + if ( !chunk_is_comment(pc) + && !chunk_is_newline(pc) + && pc->type != CT_VBRACE_CLOSE + && pc->type != CT_VBRACE_OPEN) + { + prev = pc; + } + + if ( prev == nullptr + || ( pc->type != CT_NEWLINE + && pc->type != CT_BRACE_CLOSE + && pc->type != CT_VBRACE_CLOSE)) + { + continue; + } + + // we just hit a newline and we have a previous token + if ( !prev->flags.test(PCF_IN_PREPROC) + && !prev->flags.test_any(PCF_IN_ENUM | PCF_IN_STRUCT) + && prev->type != CT_VSEMICOLON + && prev->type != CT_SEMICOLON + && !pawn_continued(prev, prev->brace_level)) + { + pawn_add_vsemi_after(prev); + prev = nullptr; + } + } + } +} + + +static chunk_t *pawn_mark_function0(chunk_t *start, chunk_t *fcn) +{ + LOG_FUNC_ENTRY(); + + // handle prototypes + if (start == fcn) + { + chunk_t *last = chunk_get_next_type(fcn, CT_PAREN_CLOSE, fcn->level); + last = chunk_get_next(last); + + if (chunk_is_token(last, CT_SEMICOLON)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' proto due to semicolon\n", + __func__, fcn->orig_line, fcn->text()); + set_chunk_type(fcn, CT_FUNC_PROTO); + return(last); + } + } + else + { + if (chunk_is_token(start, CT_FORWARD) || chunk_is_token(start, CT_NATIVE)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' [%s] proto due to %s\n", + __func__, fcn->orig_line, fcn->text(), + get_token_name(fcn->type), + get_token_name(start->type)); + set_chunk_type(fcn, CT_FUNC_PROTO); + return(chunk_get_next_nc(fcn)); + } + } + // Not a prototype, so it must be a function def + return(pawn_process_func_def(fcn)); +} + + +static chunk_t *pawn_process_func_def(chunk_t *pc) +{ + LOG_FUNC_ENTRY(); + + // We are on a function definition + set_chunk_type(pc, CT_FUNC_DEF); + + LOG_FMT(LPFUNC, "%s: %zu:%zu %s\n", + __func__, pc->orig_line, pc->orig_col, pc->text()); + + /* + * If we don't have a brace open right after the close fparen, then + * we need to add virtual braces around the function body. + */ + chunk_t *clp = chunk_get_next_str(pc, ")", 1, 0); + chunk_t *last = chunk_get_next_ncnl(clp); + + if (last != nullptr) + { + LOG_FMT(LPFUNC, "%s: %zu] last is '%s' [%s]\n", + __func__, last->orig_line, last->text(), get_token_name(last->type)); + } + + // See if there is a state clause after the function + if (last != nullptr && chunk_is_str(last, "<", 1)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' has state angle open %s\n", + __func__, pc->orig_line, pc->text(), get_token_name(last->type)); + + set_chunk_type(last, CT_ANGLE_OPEN); + set_chunk_parent(last, CT_FUNC_DEF); + + while ( ((last = chunk_get_next(last)) != nullptr) + && !chunk_is_str(last, ">", 1)) + { + // do nothing just search, TODO: use search_chunk + } + + if (last != nullptr) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' has state angle close %s\n", + __func__, pc->orig_line, pc->text(), get_token_name(last->type)); + set_chunk_type(last, CT_ANGLE_CLOSE); + set_chunk_parent(last, CT_FUNC_DEF); + } + last = chunk_get_next_ncnl(last); + } + + if (last == nullptr) + { + return(last); + } + + if (chunk_is_token(last, CT_BRACE_OPEN)) + { + set_chunk_parent(last, CT_FUNC_DEF); + last = chunk_get_next_type(last, CT_BRACE_CLOSE, last->level); + + if (last != nullptr) + { + set_chunk_parent(last, CT_FUNC_DEF); + } + } + else + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' fdef: expected brace open: %s\n", + __func__, pc->orig_line, pc->text(), get_token_name(last->type)); + + // do not insert a vbrace before a preproc + if (last->flags.test(PCF_IN_PREPROC)) + { + return(last); + } + chunk_t chunk = *last; + chunk.str.clear(); + set_chunk_type(&chunk, CT_VBRACE_OPEN); + set_chunk_parent(&chunk, CT_FUNC_DEF); + + chunk_t *prev = chunk_add_before(&chunk, last); + last = prev; + + // find the next newline at level 0 + prev = chunk_get_next_ncnl(prev); + + do + { + LOG_FMT(LPFUNC, "%s:%zu] check %s, level %zu\n", + __func__, prev->orig_line, get_token_name(prev->type), prev->level); + + if (chunk_is_token(prev, CT_NEWLINE) && prev->level == 0) + { + chunk_t *next = chunk_get_next_ncnl(prev); + + if ( next != nullptr + && next->type != CT_ELSE + && next->type != CT_WHILE_OF_DO) + { + break; + } + } + prev->level++; + prev->brace_level++; + last = prev; + } while ((prev = chunk_get_next(prev)) != nullptr); + + if (last != nullptr) + { + LOG_FMT(LPFUNC, "%s:%zu] ended on %s, level %zu\n", + __func__, last->orig_line, get_token_name(last->type), last->level); + } + chunk = *last; + chunk.str.clear(); + set_chunk_type(&chunk, CT_VBRACE_CLOSE); + set_chunk_parent(&chunk, CT_FUNC_DEF); + chunk.column += last->len(); + chunk.level = 0; + chunk.brace_level = 0; + last = chunk_add_after(&chunk, last); + } + return(last); +} // pawn_process_func_def + + +chunk_t *pawn_check_vsemicolon(chunk_t *pc) +{ + LOG_FUNC_ENTRY(); + + // Grab the open VBrace + chunk_t *vb_open = chunk_get_prev_type(pc, CT_VBRACE_OPEN, -1); + + /* + * Grab the item before the newline + * Don't do anything if: + * - the only thing previous is the V-Brace open + * - in a preprocessor + * - level > (vb_open->level + 1) -- ie, in () or [] + * - it is something that needs a continuation + * + arith, assign, bool, comma, compare + */ + chunk_t *prev = chunk_get_prev_ncnl(pc); + + if ( prev == nullptr + || prev == vb_open + || prev->flags.test(PCF_IN_PREPROC) + || pawn_continued(prev, vb_open->level + 1)) + { + if (prev != nullptr) + { + LOG_FMT(LPVSEMI, "%s: no VSEMI on line %zu, prev='%s' [%s]\n", + __func__, prev->orig_line, prev->text(), get_token_name(prev->type)); + } + return(pc); + } + return(pawn_add_vsemi_after(prev)); +} |