diff options
Diffstat (limited to 'debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/lang_pawn.cpp')
-rw-r--r-- | debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/lang_pawn.cpp | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/lang_pawn.cpp b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/lang_pawn.cpp new file mode 100644 index 00000000..fe999a2a --- /dev/null +++ b/debian/uncrustify-trinity/uncrustify-trinity-0.78.1/src/lang_pawn.cpp @@ -0,0 +1,520 @@ +/** + * @file lang_pawn.cpp + * Special functions for pawn stuff + * + * @author Ben Gardner + * @license GPL v2+ + */ + +#include "lang_pawn.h" + +#include "prototypes.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 *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 *pawn_process_line(Chunk *start); + + +//! We are on a level 0 function proto of def +static Chunk *pawn_mark_function0(Chunk *start, Chunk *fcn); + + +/** + * follows a variable definition at level 0 until the end. + * Adds a semicolon at the end, if needed. + */ +static Chunk *pawn_process_variable(Chunk *start); + + +static Chunk *pawn_process_func_def(Chunk *pc); + + +Chunk *pawn_add_vsemi_after(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + if (pc->IsSemicolon()) + { + return(pc); + } + Chunk *next = pc->GetNextNc(); + + if ( next->IsNotNullChunk() + && next->IsSemicolon()) + { + return(pc); + } + Chunk chunk = *pc; + + chunk.SetType(CT_VSEMICOLON); + chunk.SetParentType(CT_NONE); + chunk.Str() = options::mod_pawn_semicolon() ? ";" : ""; + chunk.SetColumn(pc->GetColumn() + pc->Len()); + + LOG_FMT(LPVSEMI, "%s: Added VSEMI on line %zu, prev='%s' [%s]\n", + __func__, pc->GetOrigLine(), pc->Text(), + get_token_name(pc->GetType())); + + return(chunk.CopyAndAddAfter(pc)); +} + + +void pawn_scrub_vsemi() +{ + constexpr static auto LCURRENT = LPVSEMI; + + LOG_FUNC_ENTRY(); + + log_rule_B("mod_pawn_semicolon"); + + if (!options::mod_pawn_semicolon()) + { + return; + } + + for (Chunk *pc = Chunk::GetHead(); pc->IsNotNullChunk(); pc = pc->GetNext()) + { + if (pc->IsNot(CT_VSEMICOLON)) + { + continue; + } + Chunk *prev = pc->GetPrevNcNnl(); + + if (prev->Is(CT_BRACE_CLOSE)) + { + if ( prev->GetParentType() == CT_IF + || prev->GetParentType() == CT_ELSE + || prev->GetParentType() == CT_SWITCH + || prev->GetParentType() == CT_CASE + || prev->GetParentType() == CT_WHILE_OF_DO) + { + pc->Str().clear(); + } + } + } +} + + +static bool pawn_continued(Chunk *pc, size_t br_level) +{ + LOG_FUNC_ENTRY(); + + if (pc->IsNullChunk()) + { + return(false); + } + + if ( pc->GetLevel() > br_level + || pc->Is(CT_ARITH) + || pc->Is(CT_SHIFT) + || pc->Is(CT_CARET) + || pc->Is(CT_QUESTION) + || pc->Is(CT_BOOL) + || pc->Is(CT_ASSIGN) + || pc->Is(CT_COMMA) + || pc->Is(CT_COMPARE) + || pc->Is(CT_IF) + || pc->Is(CT_ELSE) + || pc->Is(CT_DO) + || pc->Is(CT_SWITCH) + || pc->Is(CT_WHILE) + || pc->Is(CT_BRACE_OPEN) + || pc->Is(CT_VBRACE_OPEN) + || pc->Is(CT_FPAREN_OPEN) + || pc->GetParentType() == CT_IF + || pc->GetParentType() == CT_ELSE + || pc->GetParentType() == CT_ELSEIF + || pc->GetParentType() == CT_DO + || pc->GetParentType() == CT_FOR + || pc->GetParentType() == CT_SWITCH + || pc->GetParentType() == CT_WHILE + || pc->GetParentType() == CT_FUNC_DEF + || pc->GetParentType() == CT_ENUM + || pc->GetFlags().test_any(PCF_IN_ENUM | PCF_IN_STRUCT) + || pc->IsString(":") + || pc->IsString("+") + || pc->IsString("-")) + { + return(true); + } + return(false); +} // pawn_continued + + +void pawn_prescan() +{ + LOG_FUNC_ENTRY(); + + /* + * Start at the beginning and step through the entire file, and clean up + * any questionable stuff + */ + bool did_nl = true; + Chunk *pc = Chunk::GetHead(); + + while (pc->IsNotNullChunk()) + { + if ( did_nl + && pc->IsNot(CT_PREPROC) + && !pc->IsNewline() + && pc->GetLevel() == 0) + { + // pc now points to the start of a line + pc = pawn_process_line(pc); + } + + // note that continued lines are ignored + if (pc->IsNotNullChunk()) + { + did_nl = (pc->Is(CT_NEWLINE)); + } + pc = pc->GetNextNc(); + } +} + + +static Chunk *pawn_process_line(Chunk *start) +{ + LOG_FUNC_ENTRY(); + + //LOG_FMT(LSYS, "%s: %d - %s\n", __func__, + // start->GetOrigLine(), start->Text()); + + if ( start->Is(CT_NEW) + || start->IsString("const")) + { + return(pawn_process_variable(start)); + } + // if a open paren is found before an assign, then this is a function + Chunk *fcn = Chunk::NullChunkPtr; + + if (start->Is(CT_WORD)) + { + fcn = start; + } + Chunk *pc = start; + + while ( ((pc = pc->GetNextNc())->IsNotNullChunk()) + && !pc->IsString("(") + && pc->IsNot(CT_ASSIGN) + && pc->IsNot(CT_NEWLINE)) + { + if ( pc->GetLevel() == 0 + && ( pc->Is(CT_FUNCTION) + || pc->Is(CT_WORD) + || pc->Is(CT_OPERATOR_VAL))) + { + fcn = pc; + } + } + + if (pc->IsNotNullChunk()) + { + if (pc->Is(CT_ASSIGN)) + { + return(pawn_process_variable(pc)); + } + } + + if (fcn->IsNotNullChunk()) + { + //LOG_FMT(LSYS, "FUNCTION: %s\n", fcn->Text()); + return(pawn_mark_function0(start, fcn)); + } + + if (start->Is(CT_ENUM)) + { + pc = start->GetNextType(CT_BRACE_CLOSE, start->GetLevel()); + return(pc); + } + //LOG_FMT(LSYS, "%s: Don't understand line %d, starting with '%s' [%s]\n", + // __func__, start->GetOrigLine(), start->Text(), get_token_name(start->GetType())); + return(start); +} // pawn_process_line + + +static Chunk *pawn_process_variable(Chunk *start) +{ + LOG_FUNC_ENTRY(); + Chunk *pc = Chunk::NullChunkPtr; + + if (start->IsNotNullChunk()) + { + pc = start; + } + Chunk *prev = Chunk::NullChunkPtr; + + while ((pc = pc->GetNextNc())->IsNotNullChunk()) + { + if ( pc->Is(CT_NEWLINE) + && prev->IsNotNullChunk() + && !pawn_continued(prev, start->GetLevel())) + { + if (!prev->IsSemicolon()) + { + pawn_add_vsemi_after(prev); + } + break; + } + prev = pc; + } + return(pc); +} + + +void pawn_add_virtual_semicolons() +{ + LOG_FUNC_ENTRY(); + + // Add Pawn virtual semicolons + if (language_is_set(LANG_PAWN)) + { + Chunk *prev = Chunk::NullChunkPtr; + Chunk *pc = Chunk::GetHead(); + + while ((pc = pc->GetNext())->IsNotNullChunk()) + { + if ( !pc->IsCommentOrNewline() + && !pc->IsVBrace()) + { + prev = pc; + } + + if ( prev->IsNullChunk() + || ( pc->IsNot(CT_NEWLINE) + && !pc->IsBraceClose())) + { + continue; + } + + // we just hit a newline and we have a previous token + if ( !prev->TestFlags(PCF_IN_PREPROC) + && !prev->GetFlags().test_any(PCF_IN_ENUM | PCF_IN_STRUCT) + && !prev->IsSemicolon() + && !pawn_continued(prev, prev->GetBraceLevel())) + { + pawn_add_vsemi_after(prev); + prev = Chunk::NullChunkPtr; + } + } + } +} // pawn_add_virtual_semicolons + + +static Chunk *pawn_mark_function0(Chunk *start, Chunk *fcn) +{ + LOG_FUNC_ENTRY(); + + // handle prototypes + if (start == fcn) + { + Chunk *last = fcn->GetNextType(CT_PAREN_CLOSE, fcn->GetLevel())->GetNext(); + + if (last->Is(CT_SEMICOLON)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' proto due to semicolon\n", + __func__, fcn->GetOrigLine(), fcn->Text()); + fcn->SetType(CT_FUNC_PROTO); + return(last); + } + } + else + { + if ( start->Is(CT_FORWARD) + || start->Is(CT_NATIVE)) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' [%s] proto due to %s\n", + __func__, fcn->GetOrigLine(), fcn->Text(), + get_token_name(fcn->GetType()), + get_token_name(start->GetType())); + fcn->SetType(CT_FUNC_PROTO); + return(fcn->GetNextNc()); + } + } + // Not a prototype, so it must be a function def + return(pawn_process_func_def(fcn)); +} + + +static Chunk *pawn_process_func_def(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + // We are on a function definition + pc->SetType(CT_FUNC_DEF); + + LOG_FMT(LPFUNC, "%s: %zu:%zu %s\n", + __func__, pc->GetOrigLine(), pc->GetOrigCol(), 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 *clp = pc->GetNextString(")", 1, 0); + Chunk *last = clp->GetNextNcNnl(); + + if (last->IsNotNullChunk()) + { + LOG_FMT(LPFUNC, "%s: %zu] last is '%s' [%s]\n", + __func__, last->GetOrigLine(), last->Text(), get_token_name(last->GetType())); + } + + // See if there is a state clause after the function + if ( last->IsNotNullChunk() + && last->IsString("<")) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' has state angle open %s\n", + __func__, pc->GetOrigLine(), pc->Text(), get_token_name(last->GetType())); + + last->SetType(CT_ANGLE_OPEN); + last->SetParentType(CT_FUNC_DEF); + + while ( ((last = last->GetNext())->IsNotNullChunk()) + && !last->IsString(">")) + { + // do nothing just search, TODO: use search_chunk + } + + if (last->IsNotNullChunk()) + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' has state angle close %s\n", + __func__, pc->GetOrigLine(), pc->Text(), get_token_name(last->GetType())); + last->SetType(CT_ANGLE_CLOSE); + last->SetParentType(CT_FUNC_DEF); + } + last = last->GetNextNcNnl(); + } + + if (last->IsNullChunk()) + { + return(last); + } + + if (last->Is(CT_BRACE_OPEN)) + { + last->SetParentType(CT_FUNC_DEF); + last = last->GetNextType(CT_BRACE_CLOSE, last->GetLevel()); + + if (last->IsNotNullChunk()) + { + last->SetParentType(CT_FUNC_DEF); + } + } + else + { + LOG_FMT(LPFUNC, "%s: %zu] '%s' fdef: expected brace open: %s\n", + __func__, pc->GetOrigLine(), pc->Text(), get_token_name(last->GetType())); + + // do not insert a vbrace before a preproc + if (last->TestFlags(PCF_IN_PREPROC)) + { + return(last); + } + Chunk chunk = *last; + chunk.Str().clear(); + chunk.SetType(CT_VBRACE_OPEN); + chunk.SetParentType(CT_FUNC_DEF); + + Chunk *prev = chunk.CopyAndAddBefore(last); + last = prev; + + // find the next newline at level 0 + prev = prev->GetNextNcNnl(); + + do + { + LOG_FMT(LPFUNC, "%s:%zu] check %s, level %zu\n", + __func__, prev->GetOrigLine(), get_token_name(prev->GetType()), prev->GetLevel()); + + if ( prev->Is(CT_NEWLINE) + && prev->GetLevel() == 0) + { + Chunk *next = prev->GetNextNcNnl(); + + if ( next->IsNotNullChunk() + && next->IsNot(CT_ELSE) + && next->IsNot(CT_WHILE_OF_DO)) + { + break; + } + } + prev->SetLevel(prev->GetLevel() + 1); + prev->SetBraceLevel(prev->GetBraceLevel() + 1); + last = prev; + } while ((prev = prev->GetNext())->IsNotNullChunk()); + + if (last->IsNotNullChunk()) + { + LOG_FMT(LPFUNC, "%s:%zu] ended on %s, level %zu\n", + __func__, last->GetOrigLine(), get_token_name(last->GetType()), last->GetLevel()); + } + chunk = *last; + chunk.Str().clear(); + chunk.SetType(CT_VBRACE_CLOSE); + chunk.SetParentType(CT_FUNC_DEF); + chunk.SetColumn(chunk.GetColumn() + last->Len()); + chunk.SetLevel(0); + chunk.SetBraceLevel(0); + last = chunk.CopyAndAddAfter(last); + } + return(last); +} // pawn_process_func_def + + +Chunk *pawn_check_vsemicolon(Chunk *pc) +{ + LOG_FUNC_ENTRY(); + + // Grab the open VBrace + Chunk *vb_open = pc->GetPrevType(CT_VBRACE_OPEN); + + /* + * 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->GetLevel() + 1) -- ie, in () or [] + * - it is something that needs a continuation + * + arith, assign, bool, comma, compare + */ + Chunk *prev = pc->GetPrevNcNnl(); + + if ( prev->IsNullChunk() + || prev == vb_open + || prev->TestFlags(PCF_IN_PREPROC) + || pawn_continued(prev, vb_open->GetLevel() + 1)) + { + if (prev->IsNotNullChunk()) + { + LOG_FMT(LPVSEMI, "%s: no VSEMI on line %zu, prev='%s' [%s]\n", + __func__, prev->GetOrigLine(), prev->Text(), get_token_name(prev->GetType())); + } + return(pc); + } + return(pawn_add_vsemi_after(prev)); +} |