예제 #1
0
static void append_tag_name(unc_text &txt, chunk_t *pc)
{
   LOG_FUNC_ENTRY();
   chunk_t *tmp = pc;

   /* step backwards over all a::b stuff */
   while ((tmp = chunk_get_prev_ncnl(tmp)) != NULL)
   {
      if ((tmp->type != CT_DC_MEMBER) && (tmp->type != CT_MEMBER))
      {
         break;
      }
      tmp = chunk_get_prev_ncnl(tmp);
      pc  = tmp;
      if (!chunk_is_word(tmp))
      {
         break;
      }
   }

   txt += pc->str;
   while ((pc = chunk_get_next_ncnl(pc)) != NULL)
   {
      if ((pc->type != CT_DC_MEMBER) && (pc->type != CT_MEMBER))
      {
         break;
      }
      txt += pc->str;
      pc   = chunk_get_next_ncnl(pc);
      if (pc)
      {
         txt += pc->str;
      }
   }
}
예제 #2
0
static void mod_case_brace(void)
{
   LOG_FUNC_ENTRY();

   chunk_t *pc = chunk_get_head();
   while (pc != NULL)
   {
      chunk_t *next = chunk_get_next_ncnl(pc, CNAV_PREPROC);
      if (next == NULL)
      {
         return;
      }

      if ((cpd.settings[UO_mod_case_brace].a == AV_REMOVE) &&
          (pc->type == CT_BRACE_OPEN) &&
          (pc->parent_type == CT_CASE))
      {
         pc = mod_case_brace_remove(pc);
      }
      else if ((cpd.settings[UO_mod_case_brace].a & AV_ADD) &&
               (pc->type == CT_CASE_COLON) &&
               (next->type != CT_BRACE_OPEN) &&
               (next->type != CT_BRACE_CLOSE) &&
               (next->type != CT_CASE))
      {
         pc = mod_case_brace_add(pc);
      }
      else
      {
         pc = chunk_get_next_ncnl(pc, CNAV_PREPROC);
      }
   }
}
예제 #3
0
/**
 * Remove the case brace, if allowable.
 */
static chunk_t *mod_case_brace_remove(chunk_t *br_open)
{
   LOG_FUNC_ENTRY();
   chunk_t *pc;
   chunk_t *br_close;
   chunk_t *next = chunk_get_next_ncnl(br_open, CNAV_PREPROC);

   LOG_FMT(LMCB, "%s: line %lu", __func__, br_open->orig_line);

   /* Find the matching brace close */
   br_close = chunk_get_next_type(br_open, CT_BRACE_CLOSE, br_open->level, CNAV_PREPROC);
   if (br_close == NULL)
   {
      LOG_FMT(LMCB, " - no close\n");
      return(next);
   }

   /* Make sure 'break', 'return', 'goto', 'case' or '}' is after the close brace */
   pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC);
   if ((pc == NULL) ||
       ((pc->type != CT_BREAK) &&
        (pc->type != CT_RETURN) &&
        (pc->type != CT_CASE) &&
        (pc->type != CT_GOTO) &&
        (pc->type != CT_BRACE_CLOSE)))
   {
      LOG_FMT(LMCB, " - after '%s'\n",
              (pc == NULL) ? "<null>" : get_token_name(pc->type));
      return(next);
   }

   /* scan to make sure there are no definitions at brace level between braces */
   for (pc = br_open; pc != br_close; pc = chunk_get_next_ncnl(pc, CNAV_PREPROC))
   {
      if ((pc->level == (br_open->level + 1)) && (pc->flags & PCF_VAR_DEF))
      {
         LOG_FMT(LMCB, " - vardef on line %lu: '%s'\n", pc->orig_line, pc->text());
         return(next);
      }
   }
   LOG_FMT(LMCB, " - removing braces on lines %lu and %lu\n",
           br_open->orig_line, br_close->orig_line);

   for (pc = br_open; pc != br_close; pc = chunk_get_next_ncnl(pc, CNAV_PREPROC))
   {
      pc->brace_level--;
      pc->level--;
   }
   next = chunk_get_prev(br_open, CNAV_PREPROC);
   chunk_del(br_open);
   chunk_del(br_close);
   return(chunk_get_next(next, CNAV_PREPROC));
} // mod_case_brace_remove
예제 #4
0
/**
 * Add an open paren after first and add a close paren before the last
 */
static void add_parens_between(chunk_t *first, chunk_t *last)
{
   chunk_t pc;
   chunk_t *first_n;
   chunk_t *last_p;
   chunk_t *tmp;

   LOG_FMT(LPARADD, "%s: line %d between %.*s [lvl=%d] and %.*s [lvl=%d]\n",
           __func__, first->orig_line,
           first->len, first->str, first->level,
           last->len, last->str, last->level);

   /* Don't do anything if we have a bad sequence, ie "&& )" */
   first_n = chunk_get_next_ncnl(first);
   if (first_n == last)
   {
      return;
   }

   memset(&pc, 0, sizeof(pc));

   pc.type        = CT_PAREN_OPEN;
   pc.str         = "(";
   pc.len         = 1;
   pc.flags       = first_n->flags & PCF_COPY_FLAGS;
   pc.level       = first_n->level;
   pc.pp_level    = first_n->pp_level;
   pc.brace_level = first_n->brace_level;

   chunk_add_before(&pc, first_n);

   last_p         = chunk_get_prev_ncnl(last, CNAV_PREPROC);
   pc.type        = CT_PAREN_CLOSE;
   pc.str         = ")";
   pc.flags       = last_p->flags & PCF_COPY_FLAGS;
   pc.level       = last_p->level;
   pc.pp_level    = last_p->pp_level;
   pc.brace_level = last_p->brace_level;

   chunk_add_after(&pc, last_p);

   for (tmp = first_n;
        tmp != last_p;
        tmp = chunk_get_next_ncnl(tmp))
   {
      tmp->level++;
   }
   last_p->level++;
}
예제 #5
0
파일: width.cpp 프로젝트: Limsik/e17
/**
 * Splits the parameters at every comma that is at the fparen level.
 *
 * @param start   the offending token
 */
static void split_fcn_params_full(chunk_t *start)
{
   LOG_FMT(LSPLIT, "%s", __func__);

   chunk_t *fpo;
   chunk_t *pc;

   /* Find the opening fparen */
   fpo = start;
   while (((fpo = chunk_get_prev(fpo)) != NULL) &&
          (fpo->type != CT_FPAREN_OPEN))
   {
      /* do nothing */
   }

   /* Now break after every comma */
   pc = fpo;
   while ((pc = chunk_get_next_ncnl(pc)) != NULL)
   {
      if (pc->level <= fpo->level)
      {
         break;
      }
      if ((pc->level == (fpo->level + 1)) && (pc->type == CT_COMMA))
      {
         split_before_chunk(chunk_get_next(pc));
      }
   }
}
예제 #6
0
/**
 * Convert '>' + '>' into '>>'
 * If we only have a single '>', then change it to CT_COMPARE.
 */
static chunk_t *handle_double_angle_close(chunk_t *pc)
{
   chunk_t *next = chunk_get_next(pc);

   if (next)
   {
      if ((pc->type == CT_ANGLE_CLOSE) &&
          (next->type == CT_ANGLE_CLOSE) &&
          (pc->parent_type == CT_NONE) &&
          ((pc->orig_col_end + 1) == next->orig_col) &&
          (next->parent_type == CT_NONE))
      {
         pc->str.append('>');
         set_chunk_type(pc, CT_ARITH);
         pc->orig_col_end = next->orig_col_end;

         chunk_t *tmp = chunk_get_next_ncnl(next);
         chunk_del(next);
         next = tmp;
      }
      else
      {
         // bug #663
         set_chunk_type(pc, CT_COMPARE);
      }
   }
   return(next);
}
예제 #7
0
void do_parens(void)
{
   LOG_FUNC_ENTRY();

   if (cpd.settings[UO_mod_full_paren_if_bool].b)
   {
      chunk_t *pc = chunk_get_head();
      while ((pc = chunk_get_next_ncnl(pc)) != nullptr)
      {
         if (  pc->type != CT_SPAREN_OPEN
            || (  pc->parent_type != CT_IF
               && pc->parent_type != CT_ELSEIF
               && pc->parent_type != CT_SWITCH))
         {
            continue;
         }

         // Grab the close sparen
         chunk_t *pclose = chunk_get_next_type(pc, CT_SPAREN_CLOSE, pc->level, scope_e::PREPROC);
         if (pclose != nullptr)
         {
            check_bool_parens(pc, pclose, 0);
            pc = pclose;
         }
      }
   }
}
예제 #8
0
/**
 * Convert '>' + '>' into '>>'
 * If we only have a single '>', then change it to CT_COMPARE.
 */
static chunk_t *handle_double_angle_close(chunk_t *pc)
{
   chunk_t *next = chunk_get_next(pc);

   if (next != NULL)
   {
      if ((pc->type == CT_ANGLE_CLOSE) &&
          (next->type == CT_ANGLE_CLOSE) &&
          (pc->parent_type == CT_NONE) &&
          (memcmp(pc->str, ">>", 2) == 0) &&
          (next->parent_type == CT_NONE))
      {
         pc->len++;
         pc->type = CT_ARITH;
         pc->orig_col_end = next->orig_col_end;

         chunk_t *tmp = chunk_get_next_ncnl(next);
         chunk_del(next);
         next = tmp;
      }
      else
      {
         pc->type = CT_COMPARE;
      }
   }
   return(next);
}
예제 #9
0
static size_t preproc_start(parse_frame_t *frm, chunk_t *pc)
{
   LOG_FUNC_ENTRY();
   chunk_t *next;
   size_t  pp_level = cpd.pp_level;

   // Get the type of preprocessor and handle it
   next = chunk_get_next_ncnl(pc);
   if (next != nullptr)
   {
      cpd.in_preproc = next->type;

      // If we are in a define, push the frame stack.
      if (cpd.in_preproc == CT_PP_DEFINE)
      {
         pf_push(frm);

         // a preproc body starts a new, blank frame
         memset(frm, 0, sizeof(*frm));
         frm->level       = 1;
         frm->brace_level = 1;

         // TODO: not sure about the next 3 lines
         frm->pse_tos                 = 1;
         frm->pse[frm->pse_tos].type  = CT_PP_DEFINE;
         frm->pse[frm->pse_tos].stage = brace_stage_e::NONE;
      }
      else
      {
         // Check for #if, #else, #endif, etc
         pp_level = pf_check(frm, pc);
      }
   }
   return(pp_level);
}
예제 #10
0
void do_parens(void)
{
    LOG_FUNC_ENTRY();
    chunk_t *pc;
    chunk_t *pclose;

    if (cpd.settings[UO_mod_full_paren_if_bool].b)
    {
        pc = chunk_get_head();
        while ((pc = chunk_get_next_ncnl(pc)) != NULL)
        {
            if ((pc->type != CT_SPAREN_OPEN) ||
                    ((pc->parent_type != CT_IF) &&
                     (pc->parent_type != CT_ELSEIF) &&
                     (pc->parent_type != CT_SWITCH)))
            {
                continue;
            }

            /* Grab the close sparen */
            pclose = chunk_get_next_type(pc, CT_SPAREN_CLOSE, pc->level, CNAV_PREPROC);
            if (pclose != NULL)
            {
                check_bool_parens(pc, pclose, 0);
                pc = pclose;
            }
        }
    }
}
예제 #11
0
파일: width.cpp 프로젝트: CDanU/uncrustify
static void split_fcn_params_full(chunk_t *start)
{
   LOG_FUNC_ENTRY();
   LOG_FMT(LSPLIT, "%s(%d): %s\n", __func__, __LINE__, start->text());

   // Find the opening function parenthesis
   chunk_t *fpo = start;
   LOG_FMT(LSPLIT, "  %s(%d): Find the opening function parenthesis\n", __func__, __LINE__);
   while ((fpo = chunk_get_prev(fpo)) != nullptr)
   {
      LOG_FMT(LSPLIT, "%s(%d): %s, orig_col is %zu, level is %zu\n",
              __func__, __LINE__, fpo->text(), fpo->orig_col, fpo->level);
      if (fpo->type == CT_FPAREN_OPEN && (fpo->level == start->level - 1))
      {
         break;  // opening parenthesis found. Issue #1020
      }
   }

   // Now break after every comma
   chunk_t *pc = fpo;
   while ((pc = chunk_get_next_ncnl(pc)) != nullptr)
   {
      if (pc->level <= fpo->level)
      {
         break;
      }
      if ((pc->level == (fpo->level + 1)) && pc->type == CT_COMMA)
      {
         split_before_chunk(chunk_get_next(pc));
      }
   }
}
예제 #12
0
/**
 * Scans between two parens and adds additional parens if needed.
 * This function is recursive. If it hits another open paren, it'll call itself
 * with the new bounds.
 *
 * Adds optional parens in an IF or SWITCH conditional statement.
 *
 * This basically just checks for a CT_COMPARE that isn't surrounded by parens.
 * The edges for the compare are the open, close and any CT_BOOL tokens.
 *
 * This only handleds VERY simple patterns:
 *   (!a && b)         => (!a && b)          -- no change
 *   (a && b == 1)     => (a && (b == 1))
 *   (a == 1 || b > 2) => ((a == 1) || (b > 2))
 *
 * FIXME: we really should bail if we transition between a preprocessor and
 *        a non-preprocessor
 */
static void check_bool_parens(chunk_t *popen, chunk_t *pclose, int nest)
{
   chunk_t *pc;
   chunk_t *ref = popen;
   chunk_t *next;
   bool    hit_compare = false;

   LOG_FMT(LPARADD, "%s(%d): popen on %d, col %d, pclose on %d, col %d, level=%d\n",
           __func__, nest,
           popen->orig_line, popen->orig_col,
           pclose->orig_line, pclose->orig_col,
           popen->level);

   pc = popen;
   while (((pc = chunk_get_next_ncnl(pc)) != NULL) && (pc != pclose))
   {
      if ((pc->type == CT_BOOL) ||
          (pc->type == CT_QUESTION) ||
          (pc->type == CT_COND_COLON))
      {
         LOG_FMT(LPARADD2, " -- %s [%.*s] at line %d col %d, level %d\n",
                 get_token_name(pc->type),
                 pc->len, pc->str, pc->orig_line, pc->orig_col, pc->level);
         if (hit_compare)
         {
            hit_compare = false;
            add_parens_between(ref, pc);
         }
         ref = pc;
      }
      else if (pc->type == CT_COMPARE)
      {
         LOG_FMT(LPARADD2, " -- compare [%.*s] at line %d col %d, level %d\n",
                 pc->len, pc->str, pc->orig_line, pc->orig_col, pc->level);
         hit_compare = true;
      }
      else if (chunk_is_paren_open(pc))
      {
         next = chunk_get_next_type(pc, (c_token_t)(pc->type + 1), pc->level);
         if (next != NULL)
         {
            check_bool_parens(pc, next, nest + 1);
            pc = next;
         }
      }
      else if ((pc->type == CT_BRACE_OPEN) ||
               (pc->type == CT_SQUARE_OPEN) ||
               (pc->type == CT_ANGLE_OPEN))
      {
         /* Skip [], {}, and <> */
         pc = chunk_get_next_type(pc, (c_token_t)(pc->type + 1), pc->level);
      }
   }

   if (hit_compare && (ref != popen))
   {
      add_parens_between(ref, pclose);
   }
}
예제 #13
0
/**
 * Removes superfluous semicolons:
 *  - after brace close whose parent is IF, ELSE, SWITCH, WHILE, FOR, NAMESPACE
 *  - after another semicolon where parent is not FOR
 *  - (D) after brace close whose parent is ENUM/STRUCT/UNION
 *  - after an open brace
 *  - when not in a #DEFINE
 */
void remove_extra_semicolons(void)
{
   chunk_t *pc;
   chunk_t *next;
   chunk_t *prev;

   pc = chunk_get_head();
   while (pc != NULL)
   {
      next = chunk_get_next_ncnl(pc);

      if ((pc->type == CT_SEMICOLON) && !(pc->flags & PCF_IN_PREPROC) &&
          ((prev = chunk_get_prev_ncnl(pc)) != NULL))
      {
         LOG_FMT(LSCANSEMI, "Semi on %d:%d, prev = '%s' [%s/%s]\n",
                 pc->orig_line, pc->orig_col, prev->str.c_str(),
                 get_token_name(prev->type), get_token_name(prev->parent_type));

         if ((prev->type == CT_BRACE_CLOSE) &&
             ((prev->parent_type == CT_IF) ||
              (prev->parent_type == CT_ELSEIF) ||
              (prev->parent_type == CT_ELSE) ||
              (prev->parent_type == CT_SWITCH) ||
              (prev->parent_type == CT_WHILE) ||
              (prev->parent_type == CT_USING_STMT) ||
              (prev->parent_type == CT_FOR) ||
              (prev->parent_type == CT_FUNC_DEF) ||
              (prev->parent_type == CT_OC_MSG_DECL) ||
              (prev->parent_type == CT_FUNC_CLASS) ||
              (prev->parent_type == CT_NAMESPACE)))
         {
            remove_semicolon(pc);
         }
         else if ((prev->type == CT_BRACE_CLOSE) &&
                  (prev->parent_type == CT_NONE))
         {
            check_unknown_brace_close(pc, prev);
         }
         else if ((prev->type == CT_SEMICOLON) &&
                  (prev->parent_type != CT_FOR))
         {
            remove_semicolon(pc);
         }
         else if ((cpd.lang_flags & LANG_D) &&
                  ((prev->parent_type == CT_ENUM) ||
                   (prev->parent_type == CT_UNION) ||
                   (prev->parent_type == CT_STRUCT)))
         {
            remove_semicolon(pc);
         }
         else if (prev->type == CT_BRACE_OPEN)
         {
            remove_semicolon(pc);
         }
      }

      pc = next;
   }
}
예제 #14
0
파일: align.cpp 프로젝트: jscipione/Paladin
/**
 * Aligns an OC message
 *
 * @param so   the square open of the message
 * @param span the span value
 */
static void align_oc_msg_colon(chunk_t *so)
{
   int        span = cpd.settings[UO_align_oc_msg_colon_span].n;
   chunk_t    *pc;
   chunk_t    *tmp;
   AlignStack cas;   /* for the colons */
   AlignStack nas;   /* for the parameter tag */
   int        level;
   bool       did_line;
   int        lcnt;  /* line count with no colon for span */
   bool       has_colon;


   nas.Reset();
   nas.m_right_align = true;

   cas.Start(span);

   level = so->level;
   pc    = chunk_get_next_ncnl(so, CNAV_PREPROC);

   did_line  = false;
   has_colon = false;
   lcnt      = 0;

   while ((pc != NULL) && (pc->level > level))
   {
      if (pc->level > (level + 1))
      {
         /* do nothing */
      }
      else if (chunk_is_newline(pc))
      {
         if (!has_colon)
         {
            ++lcnt;
         }
         did_line  = false;
         has_colon = !has_colon;
      }
      else if (!did_line && (lcnt - 1 < span) && (pc->type == CT_OC_COLON))
      {
         has_colon = true;
         cas.Add(pc);
         tmp = chunk_get_prev(pc);
         if ((tmp != NULL) &&
             ((tmp->type == CT_OC_MSG_FUNC) ||
              (tmp->type == CT_OC_MSG_NAME)))
         {
            nas.Add(tmp);
         }
         did_line = true;
      }
      pc = chunk_get_next(pc, CNAV_PREPROC);
   }
   nas.End();
   cas.End();
}
예제 #15
0
static void add_parens_between(chunk_t *first, chunk_t *last)
{
   LOG_FUNC_ENTRY();

   LOG_FMT(LPARADD, "%s: line %zu between %s [lvl=%zu] and %s [lvl=%zu]\n",
           __func__, first->orig_line,
           first->text(), first->level,
           last->text(), last->level);

   // Don't do anything if we have a bad sequence, ie "&& )"
   chunk_t *first_n = chunk_get_next_ncnl(first);
   if (first_n == last)
   {
      return;
   }

   chunk_t pc;
   pc.type        = CT_PAREN_OPEN;
   pc.str         = "(";
   pc.flags       = first_n->flags & PCF_COPY_FLAGS;
   pc.level       = first_n->level;
   pc.pp_level    = first_n->pp_level;
   pc.brace_level = first_n->brace_level;

   chunk_add_before(&pc, first_n);

   chunk_t *last_p = chunk_get_prev_ncnl(last, scope_e::PREPROC);
   pc.type        = CT_PAREN_CLOSE;
   pc.str         = ")";
   pc.flags       = last_p->flags & PCF_COPY_FLAGS;
   pc.level       = last_p->level;
   pc.pp_level    = last_p->pp_level;
   pc.brace_level = last_p->brace_level;

   chunk_add_after(&pc, last_p);

   for (chunk_t *tmp = first_n;
        tmp != last_p;
        tmp = chunk_get_next_ncnl(tmp))
   {
      tmp->level++;
   }
   last_p->level++;
} // add_parens_between
예제 #16
0
static void move_case_break(void)
{
   LOG_FUNC_ENTRY();
   chunk_t *prev = NULL;

   for (chunk_t *pc = chunk_get_head(); pc != NULL; pc = chunk_get_next_ncnl(pc))
   {
      if ((pc->type == CT_BREAK) &&
          (prev != NULL) &&
          (prev->type == CT_BRACE_CLOSE) &&
          (prev->parent_type == CT_CASE))
      {
         if (chunk_is_newline(chunk_get_prev(pc)) &&
             chunk_is_newline(chunk_get_prev(prev)))
         {
            chunk_swap_lines(prev, pc);
         }
      }
      prev = pc;
   }
}
예제 #17
0
static int preproc_start(struct parse_frame *frm, chunk_t *pc)
{
    LOG_FUNC_ENTRY();
    chunk_t *next;
    int     pp_level = cpd.pp_level;

    /* Get the type of preprocessor and handle it */
    next = chunk_get_next_ncnl(pc);
    if (next != NULL)
    {
        cpd.in_preproc = next->type;

        /**
         * If we are in a define, push the frame stack.
         */
        if (cpd.in_preproc == CT_PP_DEFINE)
        {
            pf_push(frm);

            /* a preproc body starts a new, blank frame */
            memset(frm, 0, sizeof(*frm));
            frm->level       = 1;
            frm->brace_level = 1;

            /*TODO: not sure about the next 3 lines */
            frm->pse_tos                 = 1;
            frm->pse[frm->pse_tos].type  = CT_PP_DEFINE;
            frm->pse[frm->pse_tos].stage = BS_NONE;
        }
        else
        {
            /* Check for #if, #else, #endif, etc */
            pp_level = pf_check(frm, pc);
        }
    }
    return(pp_level);
}
예제 #18
0
/**
 * Handles a close paren or brace - just progress the stage, if the end
 * of the statement is hit, call close_statement()
 *
 * @param frm  The parse frame
 * @param pc   The current chunk
 * @return     true - done with this chunk, false - keep processing
 */
static bool handle_complex_close(struct parse_frame *frm, chunk_t *pc)
{
   chunk_t *next;

   if (frm->pse[frm->pse_tos].stage == BS_PAREN1)
   {
      /* PAREN1 always => BRACE2 */
      frm->pse[frm->pse_tos].stage = BS_BRACE2;
   }
   else if (frm->pse[frm->pse_tos].stage == BS_BRACE2)
   {
      /* BRACE2: IF => ELSE, anyting else => close */
      if ((frm->pse[frm->pse_tos].type == CT_IF) ||
          (frm->pse[frm->pse_tos].type == CT_ELSEIF))
      {
         frm->pse[frm->pse_tos].stage = BS_ELSE;

         /* If the next chunk isn't CT_ELSE, close the statement */
         next = chunk_get_next_ncnl(pc);
         if ((next != NULL) && (next->type != CT_ELSE))
         {
            frm->pse_tos--;
            print_stack(LBCSPOP, "-IF-HCS ", frm, pc);
            if (close_statement(frm, pc))
            {
               return(true);
            }
         }
      }
      else if ((frm->pse[frm->pse_tos].type == CT_TRY) ||
               (frm->pse[frm->pse_tos].type == CT_CATCH))
      {
         frm->pse[frm->pse_tos].stage = BS_CATCH;

         /* If the next chunk isn't CT_CATCH or CT_FINALLY, close the statement */
         next = chunk_get_next_ncnl(pc);
         if ((next != NULL) &&
             (next->type != CT_CATCH) &&
             (next->type != CT_FINALLY))
         {
            frm->pse_tos--;
            print_stack(LBCSPOP, "-TRY-HCS ", frm, pc);
            if (close_statement(frm, pc))
            {
               return(true);
            }
         }
      }
      else
      {
         LOG_FMT(LNOTE, "%s: close_statement on %s BS_BRACE2\n", __func__,
                 get_token_name(frm->pse[frm->pse_tos].type));
         frm->pse_tos--;
         print_stack(LBCSPOP, "-HCC B2 ", frm, pc);
         if (close_statement(frm, pc))
         {
            return(true);
         }
      }
   }
   else if (frm->pse[frm->pse_tos].stage == BS_BRACE_DO)
   {
      frm->pse[frm->pse_tos].stage = BS_WHILE;
   }
   else if (frm->pse[frm->pse_tos].stage == BS_WOD_PAREN)
   {
      LOG_FMT(LNOTE, "%s: close_statement on %s BS_WOD_PAREN\n", __func__,
              get_token_name(frm->pse[frm->pse_tos].type));
      frm->pse[frm->pse_tos].stage = BS_WOD_SEMI;
      print_stack(LBCSPOP, "-HCC WoDP ", frm, pc);
   }
   else if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI)
   {
      LOG_FMT(LNOTE, "%s: close_statement on %s BS_WOD_SEMI\n", __func__,
              get_token_name(frm->pse[frm->pse_tos].type));
      frm->pse_tos--;
      print_stack(LBCSPOP, "-HCC WoDS ", frm, pc);

      if (close_statement(frm, pc))
      {
         return(true);
      }
   }
   else
   {
      /* PROBLEM */
      LOG_FMT(LWARN, "%s:%d Error: TOS.type='%s' TOS.stage=%d\n",
              cpd.filename, pc->orig_line,
              get_token_name(frm->pse[frm->pse_tos].type),
              frm->pse[frm->pse_tos].stage);
      cpd.error_count++;
   }
   return(false);
}
예제 #19
0
/**
 * At the heart of this algorithm are two stacks.
 * There is the Paren Stack (PS) and the Frame stack.
 *
 * The PS (pse in the code) keeps track of braces, parens,
 * if/else/switch/do/while/etc items -- anything that is nestable.
 * Complex statements go through stages.
 * Take this simple if statement as an example:
 *   if ( x ) { x--; }
 *
 * The stack would change like so: 'token' stack afterwards
 * 'if' [IF - 1]
 * '('  [IF - 1] [PAREN OPEN]
 * 'x'  [IF - 1] [PAREN OPEN]
 * ')'  [IF - 2]       <- note that the state was incremented
 * '{'  [IF - 2] [BRACE OPEN]
 * 'x'  [IF - 2] [BRACE OPEN]
 * '--' [IF - 2] [BRACE OPEN]
 * ';'  [IF - 2] [BRACE OPEN]
 * '}'  [IF - 3]
 *                             <- lack of else kills the IF, closes statement
 *
 * Virtual braces example:
 *   if ( x ) x--; else x++;
 *
 * 'if'   [IF - 1]
 * '('    [IF - 1] [PAREN OPEN]
 * 'x'    [IF - 1] [PAREN OPEN]
 * ')'    [IF - 2]
 * 'x'    [IF - 2] [VBRACE OPEN]   <- VBrace open inserted before because '{' was not next
 * '--'   [IF - 2] [VBRACE OPEN]
 * ';'    [IF - 3]                 <- VBrace close inserted after semicolon
 * 'else' [ELSE - 0]               <- IF changed into ELSE
 * 'x'    [ELSE - 0] [VBRACE OPEN] <- lack of '{' -> VBrace
 * '++'   [ELSE - 0] [VBRACE OPEN]
 * ';'    [ELSE - 0]               <- VBrace close inserted after semicolon
 *                                 <- ELSE removed after statement close
 *
 * The pse stack is kept on a frame stack.
 * The frame stack is need for languages that support preprocessors (C, C++, C#)
 * that can arbitrarily change code flow. It also isolates #define macros so
 * that they are indented independently and do not affect the rest of the program.
 *
 * When an #if is hit, a copy of the current frame is push on the frame stack.
 * When an #else/#elif is hit, a copy of the current stack is pushed under the
 * #if frame and the original (pre-#if) frame is copied to the current frame.
 * When #endif is hit, the top frame is popped.
 * This has the following effects:
 *  - a simple #if / #endif does not affect program flow
 *  - #if / #else /#endif - continues from the #if clause
 *
 * When a #define is entered, the current frame is pushed and cleared.
 * When a #define is exited, the frame is popped.
 */
static void parse_cleanup(struct parse_frame *frm, chunk_t *pc)
{
   c_token_t parent = CT_NONE;
   chunk_t   *prev;

   LOG_FMT(LTOK, "%s:%d] %16s - tos:%d/%16s stg:%d\n",
           __func__, pc->orig_line, get_token_name(pc->type),
           frm->pse_tos, get_token_name(frm->pse[frm->pse_tos].type),
           frm->pse[frm->pse_tos].stage);

   /* Mark statement starts */
   if (((frm->stmt_count == 0) || (frm->expr_count == 0)) &&
       !chunk_is_semicolon(pc) &&
       (pc->type != CT_BRACE_CLOSE) &&
       (pc->type != CT_VBRACE_CLOSE) &&
       !chunk_is_str(pc, ")", 1) &&
       !chunk_is_str(pc, "]", 1))
   {
      pc->flags |= PCF_EXPR_START;
      pc->flags |= (frm->stmt_count == 0) ? PCF_STMT_START : 0;
      LOG_FMT(LSTMT, "%d] 1.marked %s as %s start st:%d ex:%d\n",
              pc->orig_line, pc->str.c_str(), (pc->flags &PCF_STMT_START) ? "stmt" : "expr",
              frm->stmt_count, frm->expr_count);
   }
   frm->stmt_count++;
   frm->expr_count++;

   if (frm->sparen_count > 0)
   {
      int tmp;

      pc->flags |= PCF_IN_SPAREN;

      /* Mark everything in the a for statement */
      for (tmp = frm->pse_tos - 1; tmp >= 0; tmp--)
      {
         if (frm->pse[tmp].type == CT_FOR)
         {
            pc->flags |= PCF_IN_FOR;
            break;
         }
      }

      /* Mark the parent on semicolons in for() stmts */
      if ((pc->type == CT_SEMICOLON) &&
          (frm->pse_tos > 1) &&
          (frm->pse[frm->pse_tos - 1].type == CT_FOR))
      {
         pc->parent_type = CT_FOR;
      }
   }

   /* Check the progression of complex statements */
   if (frm->pse[frm->pse_tos].stage != BS_NONE)
   {
      if (check_complex_statements(frm, pc))
      {
         return;
      }
   }

   /**
    * Check for a virtual brace statement close due to a semicolon.
    * The virtual brace will get handled the next time through.
    * The semicolon isn't handled at all.
    * TODO: may need to float VBRACE past comments until newline?
    */
   if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN)
   {
      if (chunk_is_semicolon(pc))
      {
         cpd.consumed = true;
         close_statement(frm, pc);
      }
      else if ((cpd.lang_flags & LANG_PAWN) != 0)
      {
         if (pc->type == CT_BRACE_CLOSE)
         {
            close_statement(frm, pc);
         }
      }
   }

   /* Handle close paren, vbrace, brace, and square */
   if ((pc->type == CT_PAREN_CLOSE) ||
       (pc->type == CT_BRACE_CLOSE) ||
       (pc->type == CT_VBRACE_CLOSE) ||
       (pc->type == CT_ANGLE_CLOSE) ||
       (pc->type == CT_MACRO_CLOSE) ||
       (pc->type == CT_SQUARE_CLOSE))
   {
      /* Change CT_PAREN_CLOSE into CT_SPAREN_CLOSE or CT_FPAREN_CLOSE */
      if ((pc->type == CT_PAREN_CLOSE) &&
          ((frm->pse[frm->pse_tos].type == CT_FPAREN_OPEN) ||
           (frm->pse[frm->pse_tos].type == CT_SPAREN_OPEN)))
      {
         pc->type = (c_token_t)(frm->pse[frm->pse_tos].type + 1);
         if (pc->type == CT_SPAREN_CLOSE)
         {
            frm->sparen_count--;
            pc->flags &= ~PCF_IN_SPAREN;
         }
      }

      /* Make sure the open / close match */
      if (pc->type != (frm->pse[frm->pse_tos].type + 1))
      {
         if ((frm->pse[frm->pse_tos].type != CT_NONE) &&
             (frm->pse[frm->pse_tos].type != CT_PP_DEFINE))
         {
            LOG_FMT(LWARN, "%s:%d Error: Unexpected '%s' for '%s', which was on line %d\n",
                    cpd.filename, pc->orig_line, pc->str.c_str(),
                    get_token_name(frm->pse[frm->pse_tos].pc->type),
                    frm->pse[frm->pse_tos].pc->orig_line);
            print_stack(LBCSPOP, "=Error  ", frm, pc);
            cpd.error_count++;
         }
      }
      else
      {
         cpd.consumed = true;

         /* Copy the parent, update the paren/brace levels */
         pc->parent_type = frm->pse[frm->pse_tos].parent;
         frm->level--;
         if ((pc->type == CT_BRACE_CLOSE) ||
             (pc->type == CT_VBRACE_CLOSE) ||
             (pc->type == CT_MACRO_CLOSE))
         {
            frm->brace_level--;
         }
         pc->level       = frm->level;
         pc->brace_level = frm->brace_level;

         /* Pop the entry */
         frm->pse_tos--;
         print_stack(LBCSPOP, "-Close  ", frm, pc);

         /* See if we are in a complex statement */
         if (frm->pse[frm->pse_tos].stage != BS_NONE)
         {
            handle_complex_close(frm, pc);
         }
      }
   }

   /* In this state, we expect a semicolon, but we'll also hit the closing
    * sparen, so we need to check cpd.consumed to see if the close sparen was
    * aleady handled.
    */
   if (frm->pse[frm->pse_tos].stage == BS_WOD_SEMI)
   {
      chunk_t *tmp = pc;

      if (cpd.consumed)
      {
         /* If consumed, then we are on the close sparen.
          * PAWN: Check the next chunk for a semicolon. If it isn't, then
          * add a virtual semicolon, which will get handled on the next pass.
          */
         if (cpd.lang_flags & LANG_PAWN)
         {
            tmp = chunk_get_next_ncnl(pc);

            if ((tmp->type != CT_SEMICOLON) && (tmp->type != CT_VSEMICOLON))
            {
               pawn_add_vsemi_after(pc);
            }
         }
      }
      else
      {
         /* Complain if this ISN'T a semicolon, but close out WHILE_OF_DO anyway */
         if ((pc->type == CT_SEMICOLON) || (pc->type == CT_VSEMICOLON))
         {
            cpd.consumed    = true;
            pc->parent_type = CT_WHILE_OF_DO;
         }
         else
         {
            LOG_FMT(LWARN, "%s:%d: Error: Expected a semicolon for WHILE_OF_DO, but got '%s'\n",
                    cpd.filename, pc->orig_line, get_token_name(pc->type));
            cpd.error_count++;
         }
         handle_complex_close(frm, pc);
      }
   }

   /* Get the parent type for brace and paren open */
   parent = pc->parent_type;
   if ((pc->type == CT_PAREN_OPEN) ||
       (pc->type == CT_FPAREN_OPEN) ||
       (pc->type == CT_SPAREN_OPEN) ||
       (pc->type == CT_BRACE_OPEN))
   {
      prev = chunk_get_prev_ncnl(pc);
      if (prev != NULL)
      {
         if ((pc->type == CT_PAREN_OPEN) ||
             (pc->type == CT_FPAREN_OPEN) ||
             (pc->type == CT_SPAREN_OPEN))
         {
            /* Set the parent for parens and change paren type */
            if (frm->pse[frm->pse_tos].stage != BS_NONE)
            {
               pc->type = CT_SPAREN_OPEN;
               parent   = frm->pse[frm->pse_tos].type;
               frm->sparen_count++;
            }
            else if (prev->type == CT_FUNCTION)
            {
               pc->type = CT_FPAREN_OPEN;
               parent   = CT_FUNCTION;
            }
            else
            {
               /* no need to set parent */
            }
         }
         else  /* must be CT_BRACE_OPEN */
         {
            /* Set the parent for open braces */
            if (frm->pse[frm->pse_tos].stage != BS_NONE)
            {
               parent = frm->pse[frm->pse_tos].type;
            }
            else if ((prev->type == CT_ASSIGN) && (prev->str[0] == '='))
            {
               parent = CT_ASSIGN;
            }
            else if (prev->type == CT_FPAREN_CLOSE)
            {
               parent = CT_FUNCTION;
            }
            else
            {
               /* no need to set parent */
            }
         }
      }
   }

   /**
    * Adjust the level for opens & create a stack entry
    * Note that CT_VBRACE_OPEN has already been handled.
    */
   if ((pc->type == CT_BRACE_OPEN) ||
       (pc->type == CT_PAREN_OPEN) ||
       (pc->type == CT_FPAREN_OPEN) ||
       (pc->type == CT_SPAREN_OPEN) ||
       (pc->type == CT_ANGLE_OPEN) ||
       (pc->type == CT_MACRO_OPEN) ||
       (pc->type == CT_SQUARE_OPEN))
   {
      frm->level++;
      if ((pc->type == CT_BRACE_OPEN) ||
          (pc->type == CT_MACRO_OPEN))
      {
         frm->brace_level++;
      }
      push_fmr_pse(frm, pc, BS_NONE, "+Open   ");
      frm->pse[frm->pse_tos].parent = parent;
      pc->parent_type = parent;
   }

   pattern_class patcls = get_token_pattern_class(pc->type);

   /** Create a stack entry for complex statements IF/DO/FOR/WHILE/SWITCH */
   if (patcls == PATCLS_BRACED)
   {
      push_fmr_pse(frm, pc,
                   (pc->type == CT_DO) ? BS_BRACE_DO : BS_BRACE2,
                   "+ComplexBraced");
   }
   else if (patcls == PATCLS_PBRACED)
   {
      brstage_e bs = BS_PAREN1;

      if ((pc->type == CT_WHILE) && maybe_while_of_do(pc))
      {
         pc->type = CT_WHILE_OF_DO;
         bs       = BS_WOD_PAREN;
      }
      push_fmr_pse(frm, pc, bs, "+ComplexParenBraced");
   }
   else if (patcls == PATCLS_OPBRACED)
   {
      push_fmr_pse(frm, pc, BS_OP_PAREN1, "+ComplexOpParenBraced");
   }
   else if (patcls == PATCLS_ELSE)
   {
      push_fmr_pse(frm, pc, BS_ELSEIF, "+ComplexElse");
   }

   /* Mark simple statement/expression starts
    *  - after { or }
    *  - after ';', but not if the paren stack top is a paren
    *  - after '(' that has a parent type of CT_FOR
    */
   if ((pc->type == CT_SQUARE_OPEN) ||
       ((pc->type == CT_BRACE_OPEN) && (pc->parent_type != CT_ASSIGN)) ||
       (pc->type == CT_BRACE_CLOSE) ||
       (pc->type == CT_VBRACE_CLOSE) ||
       ((pc->type == CT_SPAREN_OPEN) && (pc->parent_type == CT_FOR)) ||
       (chunk_is_semicolon(pc) &&
        (frm->pse[frm->pse_tos].type != CT_PAREN_OPEN) &&
        (frm->pse[frm->pse_tos].type != CT_FPAREN_OPEN) &&
        (frm->pse[frm->pse_tos].type != CT_SPAREN_OPEN)))
   {
      LOG_FMT(LSTMT, "%s: %d> reset1 stmt on %s\n",
              __func__, pc->orig_line, pc->str.c_str());
      frm->stmt_count = 0;
      frm->expr_count = 0;
   }

   /* Mark expression starts */
   chunk_t *tmp = chunk_get_next_ncnl(pc);
   if ((pc->type == CT_ARITH) ||
       (pc->type == CT_ASSIGN) ||
       (pc->type == CT_CASE) ||
       (pc->type == CT_COMPARE) ||
       ((pc->type == CT_STAR) && tmp && (tmp->type != CT_STAR)) ||
       (pc->type == CT_BOOL) ||
       (pc->type == CT_MINUS) ||
       (pc->type == CT_PLUS) ||
       (pc->type == CT_ANGLE_OPEN) ||
       (pc->type == CT_ANGLE_CLOSE) ||
       (pc->type == CT_RETURN) ||
       (pc->type == CT_GOTO) ||
       (pc->type == CT_CONTINUE) ||
       (pc->type == CT_PAREN_OPEN) ||
       (pc->type == CT_FPAREN_OPEN) ||
       (pc->type == CT_SPAREN_OPEN) ||
       (pc->type == CT_BRACE_OPEN) ||
       chunk_is_semicolon(pc) ||
       (pc->type == CT_COMMA) ||
       (pc->type == CT_NOT) ||
       (pc->type == CT_INV) ||
       (pc->type == CT_COLON) ||
       (pc->type == CT_QUESTION))
   {
      frm->expr_count = 0;
      LOG_FMT(LSTMT, "%s: %d> reset expr on %s\n",
              __func__, pc->orig_line, pc->str.c_str());
   }
}
예제 #20
0
void tokenize_cleanup(void)
{
   LOG_FUNC_ENTRY();

   chunk_t *pc   = chunk_get_head();
   chunk_t *prev = NULL;
   chunk_t *next;
   chunk_t *tmp;
   chunk_t *tmp2;
   bool    in_type_cast = false;

   cpd.unc_stage = US_TOKENIZE_CLEANUP;

   /* Since [] is expected to be TSQUARE for the 'operator', we need to make
    * this change in the first pass.
    */
   for (pc = chunk_get_head(); pc != NULL; pc = chunk_get_next_ncnl(pc))
   {
      if (pc->type == CT_SQUARE_OPEN)
      {
         next = chunk_get_next_ncnl(pc);
         if (chunk_is_token(next, CT_SQUARE_CLOSE))
         {
            /* Change '[' + ']' into '[]' */
            set_chunk_type(pc, CT_TSQUARE);
            pc->str = "[]";
            // bug # 664
            // The original orig_col_end of CT_SQUARE_CLOSE is stored at orig_col_end of CT_TSQUARE.
            // pc->orig_col_end += 1;
            pc->orig_col_end = next->orig_col_end;
            chunk_del(next);
         }
      }
      if ((pc->type == CT_SEMICOLON) &&
          (pc->flags & PCF_IN_PREPROC) &&
          !chunk_get_next_ncnl(pc, CNAV_PREPROC))
      {
         LOG_FMT(LNOTE, "%s:%d Detected a macro that ends with a semicolon. Possible failures if used.\n",
                 cpd.filename, pc->orig_line);
      }
   }

   /* We can handle everything else in the second pass */
   pc   = chunk_get_head();
   next = chunk_get_next_ncnl(pc);
   while ((pc != NULL) && (next != NULL))
   {
      if ((pc->type == CT_DOT) && (cpd.lang_flags & LANG_ALLC))
      {
         set_chunk_type(pc, CT_MEMBER);
      }

      if ((pc->type == CT_NULLCOND) && (cpd.lang_flags & LANG_CS))
      {
         set_chunk_type(pc, CT_MEMBER);
      }

      /* Determine the version stuff (D only) */
      if (pc->type == CT_D_VERSION)
      {
         if (next->type == CT_PAREN_OPEN)
         {
            set_chunk_type(pc, CT_D_VERSION_IF);
         }
         else
         {
            if (next->type != CT_ASSIGN)
            {
               LOG_FMT(LERR, "%s:%d %s: version: Unexpected token %s\n",
                       cpd.filename, pc->orig_line, __func__, get_token_name(next->type));
               cpd.error_count++;
            }
            set_chunk_type(pc, CT_WORD);
         }
      }

      /* Determine the scope stuff (D only) */
      if (pc->type == CT_D_SCOPE)
      {
         if (next->type == CT_PAREN_OPEN)
         {
            set_chunk_type(pc, CT_D_SCOPE_IF);
         }
         else
         {
            set_chunk_type(pc, CT_TYPE);
         }
      }

      /**
       * Change CT_BASE before CT_PAREN_OPEN to CT_WORD.
       * public myclass() : base() {
       * }
       */
      if ((pc->type == CT_BASE) && (next->type == CT_PAREN_OPEN))
      {
         set_chunk_type(pc, CT_WORD);
      }

      if ((pc->type == CT_ENUM) && (next->type == CT_CLASS))
      {
         set_chunk_type(next, CT_ENUM_CLASS);
      }

      /**
       * Change CT_WORD after CT_ENUM, CT_UNION, or CT_STRUCT to CT_TYPE
       * Change CT_WORD before CT_WORD to CT_TYPE
       */
      if (next->type == CT_WORD)
      {
         if ((pc->type == CT_ENUM) ||
             (pc->type == CT_ENUM_CLASS) ||
             (pc->type == CT_UNION) ||
             (pc->type == CT_STRUCT))
         {
            set_chunk_type(next, CT_TYPE);
         }
         if (pc->type == CT_WORD)
         {
            set_chunk_type(pc, CT_TYPE);
         }
      }

      /* change extern to qualifier if extern isn't followed by a string or
       * an open paren
       */
      if (pc->type == CT_EXTERN)
      {
         if (next->type == CT_STRING)
         {
            /* Probably 'extern "C"' */
         }
         else if (next->type == CT_PAREN_OPEN)
         {
            /* Probably 'extern (C)' */
         }
         else
         {
            /* Something else followed by a open brace */
            tmp = chunk_get_next_ncnl(next);
            if ((tmp == NULL) || (tmp->type != CT_BRACE_OPEN))
            {
               set_chunk_type(pc, CT_QUALIFIER);
            }
         }
      }

      /**
       * Change CT_STAR to CT_PTR_TYPE if preceded by CT_TYPE,
       * CT_QUALIFIER, or CT_PTR_TYPE.
       */
      if ((next->type == CT_STAR) &&
          ((pc->type == CT_TYPE) ||
           (pc->type == CT_QUALIFIER) ||
           (pc->type == CT_PTR_TYPE)))
      {
         set_chunk_type(next, CT_PTR_TYPE);
      }

      if ((pc->type == CT_TYPE_CAST) &&
          (next->type == CT_ANGLE_OPEN))
      {
         set_chunk_parent(next, CT_TYPE_CAST);
         in_type_cast = true;
      }

      /**
       * Change angle open/close to CT_COMPARE, if not a template thingy
       */
      if ((pc->type == CT_ANGLE_OPEN) && (pc->parent_type != CT_TYPE_CAST))
      {
         /* pretty much all languages except C use <> for something other than
          * comparisons.  "#include<xxx>" is handled elsewhere.
          */
         if (cpd.lang_flags & (LANG_CPP | LANG_CS | LANG_JAVA | LANG_VALA | LANG_OC))
         {
            // bug #663
            check_template(pc);
         }
         else
         {
            /* convert CT_ANGLE_OPEN to CT_COMPARE */
            set_chunk_type(pc, CT_COMPARE);
         }
      }
      if ((pc->type == CT_ANGLE_CLOSE) && (pc->parent_type != CT_TEMPLATE))
      {
         if (in_type_cast)
         {
            in_type_cast = false;
            set_chunk_parent(pc, CT_TYPE_CAST);
         }
         else
         {
            next = handle_double_angle_close(pc);
         }
      }

      if (cpd.lang_flags & LANG_D)
      {
         /* Check for the D string concat symbol '~' */
         if ((pc->type == CT_INV) &&
             ((prev->type == CT_STRING) ||
              (prev->type == CT_WORD) ||
              (next->type == CT_STRING)))
         {
            set_chunk_type(pc, CT_CONCAT);
         }

         /* Check for the D template symbol '!' (word + '!' + word or '(') */
         if ((pc->type == CT_NOT) &&
             (prev->type == CT_WORD) &&
             ((next->type == CT_PAREN_OPEN) ||
              (next->type == CT_WORD) ||
              (next->type == CT_TYPE)))
         {
            set_chunk_type(pc, CT_D_TEMPLATE);
         }

         /* handle "version(unittest) { }" vs "unittest { }" */
         if (prev && (pc->type == CT_UNITTEST) && (prev->type == CT_PAREN_OPEN))
         {
            set_chunk_type(pc, CT_WORD);
         }

         /* handle 'static if' and merge the tokens */
         if (prev && (pc->type == CT_IF) && chunk_is_str(prev, "static", 6))
         {
            /* delete PREV and merge with IF */
            pc->str.insert(0, ' ');
            pc->str.insert(0, prev->str);
            pc->orig_col  = prev->orig_col;
            pc->orig_line = prev->orig_line;
            chunk_t *to_be_deleted = prev;
            prev = chunk_get_prev_ncnl(prev);
            chunk_del(to_be_deleted);
         }
      }

      if (cpd.lang_flags & LANG_CPP)
      {
         /* Change Word before '::' into a type */
         if ((pc->type == CT_WORD) && (next->type == CT_DC_MEMBER))
         {
            set_chunk_type(pc, CT_TYPE);
         }
      }

      /* Change get/set to CT_WORD if not followed by a brace open */
      if ((pc->type == CT_GETSET) && (next->type != CT_BRACE_OPEN))
      {
         if ((next->type == CT_SEMICOLON) &&
             ((prev->type == CT_BRACE_CLOSE) ||
              (prev->type == CT_BRACE_OPEN) ||
              (prev->type == CT_SEMICOLON)))
         {
            set_chunk_type(pc, CT_GETSET_EMPTY);
            set_chunk_parent(next, CT_GETSET);
         }
         else
         {
            set_chunk_type(pc, CT_WORD);
         }
      }

      /* Interface is only a keyword in MS land if followed by 'class' or 'struct'
       * likewise, 'class' may be a member name in Java.
       */
      if ((pc->type == CT_CLASS) && !CharTable::IsKw1(next->str[0]))
      {
         set_chunk_type(pc, CT_WORD);
      }

      /* Change item after operator (>=, ==, etc) to a CT_OPERATOR_VAL
       * Usually the next item is part of the operator.
       * In a few cases the next few tokens are part of it:
       *  operator +       - common case
       *  operator >>      - need to combine '>' and '>'
       *  operator ()
       *  operator []      - already converted to TSQUARE
       *  operator new []
       *  operator delete []
       *  operator const char *
       *  operator const B&
       *  operator std::allocator<U>
       *
       * In all cases except the last, this will put the entire operator value
       * in one chunk.
       */
      if (pc->type == CT_OPERATOR)
      {
         tmp2 = chunk_get_next(next);
         /* Handle special case of () operator -- [] already handled */
         if (next->type == CT_PAREN_OPEN)
         {
            tmp = chunk_get_next(next);
            if ((tmp != NULL) && (tmp->type == CT_PAREN_CLOSE))
            {
               next->str = "()";
               set_chunk_type(next, CT_OPERATOR_VAL);
               chunk_del(tmp);
               next->orig_col_end += 1;
            }
         }
         else if ((next->type == CT_ANGLE_CLOSE) &&
                  tmp2 && (tmp2->type == CT_ANGLE_CLOSE) &&
                  (tmp2->orig_col == next->orig_col_end))
         {
            next->str.append('>');
            next->orig_col_end++;
            set_chunk_type(next, CT_OPERATOR_VAL);
            chunk_del(tmp2);
         }
         else if (next->flags & PCF_PUNCTUATOR)
         {
            set_chunk_type(next, CT_OPERATOR_VAL);
         }
         else
         {
            set_chunk_type(next, CT_TYPE);

            /* Replace next with a collection of all tokens that are part of
             * the type.
             */
            tmp2 = next;
            while ((tmp = chunk_get_next(tmp2)) != NULL)
            {
               if ((tmp->type != CT_WORD) &&
                   (tmp->type != CT_TYPE) &&
                   (tmp->type != CT_QUALIFIER) &&
                   (tmp->type != CT_STAR) &&
                   (tmp->type != CT_CARET) &&
                   (tmp->type != CT_AMP) &&
                   (tmp->type != CT_TSQUARE))
               {
                  break;
               }
               /* Change tmp into a type so that space_needed() works right */
               make_type(tmp);
               int num_sp = space_needed(tmp2, tmp);
               while (num_sp-- > 0)
               {
                  next->str.append(" ");
               }
               next->str.append(tmp->str);
               tmp2 = tmp;
            }

            while ((tmp2 = chunk_get_next(next)) != tmp)
            {
               chunk_del(tmp2);
            }

            set_chunk_type(next, CT_OPERATOR_VAL);

            next->orig_col_end = next->orig_col + next->len();
         }
         set_chunk_parent(next, CT_OPERATOR);

         LOG_FMT(LOPERATOR, "%s: %d:%d operator '%s'\n",
                 __func__, pc->orig_line, pc->orig_col, next->text());
      }

      /* Change private, public, protected into either a qualifier or label */
      if (pc->type == CT_PRIVATE)
      {
         /* Handle Qt slots - maybe should just check for a CT_WORD? */
         if (chunk_is_str(next, "slots", 5) || chunk_is_str(next, "Q_SLOTS", 7))
         {
            tmp = chunk_get_next(next);
            if ((tmp != NULL) && (tmp->type == CT_COLON))
            {
               next = tmp;
            }
         }
         if (next->type == CT_COLON)
         {
            set_chunk_type(next, CT_PRIVATE_COLON);
            if ((tmp = chunk_get_next_ncnl(next)) != NULL)
            {
               chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START);
            }
         }
         else
         {
            set_chunk_type(pc, (chunk_is_str(pc, "signals", 7) || chunk_is_str(pc, "Q_SIGNALS", 9)) ? CT_WORD : CT_QUALIFIER);
         }
      }

      /* Look for <newline> 'EXEC' 'SQL' */
      if ((chunk_is_str(pc, "EXEC", 4) && chunk_is_str(next, "SQL", 3)) ||
          ((*pc->str == '$') && (pc->type != CT_SQL_WORD)))
      {
         tmp = chunk_get_prev(pc);
         if (chunk_is_newline(tmp))
         {
            if (*pc->str == '$')
            {
               set_chunk_type(pc, CT_SQL_EXEC);
               if (pc->len() > 1)
               {
                  /* SPLIT OFF '$' */
                  chunk_t nc;

                  nc = *pc;
                  pc->str.resize(1);
                  pc->orig_col_end = pc->orig_col + 1;

                  nc.type = CT_SQL_WORD;
                  nc.str.pop_front();
                  nc.orig_col++;
                  nc.column++;
                  chunk_add_after(&nc, pc);

                  next = chunk_get_next(pc);
               }
            }
            tmp = chunk_get_next(next);
            if (chunk_is_str_case(tmp, "BEGIN", 5))
            {
               set_chunk_type(pc, CT_SQL_BEGIN);
            }
            else if (chunk_is_str_case(tmp, "END", 3))
            {
               set_chunk_type(pc, CT_SQL_END);
            }
            else
            {
               set_chunk_type(pc, CT_SQL_EXEC);
            }

            /* Change words into CT_SQL_WORD until CT_SEMICOLON */
            while (tmp != NULL)
            {
               if (tmp->type == CT_SEMICOLON)
               {
                  break;
               }
               if ((tmp->len() > 0) && (unc_isalpha(*tmp->str) || (*tmp->str == '$')))
               {
                  set_chunk_type(tmp, CT_SQL_WORD);
               }
               tmp = chunk_get_next_ncnl(tmp);
            }
         }
      }

      /* handle MS abomination 'for each' */
      if ((pc->type == CT_FOR) && chunk_is_str(next, "each", 4) &&
          (next == chunk_get_next(pc)))
      {
         /* merge the two with a space between */
         pc->str.append(' ');
         pc->str         += next->str;
         pc->orig_col_end = next->orig_col_end;
         chunk_del(next);
         next = chunk_get_next_ncnl(pc);
         /* label the 'in' */
         if (next && (next->type == CT_PAREN_OPEN))
         {
            tmp = chunk_get_next_ncnl(next);
            while (tmp && (tmp->type != CT_PAREN_CLOSE))
            {
               if (chunk_is_str(tmp, "in", 2))
               {
                  set_chunk_type(tmp, CT_IN);
                  break;
               }
               tmp = chunk_get_next_ncnl(tmp);
            }
         }
      }

      /* ObjectiveC allows keywords to be used as identifiers in some situations
       * This is a dirty hack to allow some of the more common situations.
       */
      if (cpd.lang_flags & LANG_OC)
      {
         if (((pc->type == CT_IF) ||
              (pc->type == CT_FOR) ||
              (pc->type == CT_WHILE)) &&
             !chunk_is_token(next, CT_PAREN_OPEN))
         {
            set_chunk_type(pc, CT_WORD);
         }
         if ((pc->type == CT_DO) &&
             (chunk_is_token(prev, CT_MINUS) ||
              chunk_is_token(next, CT_SQUARE_CLOSE)))
         {
            set_chunk_type(pc, CT_WORD);
         }
      }

      /* Another hack to clean up more keyword abuse */
      if ((pc->type == CT_CLASS) &&
          (chunk_is_token(prev, CT_DOT) ||
           chunk_is_token(next, CT_DOT)))
      {
         set_chunk_type(pc, CT_WORD);
      }

      /* Detect Objective C class name */
      if ((pc->type == CT_OC_IMPL) ||
          (pc->type == CT_OC_INTF) ||
          (pc->type == CT_OC_PROTOCOL))
      {
         if (next->type != CT_PAREN_OPEN)
         {
            set_chunk_type(next, CT_OC_CLASS);
         }
         set_chunk_parent(next, pc->type);

         tmp = chunk_get_next_ncnl(next);
         if (tmp != NULL)
         {
            chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START);
         }

         tmp = chunk_get_next_type(pc, CT_OC_END, pc->level);
         if (tmp != NULL)
         {
            set_chunk_parent(tmp, pc->type);
         }
      }

      if (pc->type == CT_OC_INTF)
      {
         tmp = chunk_get_next_ncnl(pc, CNAV_PREPROC);
         while ((tmp != NULL) && (tmp->type != CT_OC_END))
         {
            if (get_token_pattern_class(tmp->type) != PATCLS_NONE)
            {
               LOG_FMT(LOBJCWORD, "@interface %d:%d change '%s' (%s) to CT_WORD\n",
                       pc->orig_line, pc->orig_col, tmp->text(),
                       get_token_name(tmp->type));
               set_chunk_type(tmp, CT_WORD);
            }
            tmp = chunk_get_next_ncnl(tmp, CNAV_PREPROC);
         }
      }

      /* Detect Objective-C categories and class extensions */
      /* @interface ClassName (CategoryName) */
      /* @implementation ClassName (CategoryName) */
      /* @interface ClassName () */
      /* @implementation ClassName () */
      if (((pc->parent_type == CT_OC_IMPL) ||
           (pc->parent_type == CT_OC_INTF) ||
           (pc->type == CT_OC_CLASS)) &&
          (next->type == CT_PAREN_OPEN))
      {
         set_chunk_parent(next, pc->parent_type);

         tmp = chunk_get_next(next);
         if ((tmp != NULL) && (tmp->next != NULL))
         {
            if (tmp->type == CT_PAREN_CLOSE)
            {
               //set_chunk_type(tmp, CT_OC_CLASS_EXT);
               set_chunk_parent(tmp, pc->parent_type);
            }
            else
            {
               set_chunk_type(tmp, CT_OC_CATEGORY);
               set_chunk_parent(tmp, pc->parent_type);
            }
         }

         tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level);
         if (tmp != NULL)
         {
            set_chunk_parent(tmp, pc->parent_type);
         }
      }

      /* Detect Objective C @property
       *  @property NSString *stringProperty;
       *  @property(nonatomic, retain) NSMutableDictionary *shareWith;
       */
      if (pc->type == CT_OC_PROPERTY)
      {
         if (next->type != CT_PAREN_OPEN)
         {
            chunk_flags_set(next, PCF_STMT_START | PCF_EXPR_START);
         }
         else
         {
            set_chunk_parent(next, pc->type);

            tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level);
            if (tmp != NULL)
            {
               set_chunk_parent(tmp, pc->type);
               tmp = chunk_get_next_ncnl(tmp);
               if (tmp != NULL)
               {
                  chunk_flags_set(tmp, PCF_STMT_START | PCF_EXPR_START);

                  tmp = chunk_get_next_type(tmp, CT_SEMICOLON, pc->level);
                  if (tmp != NULL)
                  {
                     set_chunk_parent(tmp, pc->type);
                  }
               }
            }
         }
      }

      /* Detect Objective C @selector
       *  @selector(msgNameWithNoArg)
       *  @selector(msgNameWith1Arg:)
       *  @selector(msgNameWith2Args:arg2Name:)
       */
      if ((pc->type == CT_OC_SEL) && (next->type == CT_PAREN_OPEN))
      {
         set_chunk_parent(next, pc->type);

         tmp = chunk_get_next(next);
         if (tmp != NULL)
         {
            set_chunk_type(tmp, CT_OC_SEL_NAME);
            set_chunk_parent(tmp, pc->type);

            while ((tmp = chunk_get_next_ncnl(tmp)) != NULL)
            {
               if (tmp->type == CT_PAREN_CLOSE)
               {
                  set_chunk_parent(tmp, CT_OC_SEL);
                  break;
               }
               set_chunk_type(tmp, CT_OC_SEL_NAME);
               set_chunk_parent(tmp, pc->type);
            }
         }
      }

      /* Handle special preprocessor junk */
      if (pc->type == CT_PREPROC)
      {
         set_chunk_parent(pc, next->type);
      }

      /* Detect "pragma region" and "pragma endregion" */
      if ((pc->type == CT_PP_PRAGMA) && (next->type == CT_PREPROC_BODY))
      {
         if ((memcmp(next->str, "region", 6) == 0) ||
             (memcmp(next->str, "endregion", 9) == 0))
         {
            set_chunk_type(pc, (*next->str == 'r') ? CT_PP_REGION : CT_PP_ENDREGION);

            set_chunk_parent(prev, pc->type);
         }
      }

      /* Check for C# nullable types '?' is in next */
      if ((cpd.lang_flags & LANG_CS) &&
          (next->type == CT_QUESTION) &&
          (next->orig_col == (pc->orig_col + pc->len())))
      {
         tmp = chunk_get_next_ncnl(next);
         if (tmp != NULL)
         {
            bool doit = ((tmp->type == CT_PAREN_CLOSE) ||
                         (tmp->type == CT_ANGLE_CLOSE));

            if (tmp->type == CT_WORD)
            {
               tmp2 = chunk_get_next_ncnl(tmp);
               if ((tmp2 != NULL) &&
                   ((tmp2->type == CT_SEMICOLON) ||
                    (tmp2->type == CT_ASSIGN) ||
                    (tmp2->type == CT_COMMA) ||
                    (tmp2->type == CT_BRACE_OPEN)))
               {
                  doit = true;
               }
            }

            if (doit)
            {
               pc->str         += next->str;
               pc->orig_col_end = next->orig_col_end;
               chunk_del(next);
               next = tmp;
            }
         }
      }

      /* Change 'default(' into a sizeof-like statement */
      if ((cpd.lang_flags & LANG_CS) &&
          (pc->type == CT_DEFAULT) &&
          (next->type == CT_PAREN_OPEN))
      {
         set_chunk_type(pc, CT_SIZEOF);
      }

      if ((pc->type == CT_UNSAFE) && (next->type != CT_BRACE_OPEN))
      {
         set_chunk_type(pc, CT_QUALIFIER);
      }

      if (((pc->type == CT_USING) ||
           ((pc->type == CT_TRY) && (cpd.lang_flags & LANG_JAVA))) &&
          (next->type == CT_PAREN_OPEN))
      {
         set_chunk_type(pc, CT_USING_STMT);
      }

      /* Add minimal support for C++0x rvalue references */
      if ((pc->type == CT_BOOL) && chunk_is_str(pc, "&&", 2))
      {
         if (prev->type == CT_TYPE)
         {
            set_chunk_type(pc, CT_BYREF);
         }
      }

      /* HACK: treat try followed by a colon as a qualifier to handle this:
       *   A::A(int) try : B() { } catch (...) { }
       */
      if ((pc->type == CT_TRY) && chunk_is_str(pc, "try", 3) &&
          (next != NULL) && (next->type == CT_COLON))
      {
         set_chunk_type(pc, CT_QUALIFIER);
      }

      /* If Java's 'synchronized' is in a method declaration, it should be
       * a qualifier. */
      if ((cpd.lang_flags & LANG_JAVA) &&
          (pc->type == CT_SYNCHRONIZED) &&
          (next->type != CT_PAREN_OPEN))
      {
         set_chunk_type(pc, CT_QUALIFIER);
      }

      // guy 2015-11-05
      // change CT_DC_MEMBER + CT_FOR into CT_DC_MEMBER + CT_FUNC_CALL
      if ((pc->type == CT_FOR) &&
          (pc->prev->type == CT_DC_MEMBER))
      {
         set_chunk_type(pc, CT_FUNC_CALL);
      }
      /* TODO: determine other stuff here */

      prev = pc;
      pc   = next;
      next = chunk_get_next_ncnl(pc);
   }
} // tokenize_cleanup
예제 #21
0
static chunk_t *pawn_process_func_def(chunk_t *pc)
{
   /* We are on a function definition */
   chunk_t *clp;
   chunk_t *last;
   chunk_t *next;

   pc->type = CT_FUNC_DEF;

   /* If we don't have a brace open right after the close fparen, then
    * we need to add virtual braces around the function body.
    */
   clp  = chunk_get_next_str(pc, ")", 1, 0);
   last = chunk_get_next_ncnl(clp);

   if (last != NULL)
   {
      LOG_FMT(LPFUNC, "%s: %d] last is '%s' [%s]\n", __func__,
              last->orig_line, last->str.c_str(), get_token_name(last->type));
   }

   /* See if there is a state clause after the function */
   if ((last != NULL) && chunk_is_str(last, "<", 1))
   {
      LOG_FMT(LPFUNC, "%s: %d] '%s' has state angle open %s\n", __func__,
              pc->orig_line, pc->str.c_str(), get_token_name(last->type));

      last->type        = CT_ANGLE_OPEN;
      last->parent_type = CT_FUNC_DEF;
      while (((last = chunk_get_next(last)) != NULL) &&
             !chunk_is_str(last, ">", 1))
      {
      }

      if (last != NULL)
      {
         LOG_FMT(LPFUNC, "%s: %d] '%s' has state angle close %s\n", __func__,
                 pc->orig_line, pc->str.c_str(), get_token_name(last->type));
         last->type        = CT_ANGLE_CLOSE;
         last->parent_type = CT_FUNC_DEF;
      }
      last = chunk_get_next_ncnl(last);
   }

   if (last == NULL)
   {
      return(last);
   }
   if (last->type == CT_BRACE_OPEN)
   {
      last->parent_type = CT_FUNC_DEF;
      last = chunk_get_next_type(last, CT_BRACE_CLOSE, last->level);
      if (last != NULL)
      {
         last->parent_type = CT_FUNC_DEF;
      }
   }
   else
   {
      LOG_FMT(LPFUNC, "%s: %d] '%s' fdef: expected brace open: %s\n", __func__,
              pc->orig_line, pc->str.c_str(), get_token_name(last->type));

      chunk_t chunk;
      chunk             = *last;
      chunk.str.clear();
      chunk.type        = CT_VBRACE_OPEN;
      chunk.parent_type = 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:%d] check %s, level %d\n", __func__,
                 prev->orig_line, get_token_name(prev->type), prev->level);
         if ((prev->type == CT_NEWLINE) &&
             (prev->level == 0))
         {
            next = chunk_get_next_ncnl(prev);
            if ((next != NULL) &&
                (next->type != CT_ELSE) &&
                (next->type != CT_WHILE_OF_DO))
            {
               break;
            }
         }
         prev->level++;
         prev->brace_level++;
         last = prev;
      } while ((prev = chunk_get_next(prev)) != NULL);

      if (last != NULL)
      {
         LOG_FMT(LPFUNC, "%s:%d] ended on %s, level %d\n", __func__,
                 last->orig_line, get_token_name(last->type), last->level);
      }

      chunk             = *last;
      chunk.str.clear();
      chunk.column     += last->len();
      chunk.type        = CT_VBRACE_CLOSE;
      chunk.level       = 0;
      chunk.brace_level = 0;
      chunk.parent_type = CT_FUNC_DEF;
      last = chunk_add_after(&chunk, last);
   }
   return(last);
}
예제 #22
0
파일: space.cpp 프로젝트: jscipione/Paladin
/**
 * Decides how to change inter-chunk spacing.
 * Note that the order of the if statements is VERY important.
 *
 * @param first   The first chunk
 * @param second  The second chunk
 * @return        AV_IGNORE, AV_ADD, AV_REMOVE or AV_FORCE
 */
argval_t do_space(chunk_t *first, chunk_t *second, bool complete = true)
{
   int      idx;
   argval_t arg;
   chunk_t  *next;

   if ((first->type == CT_IGNORED) || (second->type == CT_IGNORED))
   {
      log_rule("IGNORED");
      return(AV_REMOVE);
   }
   if ((first->type == CT_PP) || (second->type == CT_PP))
   {
      log_rule("sp_pp_concat");
      return(cpd.settings[UO_sp_pp_concat].a);
   }
   if (first->type == CT_POUND)
   {
      log_rule("sp_pp_stringify");
      return(cpd.settings[UO_sp_pp_stringify].a);
   }

   if ((first->type == CT_SPACE) || (second->type == CT_SPACE))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((second->type == CT_NEWLINE) ||
       (second->type == CT_VBRACE_OPEN))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }
   if ((first->type == CT_VBRACE_OPEN) && (second->type != CT_NL_CONT))
   {
      log_rule("ADD");
      return(AV_ADD);
   }
   if ((first->type == CT_VBRACE_CLOSE) && (second->type != CT_NL_CONT))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }
   if (second->type == CT_VSEMICOLON)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }
   if (first->type == CT_MACRO_FUNC)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }
   if (second->type == CT_NL_CONT)
   {
      log_rule("sp_before_nl_cont");
      return(cpd.settings[UO_sp_before_nl_cont].a);
   }

   if ((first->type == CT_D_ARRAY_COLON) ||
       (second->type == CT_D_ARRAY_COLON))
   {
      log_rule("sp_d_array_colon");
      return(cpd.settings[UO_sp_d_array_colon].a);
   }

   if ((first->type == CT_CASE) && CharTable::IsKw1(second->str[0]))
   {
      log_rule("sp_case_label");
      return(argval_t(cpd.settings[UO_sp_case_label].a | AV_ADD));
   }

   if ((first->type == CT_QUESTION) || (second->type == CT_QUESTION))
   {
      if (cpd.settings[UO_sp_cond_question].a != AV_IGNORE)
      {
         return(cpd.settings[UO_sp_cond_question].a);
      }
   }
   if ((first->type == CT_COND_COLON) || (second->type == CT_COND_COLON))
   {
      if (cpd.settings[UO_sp_cond_colon].a != AV_IGNORE)
      {
         return(cpd.settings[UO_sp_cond_colon].a);
      }
   }
   if ((first->type == CT_RANGE) || (second->type == CT_RANGE))
   {
      return(cpd.settings[UO_sp_range].a);
   }

   if ((first->type == CT_COLON) && (first->parent_type == CT_SQL_EXEC))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   /* Macro stuff can only return IGNORE, ADD, or FORCE */
   if (first->type == CT_MACRO)
   {
      log_rule("sp_macro");
      arg = cpd.settings[UO_sp_macro].a;
      return((argval_t)(arg | ((arg != AV_IGNORE) ? AV_ADD : AV_IGNORE)));
   }

   if ((first->type == CT_FPAREN_CLOSE) && (first->parent_type == CT_MACRO_FUNC))
   {
      log_rule("sp_macro_func");
      arg = cpd.settings[UO_sp_macro_func].a;
      return((argval_t)(arg | ((arg != AV_IGNORE) ? AV_ADD : AV_IGNORE)));
   }

   if (first->type == CT_PREPROC)
   {
      /* Remove spaces, unless we are ignoring. See indent_preproc() */
      if (cpd.settings[UO_pp_space].a == AV_IGNORE)
      {
         log_rule("IGNORE");
         return(AV_IGNORE);
      }
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if (second->type == CT_SEMICOLON)
   {
      if (second->parent_type == CT_FOR)
      {
         if ((cpd.settings[UO_sp_before_semi_for_empty].a != AV_IGNORE) &&
             ((first->type == CT_SPAREN_OPEN) || (first->type == CT_SEMICOLON)))
         {
            log_rule("sp_before_semi_for_empty");
            return(cpd.settings[UO_sp_before_semi_for_empty].a);
         }
         if (cpd.settings[UO_sp_before_semi_for].a != AV_IGNORE)
         {
            log_rule("sp_before_semi_for");
            return(cpd.settings[UO_sp_before_semi_for].a);
         }
      }

      arg = cpd.settings[UO_sp_before_semi].a;
      log_rule("sp_before_semi");
      if ((first->type == CT_SPAREN_CLOSE) &&
          (first->parent_type != CT_WHILE_OF_DO))
      {
         log_rule("sp_special_semi");
         arg = (argval_t)(arg | cpd.settings[UO_sp_special_semi].a);
      }
      return(arg);
   }

   /* "for (;;)" vs "for (;; )" and "for (a;b;c)" vs "for (a; b; c)" */
   if (first->type == CT_SEMICOLON)
   {
      if (first->parent_type == CT_FOR)
      {
         if ((cpd.settings[UO_sp_after_semi_for_empty].a != AV_IGNORE) &&
             (second->type == CT_SPAREN_CLOSE))
         {
            log_rule("sp_after_semi_for_empty");
            return(cpd.settings[UO_sp_after_semi_for_empty].a);
         }
         if (cpd.settings[UO_sp_after_semi_for].a != AV_IGNORE)
         {
            log_rule("sp_after_semi_for");
            return(cpd.settings[UO_sp_after_semi_for].a);
         }
      }
      else if (!chunk_is_comment(second))
      {
         log_rule("sp_after_semi");
         return(cpd.settings[UO_sp_after_semi].a);
      }
      /* Let the comment spacing rules handle this */
   }

   if (((first->type == CT_NEG) || (first->type == CT_POS) || (first->type == CT_ARITH)) &&
       ((second->type == CT_NEG) || (second->type == CT_POS) || (second->type == CT_ARITH)))
   {
      log_rule("ADD");
      return(AV_ADD);
   }

   /* "return(a);" vs "return (foo_t)a + 3;" vs "return a;" vs "return;" */
   if (first->type == CT_RETURN)
   {
      if ((second->type == CT_PAREN_OPEN) &&
          (second->parent_type == CT_RETURN))
      {
         log_rule("sp_return_paren");
         return(cpd.settings[UO_sp_return_paren].a);
      }
      /* everything else requires a space */
      log_rule("FORCE");
      return(AV_FORCE);
   }

   /* "sizeof(foo_t)" vs "sizeof foo_t" */
   if (first->type == CT_SIZEOF)
   {
      if (second->type == CT_PAREN_OPEN)
      {
         log_rule("sp_sizeof_paren");
         return(cpd.settings[UO_sp_sizeof_paren].a);
      }
      log_rule("FORCE");
      return(AV_FORCE);
   }

   /* handle '::' */
   if (first->type == CT_DC_MEMBER)
   {
      log_rule("sp_after_dc");
      return(cpd.settings[UO_sp_after_dc].a);
   }
   if ((second->type == CT_DC_MEMBER) &&
       ((first->type == CT_WORD) || (first->type == CT_TYPE) ||
        CharTable::IsKw1(first->str[0])))
   {
      log_rule("sp_before_dc");
      return(cpd.settings[UO_sp_before_dc].a);
   }

   /* "a,b" vs "a, b" */
   if (first->type == CT_COMMA)
   {
      log_rule("sp_after_comma");
      return(cpd.settings[UO_sp_after_comma].a);
   }
   if (second->type == CT_COMMA)
   {
      if ((first->type == CT_PAREN_OPEN) &&
          (cpd.settings[UO_sp_paren_comma].a != AV_IGNORE))
      {
         log_rule("sp_paren_comma");
         return(cpd.settings[UO_sp_paren_comma].a);
      }
      log_rule("sp_before_comma");
      return(cpd.settings[UO_sp_before_comma].a);
   }

   if (second->type == CT_ELLIPSIS)
   {
      /* non-punc followed by a ellipsis */
      if (((first->flags & PCF_PUNCTUATOR) == 0) &&
          (cpd.settings[UO_sp_before_ellipsis].a != AV_IGNORE))
      {
         log_rule("sp_before_ellipsis");
         return(cpd.settings[UO_sp_before_ellipsis].a);
      }

      if (first->type == CT_TAG_COLON)
      {
         log_rule("FORCE");
         return(AV_FORCE);
      }
   }
   if ((first->type == CT_ELLIPSIS) && CharTable::IsKw1(second->str[0]))
   {
      log_rule("FORCE");
      return(AV_FORCE);
   }
   if (first->type == CT_TAG_COLON)
   {
      log_rule("sp_after_tag");
      return(cpd.settings[UO_sp_after_tag].a);
   }
   if (second->type == CT_TAG_COLON)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   /* handle '~' */
   if (first->type == CT_DESTRUCTOR)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   /* "((" vs "( (" */
   if ((chunk_is_str(first, "(", 1) && chunk_is_str(second, "(", 1)) ||
       (chunk_is_str(first, ")", 1) && chunk_is_str(second, ")", 1)))
   {
      log_rule("sp_paren_paren");
      return(cpd.settings[UO_sp_paren_paren].a);
   }

   /* "if (" vs "if(" */
   if (second->type == CT_SPAREN_OPEN)
   {
      log_rule("sp_before_sparen");
      return(cpd.settings[UO_sp_before_sparen].a);
   }

   if ((first->type == CT_LAMBDA) ||
       (second->type == CT_LAMBDA))
   {
      log_rule("sp_assign (lambda)");
      return(cpd.settings[UO_sp_assign].a);
   }

   if (second->type == CT_OC_BLOCK_CARET)
   {
      log_rule("sp_before_oc_block_caret");
      return(cpd.settings[UO_sp_before_oc_block_caret].a);
   }
   if (first->type == CT_OC_BLOCK_CARET)
   {
      log_rule("sp_after_oc_block_caret");
      return(cpd.settings[UO_sp_after_oc_block_caret].a);
   }

   if (second->type == CT_ASSIGN)
   {
      if (second->flags & PCF_IN_ENUM)
      {
         if (cpd.settings[UO_sp_enum_before_assign].a != AV_IGNORE)
         {
            log_rule("sp_enum_before_assign");
            return(cpd.settings[UO_sp_enum_before_assign].a);
         }
         log_rule("sp_enum_assign");
         return(cpd.settings[UO_sp_enum_assign].a);
      }
      if ((cpd.settings[UO_sp_assign_default].a != AV_IGNORE) &&
          (second->parent_type == CT_FUNC_PROTO))
      {
         log_rule("sp_assign_default");
         return(cpd.settings[UO_sp_assign_default].a);
      }
      if (cpd.settings[UO_sp_before_assign].a != AV_IGNORE)
      {
         log_rule("sp_before_assign");
         return(cpd.settings[UO_sp_before_assign].a);
      }
      log_rule("sp_assign");
      return(cpd.settings[UO_sp_assign].a);
   }

   if (first->type == CT_ASSIGN)
   {
      if (first->flags & PCF_IN_ENUM)
      {
         if (cpd.settings[UO_sp_enum_after_assign].a != AV_IGNORE)
         {
            log_rule("sp_enum_after_assign");
            return(cpd.settings[UO_sp_enum_after_assign].a);
         }
         log_rule("sp_enum_assign");
         return(cpd.settings[UO_sp_enum_assign].a);
      }
      if ((cpd.settings[UO_sp_assign_default].a != AV_IGNORE) &&
          (first->parent_type == CT_FUNC_PROTO))
      {
         log_rule("sp_assign_default");
         return(cpd.settings[UO_sp_assign_default].a);
      }
      if (cpd.settings[UO_sp_after_assign].a != AV_IGNORE)
      {
         log_rule("sp_after_assign");
         return(cpd.settings[UO_sp_after_assign].a);
      }
      log_rule("sp_assign");
      return(cpd.settings[UO_sp_assign].a);
   }

   /* "a [x]" vs "a[x]" */
   if ((second->type == CT_SQUARE_OPEN) && (second->parent_type != CT_OC_MSG))
   {
      log_rule("sp_before_square");
      return(cpd.settings[UO_sp_before_square].a);
   }

   /* "byte[]" vs "byte []" */
   if (second->type == CT_TSQUARE)
   {
      log_rule("sp_before_squares");
      return(cpd.settings[UO_sp_before_squares].a);
   }

   if ((cpd.settings[UO_sp_angle_shift].a != AV_IGNORE) &&
       (first->type == CT_ANGLE_CLOSE) && (second->type == CT_ANGLE_CLOSE))
   {
      log_rule("sp_angle_shift");
      return(cpd.settings[UO_sp_angle_shift].a);
   }

   /* spacing around template < > stuff */
   if ((first->type == CT_ANGLE_OPEN) ||
       (second->type == CT_ANGLE_CLOSE))
   {
      log_rule("sp_inside_angle");
      return(cpd.settings[UO_sp_inside_angle].a);
   }
   if (second->type == CT_ANGLE_OPEN)
   {
      if ((first->type == CT_TEMPLATE) &&
          (cpd.settings[UO_sp_template_angle].a != AV_IGNORE))
      {
         log_rule("sp_template_angle");
         return(cpd.settings[UO_sp_template_angle].a);
      }
      log_rule("sp_before_angle");
      return(cpd.settings[UO_sp_before_angle].a);
   }
   if (first->type == CT_ANGLE_CLOSE)
   {
      if ((second->type == CT_WORD) || CharTable::IsKw1(second->str[0]))
      {
         if (cpd.settings[UO_sp_angle_word].a != AV_IGNORE)
         {
            log_rule("sp_angle_word");
            return(cpd.settings[UO_sp_angle_word].a);
         }
      }
      if ((second->type == CT_FPAREN_OPEN) ||
          (second->type == CT_PAREN_OPEN))
      {
         log_rule("sp_angle_paren");
         return(cpd.settings[UO_sp_angle_paren].a);
      }
      if (second->type == CT_DC_MEMBER)
      {
         log_rule("sp_before_dc");
         return(cpd.settings[UO_sp_before_dc].a);
      }
      if ((second->type != CT_BYREF) &&
          (second->type != CT_PTR_TYPE))
      {
         log_rule("sp_after_angle");
         return(cpd.settings[UO_sp_after_angle].a);
      }
   }

   if ((first->type == CT_BYREF) &&
       (cpd.settings[UO_sp_after_byref_func].a != AV_IGNORE) &&
       ((first->parent_type == CT_FUNC_DEF) ||
        (first->parent_type == CT_FUNC_PROTO)))
   {
      log_rule("sp_after_byref_func");
      return(cpd.settings[UO_sp_after_byref_func].a);
   }

   if ((first->type == CT_BYREF) && CharTable::IsKw1(second->str[0]))
   {
      log_rule("sp_after_byref");
      return(cpd.settings[UO_sp_after_byref].a);
   }

   if (second->type == CT_BYREF)
   {
      if (cpd.settings[UO_sp_before_byref_func].a != AV_IGNORE)
      {
         next = chunk_get_next(second);
         if ((next != NULL) &&
             ((next->type == CT_FUNC_DEF) ||
              (next->type == CT_FUNC_PROTO)))
         {
            return(cpd.settings[UO_sp_before_byref_func].a);
         }
      }

      if (cpd.settings[UO_sp_before_unnamed_byref].a != AV_IGNORE)
      {
         next = chunk_get_next_nc(second);
         if ((next != NULL) && (next->type != CT_WORD))
         {
            log_rule("sp_before_unnamed_byref");
            return(cpd.settings[UO_sp_before_unnamed_byref].a);
         }
      }
      log_rule("sp_before_byref");
      return(cpd.settings[UO_sp_before_byref].a);
   }

   if (first->type == CT_SPAREN_CLOSE)
   {
      if ((second->type == CT_BRACE_OPEN) &&
          (cpd.settings[UO_sp_sparen_brace].a != AV_IGNORE))
      {
         log_rule("sp_sparen_brace");
         return(cpd.settings[UO_sp_sparen_brace].a);
      }
      if (!chunk_is_comment(second) &&
          (cpd.settings[UO_sp_after_sparen].a != AV_IGNORE))
      {
         log_rule("sp_after_sparen");
         return(cpd.settings[UO_sp_after_sparen].a);
      }
   }

   if ((second->type == CT_FPAREN_OPEN) &&
       (first->parent_type == CT_OPERATOR) &&
       (cpd.settings[UO_sp_after_operator_sym].a != AV_IGNORE))
   {
      log_rule("sp_after_operator_sym");
      return(cpd.settings[UO_sp_after_operator_sym].a);
   }

   /* spaces between function and open paren */
   if ((first->type == CT_FUNC_CALL) ||
       (first->type == CT_FUNC_CTOR_VAR))
   {
      if ((cpd.settings[UO_sp_func_call_paren_empty].a != AV_IGNORE) &&
          (second->type == CT_FPAREN_OPEN))
      {
         next = chunk_get_next_ncnl(second);
         if (next && (next->type == CT_FPAREN_CLOSE))
         {
            log_rule("sp_func_call_paren_empty");
            return(cpd.settings[UO_sp_func_call_paren_empty].a);
         }
      }
      log_rule("sp_func_call_paren");
      return(cpd.settings[UO_sp_func_call_paren].a);
   }
   if (first->type == CT_FUNC_CALL_USER)
   {
      log_rule("sp_func_call_user_paren");
      return(cpd.settings[UO_sp_func_call_user_paren].a);
   }
   if (first->type == CT_ATTRIBUTE)
   {
      log_rule("sp_attribute_paren");
      return(cpd.settings[UO_sp_attribute_paren].a);
   }
   if (first->type == CT_FUNC_DEF)
   {
      log_rule("sp_func_def_paren");
      return(cpd.settings[UO_sp_func_def_paren].a);
   }
   if ((first->type == CT_CPP_CAST) || (first->type == CT_TYPE_WRAP))
   {
      log_rule("sp_cpp_cast_paren");
      return(cpd.settings[UO_sp_cpp_cast_paren].a);
   }

   if ((first->type == CT_PAREN_CLOSE) &&
       ((second->type == CT_PAREN_OPEN) ||
        (second->type == CT_FPAREN_OPEN)))
   {
      /* "(int)a" vs "(int) a" or "cast(int)a" vs "cast(int) a" */
      if ((first->parent_type == CT_C_CAST) ||
          (first->parent_type == CT_D_CAST))
      {
         log_rule("sp_after_cast");
         return(cpd.settings[UO_sp_after_cast].a);
      }

      /* Must be an indirect/chained function call? */
      log_rule("REMOVE");
      return(AV_REMOVE);  /* TODO: make this configurable? */
   }

   if ((first->type == CT_FUNC_PROTO) ||
       ((second->type == CT_FPAREN_OPEN) &&
        (second->parent_type == CT_FUNC_PROTO)))
   {
      log_rule("sp_func_proto_paren");
      return(cpd.settings[UO_sp_func_proto_paren].a);
   }
   if (first->type == CT_FUNC_CLASS)
   {
      log_rule("sp_func_class_paren");
      return(cpd.settings[UO_sp_func_class_paren].a);
   }
   if ((first->type == CT_CLASS) && (first->parent_type != CT_OC_MSG))
   {
      log_rule("FORCE");
      return(AV_FORCE);
   }

   if ((first->type == CT_BRACE_OPEN) && (second->type == CT_BRACE_CLOSE))
   {
      log_rule("sp_inside_braces_empty");
      return(cpd.settings[UO_sp_inside_braces_empty].a);
   }

   if (second->type == CT_BRACE_CLOSE)
   {
      if (second->parent_type == CT_ENUM)
      {
         log_rule("sp_inside_braces_enum");
         return(cpd.settings[UO_sp_inside_braces_enum].a);
      }
      if ((second->parent_type == CT_STRUCT) ||
          (second->parent_type == CT_UNION))
      {
         log_rule("sp_inside_braces_struct");
         return(cpd.settings[UO_sp_inside_braces_struct].a);
      }
      log_rule("sp_inside_braces");
      return(cpd.settings[UO_sp_inside_braces].a);
   }

   if (first->type == CT_D_CAST)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_PP_DEFINED) && (second->type == CT_PAREN_OPEN))
   {
      log_rule("sp_defined_paren");
      return(cpd.settings[UO_sp_defined_paren].a);
   }

   if ((first->type == CT_THROW) && (second->type == CT_PAREN_OPEN))
   {
      log_rule("sp_throw_paren");
      return(cpd.settings[UO_sp_throw_paren].a);
   }

   if ((first->type == CT_THIS) && (second->type == CT_PAREN_OPEN))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_STATE) && (second->type == CT_PAREN_OPEN))
   {
      log_rule("ADD");
      return(AV_ADD);
   }

   if ((first->type == CT_DELEGATE) && (second->type == CT_PAREN_OPEN))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_MEMBER) || (second->type == CT_MEMBER))
   {
      log_rule("sp_member");
      return(cpd.settings[UO_sp_member].a);
   }

   if (first->type == CT_C99_MEMBER)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_SUPER) && (second->type == CT_PAREN_OPEN))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_FPAREN_CLOSE) && (second->type == CT_BRACE_OPEN))
   {
      log_rule("sp_fparen_brace");
      return(cpd.settings[UO_sp_fparen_brace].a);
   }

   if ((first->type == CT_D_TEMPLATE) || (second->type == CT_D_TEMPLATE))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_ELSE) && (second->type == CT_BRACE_OPEN))
   {
      log_rule("sp_else_brace");
      return(cpd.settings[UO_sp_else_brace].a);
   }

   if ((first->type == CT_ELSE) && (second->type == CT_ELSEIF))
   {
      log_rule("FORCE");
      return(AV_FORCE);
   }

   if ((first->type == CT_CATCH) && (second->type == CT_BRACE_OPEN))
   {
      log_rule("sp_catch_brace");
      return(cpd.settings[UO_sp_catch_brace].a);
   }

   if ((first->type == CT_FINALLY) && (second->type == CT_BRACE_OPEN))
   {
      log_rule("sp_finally_brace");
      return(cpd.settings[UO_sp_finally_brace].a);
   }

   if ((first->type == CT_TRY) && (second->type == CT_BRACE_OPEN))
   {
      log_rule("sp_try_brace");
      return(cpd.settings[UO_sp_try_brace].a);
   }

   if ((first->type == CT_GETSET) && (second->type == CT_BRACE_OPEN))
   {
      log_rule("sp_getset_brace");
      return(cpd.settings[UO_sp_getset_brace].a);
   }

   if ((second->type == CT_PAREN_OPEN) &&
       (second->parent_type == CT_INVARIANT))
   {
      log_rule("sp_invariant_paren");
      return(cpd.settings[UO_sp_invariant_paren].a);
   }

   if (first->type == CT_PAREN_CLOSE)
   {
      if (first->parent_type == CT_D_TEMPLATE)
      {
         log_rule("FORCE");
         return(AV_FORCE);
      }

      if (first->parent_type == CT_INVARIANT)
      {
         log_rule("sp_after_invariant_paren");
         return(cpd.settings[UO_sp_after_invariant_paren].a);
      }

      /* Arith after a cast comes first */
      if (second->type == CT_ARITH)
      {
         log_rule("sp_arith");
         return(cpd.settings[UO_sp_arith].a);
      }

      /* "(struct foo) {...}" vs "(struct foo){...}" */
      if (second->type == CT_BRACE_OPEN)
      {
         log_rule("sp_paren_brace");
         return(cpd.settings[UO_sp_paren_brace].a);
      }

      /* D-specific: "delegate(some thing) dg */
      if (first->parent_type == CT_DELEGATE)
      {
         log_rule("ADD");
         return(AV_ADD);
      }

      /* PAWN-specific: "state (condition) next" */
      if (first->parent_type == CT_STATE)
      {
         log_rule("ADD");
         return(AV_ADD);
      }
   }

   /* "foo(...)" vs "foo( ... )" */
   if ((first->type == CT_FPAREN_OPEN) || (second->type == CT_FPAREN_CLOSE))
   {
      if ((first->type == CT_FPAREN_OPEN) && (second->type == CT_FPAREN_CLOSE))
      {
         log_rule("sp_inside_fparens");
         return(cpd.settings[UO_sp_inside_fparens].a);
      }
      log_rule("sp_inside_fparen");
      return(cpd.settings[UO_sp_inside_fparen].a);
   }

   if (first->type == CT_PAREN_CLOSE)
   {
      if (first->parent_type == CT_OC_RTYPE)
      {
         log_rule("sp_after_oc_return_type");
         return(cpd.settings[UO_sp_after_oc_return_type].a);
      }
      else if ((first->parent_type == CT_OC_MSG_SPEC) ||
               (first->parent_type == CT_OC_MSG_DECL))
      {
         log_rule("sp_after_oc_type");
         return(cpd.settings[UO_sp_after_oc_type].a);
      }
      else if ((first->parent_type == CT_OC_SEL) &&
               (second->type != CT_SQUARE_CLOSE))
      {
         log_rule("sp_after_oc_at_sel_parens");
         return(cpd.settings[UO_sp_after_oc_at_sel_parens].a);
      }
   }

   if (cpd.settings[UO_sp_inside_oc_at_sel_parens].a != AV_IGNORE)
   {
      if (((first->type == CT_PAREN_OPEN) &&
           ((first->parent_type == CT_OC_SEL) ||
            (first->parent_type == CT_OC_PROTOCOL)))
          ||
          ((second->type == CT_PAREN_CLOSE) &&
           ((second->parent_type == CT_OC_SEL) ||
            (second->parent_type == CT_OC_PROTOCOL))))
      {
         log_rule("sp_inside_oc_at_sel_parens");
         return(cpd.settings[UO_sp_inside_oc_at_sel_parens].a);
      }
   }

   if ((second->type == CT_PAREN_OPEN) &&
       ((first->type == CT_OC_SEL) || (first->type == CT_OC_PROTOCOL)))
   {
      log_rule("sp_after_oc_at_sel");
      return(cpd.settings[UO_sp_after_oc_at_sel].a);
   }

   /* C cast:   "(int)"      vs "( int )"
    * D cast:   "cast(int)"  vs "cast( int )"
    * CPP cast: "int(a + 3)" vs "int( a + 3 )"
    */
   if (first->type == CT_PAREN_OPEN)
   {
      if ((first->parent_type == CT_C_CAST) ||
          (first->parent_type == CT_CPP_CAST) ||
          (first->parent_type == CT_D_CAST))
      {
         log_rule("sp_inside_paren_cast");
         return(cpd.settings[UO_sp_inside_paren_cast].a);
      }
      log_rule("sp_inside_paren");
      return(cpd.settings[UO_sp_inside_paren].a);
   }

   if (second->type == CT_PAREN_CLOSE)
   {
      if ((second->parent_type == CT_C_CAST) ||
          (second->parent_type == CT_CPP_CAST) ||
          (second->parent_type == CT_D_CAST))
      {
         log_rule("sp_inside_paren_cast");
         return(cpd.settings[UO_sp_inside_paren_cast].a);
      }
      log_rule("sp_inside_paren");
      return(cpd.settings[UO_sp_inside_paren].a);
   }

   /* "[3]" vs "[ 3 ]" */
   if ((first->type == CT_SQUARE_OPEN) || (second->type == CT_SQUARE_CLOSE))
   {
      log_rule("sp_inside_square");
      return(cpd.settings[UO_sp_inside_square].a);
   }
   if ((first->type == CT_SQUARE_CLOSE) && (second->type == CT_FPAREN_OPEN))
   {
      log_rule("sp_square_fparen");
      return(cpd.settings[UO_sp_square_fparen].a);
   }

   /* "if(...)" vs "if( ... )" */
   if ((second->type == CT_SPAREN_CLOSE) &&
       (cpd.settings[UO_sp_inside_sparen_close].a != AV_IGNORE))
   {
      log_rule("sp_inside_sparen_close");
      return(cpd.settings[UO_sp_inside_sparen_close].a);
   }
   if ((first->type == CT_SPAREN_OPEN) || (second->type == CT_SPAREN_CLOSE))
   {
      log_rule("sp_inside_sparen");
      return(cpd.settings[UO_sp_inside_sparen].a);
   }

   if ((cpd.settings[UO_sp_after_class_colon].a != AV_IGNORE) &&
       (first->type == CT_CLASS_COLON))
   {
      log_rule("sp_after_class_colon");
      return(cpd.settings[UO_sp_after_class_colon].a);
   }
   if ((cpd.settings[UO_sp_before_class_colon].a != AV_IGNORE) &&
       (second->type == CT_CLASS_COLON))
   {
      log_rule("sp_before_class_colon");
      return(cpd.settings[UO_sp_before_class_colon].a);
   }
   if ((cpd.settings[UO_sp_before_case_colon].a != AV_IGNORE) &&
       (second->type == CT_CASE_COLON))
   {
      log_rule("sp_before_case_colon");
      return(cpd.settings[UO_sp_before_case_colon].a);
   }

   if (first->type == CT_DOT)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }
   if (second->type == CT_DOT)
   {
      log_rule("ADD");
      return(AV_ADD);
   }

   if ((first->type == CT_ARITH) || (second->type == CT_ARITH))
   {
      log_rule("sp_arith");
      return(cpd.settings[UO_sp_arith].a);
   }
   if ((first->type == CT_BOOL) || (second->type == CT_BOOL))
   {
      arg = cpd.settings[UO_sp_bool].a;
      if ((cpd.settings[UO_pos_bool].tp != TP_IGNORE) &&
          (first->orig_line != second->orig_line) &&
          (arg != AV_REMOVE))
      {
         arg = (argval_t)(arg | AV_ADD);
      }
      log_rule("sp_bool");
      return(arg);
   }
   if ((first->type == CT_COMPARE) || (second->type == CT_COMPARE))
   {
      log_rule("sp_compare");
      return(cpd.settings[UO_sp_compare].a);
   }

   if ((first->type == CT_PAREN_OPEN) && (second->type == CT_PTR_TYPE))
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }

   if ((first->type == CT_PTR_TYPE) &&
       (second->type == CT_PTR_TYPE) &&
       (cpd.settings[UO_sp_between_ptr_star].a != AV_IGNORE))
   {
      log_rule("sp_between_ptr_star");
      return(cpd.settings[UO_sp_between_ptr_star].a);
   }

   if ((first->type == CT_PTR_TYPE) &&
       (cpd.settings[UO_sp_after_ptr_star_func].a != AV_IGNORE) &&
       ((first->parent_type == CT_FUNC_DEF) ||
        (first->parent_type == CT_FUNC_PROTO)))
   {
      log_rule("sp_after_ptr_star_func");
      return(cpd.settings[UO_sp_after_ptr_star_func].a);
   }

   if ((first->type == CT_PTR_TYPE) &&
       (cpd.settings[UO_sp_after_ptr_star].a != AV_IGNORE) &&
       CharTable::IsKw1(second->str[0]))
   {
      log_rule("sp_after_ptr_star");
      return(cpd.settings[UO_sp_after_ptr_star].a);
   }

   if (second->type == CT_PTR_TYPE)
   {
      if (cpd.settings[UO_sp_before_ptr_star_func].a != AV_IGNORE)
      {
         /* Find the next non-'*' chunk */
         next = second;
         do
         {
            next = chunk_get_next(next);
         } while ((next != NULL) && (next->type == CT_PTR_TYPE));

         if ((next != NULL) &&
             ((next->type == CT_FUNC_DEF) ||
              (next->type == CT_FUNC_PROTO)))
         {
            return(cpd.settings[UO_sp_before_ptr_star_func].a);
         }
      }

      if (cpd.settings[UO_sp_before_unnamed_ptr_star].a != AV_IGNORE)
      {
         next = chunk_get_next_nc(second);
         while ((next != NULL) && (next->type == CT_PTR_TYPE))
         {
            next = chunk_get_next_nc(next);
         }
         if ((next != NULL) && (next->type != CT_WORD))
         {
            log_rule("sp_before_unnamed_ptr_star");
            return(cpd.settings[UO_sp_before_unnamed_ptr_star].a);
         }
      }
      if (cpd.settings[UO_sp_before_ptr_star].a != AV_IGNORE)
      {
         log_rule("sp_before_ptr_star");
         return(cpd.settings[UO_sp_before_ptr_star].a);
      }
   }

   if (first->type == CT_OPERATOR)
   {
      log_rule("sp_after_operator");
      return(cpd.settings[UO_sp_after_operator].a);
   }

   if ((second->type == CT_FUNC_PROTO) || (second->type == CT_FUNC_DEF))
   {
      if (first->type != CT_PTR_TYPE)
      {
         log_rule("sp_type_func|ADD");
         return((argval_t)(cpd.settings[UO_sp_type_func].a | AV_ADD));
      }
      log_rule("sp_type_func");
      return(cpd.settings[UO_sp_type_func].a);
   }

   /* "(int)a" vs "(int) a" or "cast(int)a" vs "cast(int) a" */
   if ((first->parent_type == CT_C_CAST) ||
       (first->parent_type == CT_D_CAST))
   {
      log_rule("sp_after_cast");
      return(cpd.settings[UO_sp_after_cast].a);
   }

   if (first->type == CT_BRACE_CLOSE)
   {
      if (second->type == CT_ELSE)
      {
         log_rule("sp_brace_else");
         return(cpd.settings[UO_sp_brace_else].a);
      }
      else if (second->type == CT_CATCH)
      {
         log_rule("sp_brace_catch");
         return(cpd.settings[UO_sp_brace_catch].a);
      }
      else if (second->type == CT_FINALLY)
      {
         log_rule("sp_brace_finally");
         return(cpd.settings[UO_sp_brace_finally].a);
      }
   }

   if (first->type == CT_BRACE_OPEN)
   {
      if (first->parent_type == CT_ENUM)
      {
         log_rule("sp_inside_braces_enum");
         return(cpd.settings[UO_sp_inside_braces_enum].a);
      }
      else if ((first->parent_type == CT_UNION) ||
               (first->parent_type == CT_STRUCT))
      {
         log_rule("sp_inside_braces_struct");
         return(cpd.settings[UO_sp_inside_braces_struct].a);
      }
      else if (!chunk_is_comment(second))
      {
         log_rule("sp_inside_braces");
         return(cpd.settings[UO_sp_inside_braces].a);
      }
   }

   if (second->type == CT_BRACE_CLOSE)
   {
      if (second->parent_type == CT_ENUM)
      {
         log_rule("sp_inside_braces_enum");
         return(cpd.settings[UO_sp_inside_braces_enum].a);
      }
      else if ((second->parent_type == CT_UNION) ||
               (second->parent_type == CT_STRUCT))
      {
         log_rule("sp_inside_braces_struct");
         return(cpd.settings[UO_sp_inside_braces_struct].a);
      }
      log_rule("sp_inside_braces");
      return(cpd.settings[UO_sp_inside_braces].a);
   }

   if ((first->type == CT_BRACE_CLOSE) &&
       (first->flags & PCF_IN_TYPEDEF) &&
       ((first->parent_type == CT_ENUM) ||
        (first->parent_type == CT_STRUCT) ||
        (first->parent_type == CT_UNION)))
   {
      log_rule("sp_brace_typedef");
      return(cpd.settings[UO_sp_brace_typedef].a);
   }

   if (second->type == CT_SPAREN_OPEN)
   {
      log_rule("sp_before_sparen");
      return(cpd.settings[UO_sp_before_sparen].a);
   }

   if ((second->type != CT_PTR_TYPE) &&
       ((first->type == CT_QUALIFIER) || (first->type == CT_TYPE)))
   {
      arg = cpd.settings[UO_sp_after_type].a;
      log_rule("sp_after_type");
      return((arg != AV_REMOVE) ? arg : AV_FORCE);
   }

   if ((first->type == CT_MACRO_OPEN) ||
       (first->type == CT_MACRO_CLOSE) ||
       (first->type == CT_MACRO_ELSE))
   {
      if (second->type == CT_PAREN_OPEN)
      {
         log_rule("sp_func_call_paren");
         return(cpd.settings[UO_sp_func_call_paren].a);
      }
      log_rule("IGNORE");
      return(AV_IGNORE);
   }

   /* If nothing claimed the PTR_TYPE, then return ignore */
   if ((first->type == CT_PTR_TYPE) || (second->type == CT_PTR_TYPE))
   {
      log_rule("IGNORE");
      return(AV_IGNORE);
   }

   if (first->type == CT_NOT)
   {
      log_rule("sp_not");
      return(cpd.settings[UO_sp_not].a);
   }
   if (first->type == CT_INV)
   {
      log_rule("sp_inv");
      return(cpd.settings[UO_sp_inv].a);
   }
   if (first->type == CT_ADDR)
   {
      log_rule("sp_addr");
      return(cpd.settings[UO_sp_addr].a);
   }
   if (first->type == CT_DEREF)
   {
      log_rule("sp_deref");
      return(cpd.settings[UO_sp_deref].a);
   }
   if ((first->type == CT_POS) || (first->type == CT_NEG))
   {
      log_rule("sp_sign");
      return(cpd.settings[UO_sp_sign].a);
   }
   if ((first->type == CT_INCDEC_BEFORE) || (second->type == CT_INCDEC_AFTER))
   {
      log_rule("sp_incdec");
      return(cpd.settings[UO_sp_incdec].a);
   }
   if (second->type == CT_CS_SQ_COLON)
   {
      log_rule("REMOVE");
      return(AV_REMOVE);
   }
   if (first->type == CT_CS_SQ_COLON)
   {
      log_rule("FORCE");
      return(AV_FORCE);
   }
   if (first->type == CT_OC_SCOPE)
   {
      log_rule("sp_after_oc_scope");
      return(cpd.settings[UO_sp_after_oc_scope].a);
   }
   if (first->type == CT_OC_COLON)
   {
      if (first->parent_type == CT_OC_MSG)
      {
         log_rule("sp_after_send_oc_colon");
         return(cpd.settings[UO_sp_after_send_oc_colon].a);
      }
      else
      {
         log_rule("sp_after_oc_colon");
         return(cpd.settings[UO_sp_after_oc_colon].a);
      }
   }
   if (second->type == CT_OC_COLON)
   {
      if ((first->parent_type == CT_OC_MSG) &&
          ((first->type == CT_OC_MSG_FUNC) ||
           (first->type == CT_OC_MSG_NAME)))
      {
         log_rule("sp_before_send_oc_colon");
         return(cpd.settings[UO_sp_before_send_oc_colon].a);
      }
      else
      {
         log_rule("sp_before_oc_colon");
         return(cpd.settings[UO_sp_before_oc_colon].a);
      }
   }

   if ((second->type == CT_COMMENT) && (second->parent_type == CT_COMMENT_EMBED))
   {
      log_rule("FORCE");
      return(AV_FORCE);
   }

   if ((second->type == CT_COMMENT) &&
       ((first->type == CT_PP_ELSE) || (first->type == CT_PP_ENDIF)))
   {
      if (cpd.settings[UO_sp_endif_cmt].a != AV_IGNORE)
      {
         second->type = CT_COMMENT_ENDIF;
         log_rule("sp_endif_cmt");
         return(cpd.settings[UO_sp_endif_cmt].a);
      }
   }

   if (chunk_is_comment(second))
   {
      log_rule("IGNORE");
      return(AV_IGNORE);
   }

   if (first->type == CT_COMMENT)
   {
      log_rule("FORCE");
      return(AV_FORCE);
   }

   for (idx = 0; idx < (int)ARRAY_SIZE(no_space_table); idx++)
   {
      if (((no_space_table[idx].first == CT_UNKNOWN) ||
           (no_space_table[idx].first == first->type))
          &&
          ((no_space_table[idx].second == CT_UNKNOWN) ||
           (no_space_table[idx].second == second->type)))
      {
         log_rule("REMOVE");
         return(AV_REMOVE);
      }
   }
   log_rule("ADD");
   return(AV_ADD);
}
예제 #23
0
/**
 * Change the top-level indentation only by changing the column member in
 * the chunk structures.
 * The level indicator must already be set.
 */
void indent_text(void)
{
    chunk_t            *pc;
    chunk_t            *next;
    chunk_t            *prev       = NULL;
    bool did_newline = true;
    int idx;
    int vardefcol   = 0;
    int indent_size = cpd.settings[UO_indent_columns].n;
    int tmp;
    struct parse_frame frm;
    bool in_preproc = false, was_preproc = false;
    int indent_column;
    int cout_col            = 0;                 // for aligning << stuff
    int cout_level          = 0;                 // for aligning << stuff
    int parent_token_indent = 0;

    memset(&frm, 0, sizeof(frm));

    /* dummy top-level entry */
    frm.pse[0].indent     = 1;
    frm.pse[0].indent_tmp = 1;
    frm.pse[0].type       = CT_EOF;

    pc = chunk_get_head();

    while (pc != NULL)
    {
        /* Handle proprocessor transitions */
        was_preproc = in_preproc;
        in_preproc  = (pc->flags & PCF_IN_PREPROC) != 0;

        if (cpd.settings[UO_indent_brace_parent].b)
            parent_token_indent = token_indent(pc->parent_type);

        /* Clean up after a #define */
        if (!in_preproc)
            while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc)
                indent_pse_pop(frm, pc);

        else
        {
            pf_check(&frm, pc);

            if (!was_preproc)
            {
                /* Transition into a preproc by creating a dummy indent */
                frm.level++;
                indent_pse_push(frm, pc);

                frm.pse[frm.pse_tos].indent     = 1 + indent_size;
                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
            }
        }

        if ((cout_col > 0) &&
                (chunk_is_semicolon(pc) ||
                 (pc->level < cout_level)))
        {
            cout_col   = 0;
            cout_level = 0;
        }

        /**
         * Handle non-brace closures
         */

        int old_pse_tos;

        do
        {
            old_pse_tos = frm.pse_tos;

            /* End anything that drops a level
             * REVISIT: not sure about the preproc check
             */
            if (!chunk_is_newline(pc) &&
                    !chunk_is_comment(pc) &&
                    ((pc->flags & PCF_IN_PREPROC) == 0) &&
                    (frm.pse[frm.pse_tos].level > pc->level))
                indent_pse_pop(frm, pc);

            if (frm.pse[frm.pse_tos].level == pc->level)
            {
                /* process virtual braces closes (no text output) */
                if ((pc->type == CT_VBRACE_CLOSE) &&
                        (frm.pse[frm.pse_tos].type == CT_VBRACE_OPEN))
                {
                    indent_pse_pop(frm, pc);
                    frm.level--;
                    pc = chunk_get_next(pc);
                }

                /* End any assign operations with a semicolon on the same level */
                if ((frm.pse[frm.pse_tos].type == CT_ASSIGN) &&
                        (chunk_is_semicolon(pc) ||
                         (pc->type == CT_COMMA) ||
                         (pc->type == CT_BRACE_OPEN)))
                    indent_pse_pop(frm, pc);

                /* End any CPP class colon crap */
                if ((frm.pse[frm.pse_tos].type == CT_CLASS_COLON) &&
                        ((pc->type == CT_BRACE_OPEN) ||
                         chunk_is_semicolon(pc)))
                    indent_pse_pop(frm, pc);

                /* a case is ended with another case or a close brace */
                if ((frm.pse[frm.pse_tos].type == CT_CASE) &&
                        ((pc->type == CT_BRACE_CLOSE) ||
                         (pc->type == CT_CASE)))
                    indent_pse_pop(frm, pc);

                /* a return is ended with a semicolon */
                if ((frm.pse[frm.pse_tos].type == CT_RETURN) &&
                        chunk_is_semicolon(pc))
                    indent_pse_pop(frm, pc);

                /* Close out parens and squares */
                if ((frm.pse[frm.pse_tos].type == (pc->type - 1)) &&
                        ((pc->type == CT_PAREN_CLOSE) ||
                         (pc->type == CT_SPAREN_CLOSE) ||
                         (pc->type == CT_FPAREN_CLOSE) ||
                         (pc->type == CT_SQUARE_CLOSE) ||
                         (pc->type == CT_ANGLE_CLOSE)))
                {
                    indent_pse_pop(frm, pc);
                    frm.paren_count--;
                }
            }
        }
        while (old_pse_tos > frm.pse_tos);

        /* Grab a copy of the current indent */
        indent_column = frm.pse[frm.pse_tos].indent_tmp;

        if (!chunk_is_newline(pc) && !chunk_is_comment(pc))
        {
            LOG_FMT(LINDPC, " -=[ %.*s ]=- top=%d %s %d/%d\n",
                    pc->len, pc->str,
                    frm.pse_tos,
                    get_token_name(frm.pse[frm.pse_tos].type),
                    frm.pse[frm.pse_tos].indent_tmp,
                    frm.pse[frm.pse_tos].indent);
        }

        /**
         * Handle stuff that can affect the current indent:
         *  - brace close
         *  - vbrace open
         *  - brace open
         *  - case         (immediate)
         *  - labels       (immediate)
         *  - class colons (immediate)
         *
         * And some stuff that can't
         *  - open paren
         *  - open square
         *  - assignment
         *  - return
         */

        if (pc->type == CT_BRACE_CLOSE)
        {
            if (frm.pse[frm.pse_tos].type == CT_BRACE_OPEN)
            {
                indent_pse_pop(frm, pc);
                frm.level--;

                /* Update the indent_column if needed */
                if (!cpd.settings[UO_indent_braces].b &&
                        (parent_token_indent == 0))
                    indent_column = frm.pse[frm.pse_tos].indent_tmp;

                if ((pc->parent_type == CT_IF) ||
                        (pc->parent_type == CT_ELSE) ||
                        (pc->parent_type == CT_ELSEIF) ||
                        (pc->parent_type == CT_DO) ||
                        (pc->parent_type == CT_WHILE) ||
                        (pc->parent_type == CT_SWITCH) ||
                        (pc->parent_type == CT_FOR))
                    indent_column += cpd.settings[UO_indent_brace].n;
            }
        }
        else if (pc->type == CT_VBRACE_OPEN)
        {
            frm.level++;
            indent_pse_push(frm, pc);

            frm.pse[frm.pse_tos].indent     = frm.pse[frm.pse_tos - 1].indent + indent_size;
            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;

            /* Always indent on virtual braces */
            indent_column = frm.pse[frm.pse_tos].indent_tmp;
        }
        else if (pc->type == CT_BRACE_OPEN)
        {
            frm.level++;
            indent_pse_push(frm, pc);

            if (frm.paren_count != 0)
                /* We are inside ({ ... }) -- indent one tab from the paren */
                frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
            else
            {
                /* Use the prev indent level + indent_size. */
                frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;

                /* If this brace is part of a statement, bump it out by indent_brace */
                if ((pc->parent_type == CT_IF) ||
                        (pc->parent_type == CT_ELSE) ||
                        (pc->parent_type == CT_ELSEIF) ||
                        (pc->parent_type == CT_DO) ||
                        (pc->parent_type == CT_WHILE) ||
                        (pc->parent_type == CT_SWITCH) ||
                        (pc->parent_type == CT_FOR))
                {
                    if (parent_token_indent != 0)
                        frm.pse[frm.pse_tos].indent += parent_token_indent - indent_size;
                    else
                    {
                        frm.pse[frm.pse_tos].indent += cpd.settings[UO_indent_brace].n;
                        indent_column += cpd.settings[UO_indent_brace].n;
                    }
                }
                else if (pc->parent_type == CT_CASE)
                {
                    /* The indent_case_brace setting affects the parent CT_CASE */
                    frm.pse[frm.pse_tos].indent_tmp += cpd.settings[UO_indent_case_brace].n;
                    frm.pse[frm.pse_tos].indent     += cpd.settings[UO_indent_case_brace].n;
                }
                else if ((pc->parent_type == CT_CLASS) && !cpd.settings[UO_indent_class].b)
                    frm.pse[frm.pse_tos].indent -= indent_size;
                else if ((pc->parent_type == CT_NAMESPACE) && !cpd.settings[UO_indent_namespace].b)
                    frm.pse[frm.pse_tos].indent -= indent_size;
            }

            if ((pc->flags & PCF_DONT_INDENT) != 0)
            {
                frm.pse[frm.pse_tos].indent = pc->column;
                indent_column = pc->column;
            }
            else
            {
                /**
                 * If there isn't a newline between the open brace and the next
                 * item, just indent to wherever the next token is.
                 * This covers this sort of stuff:
                 * { a++;
                 *   b--; };
                 */
                next = chunk_get_next_ncnl(pc);

                if (!chunk_is_newline_between(pc, next))
                    frm.pse[frm.pse_tos].indent = next->column;

                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
                frm.pse[frm.pse_tos].open_line  = pc->orig_line;

                /* Update the indent_column if needed */
                if (cpd.settings[UO_indent_braces].n ||
                        (parent_token_indent != 0))
                    indent_column = frm.pse[frm.pse_tos].indent_tmp;
            }
        }
        else if (pc->type == CT_CASE)
        {
            /* Start a case - indent UO_indent_switch_case from the switch level */
            tmp = frm.pse[frm.pse_tos].indent + cpd.settings[UO_indent_switch_case].n;

            indent_pse_push(frm, pc);

            frm.pse[frm.pse_tos].indent     = tmp;
            frm.pse[frm.pse_tos].indent_tmp = tmp - indent_size;

            /* Always set on case statements */
            indent_column = frm.pse[frm.pse_tos].indent_tmp;
        }
        else if (pc->type == CT_LABEL)
        {
            /* Labels get sent to the left or backed up */
            if (cpd.settings[UO_indent_label].n > 0)
                indent_column = cpd.settings[UO_indent_label].n;
            else
                indent_column = frm.pse[frm.pse_tos].indent +
                                cpd.settings[UO_indent_label].n;
        }
        else if (pc->type == CT_CLASS_COLON)
        {
            /* just indent one level */
            indent_pse_push(frm, pc);
            frm.pse[frm.pse_tos].indent     = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;

            indent_column = frm.pse[frm.pse_tos].indent_tmp;

            if (cpd.settings[UO_indent_class_colon].b)
            {
                prev = chunk_get_prev(pc);

                if (chunk_is_newline(prev))
                    frm.pse[frm.pse_tos].indent += 2;
                /* don't change indent of current line */
            }
        }
        else if ((pc->type == CT_PAREN_OPEN) ||
                 (pc->type == CT_SPAREN_OPEN) ||
                 (pc->type == CT_FPAREN_OPEN) ||
                 (pc->type == CT_SQUARE_OPEN) ||
                 (pc->type == CT_ANGLE_OPEN))
        {
            /* Open parens and squares - never update indent_column */
            indent_pse_push(frm, pc);
            frm.pse[frm.pse_tos].indent = pc->column + pc->len;

            if (cpd.settings[UO_indent_func_call_param].b &&
                    (pc->type == CT_FPAREN_OPEN) &&
                    (pc->parent_type == CT_FUNC_CALL))
                frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent + indent_size;

            if ((chunk_is_str(pc, "(", 1) && !cpd.settings[UO_indent_paren_nl].b) ||
                    (chunk_is_str(pc, "[", 1) && !cpd.settings[UO_indent_square_nl].b))
            {
                next = chunk_get_next_nc(pc);

                if (chunk_is_newline(next))
                {
                    int sub = 1;

                    if (frm.pse[frm.pse_tos - 1].type == CT_ASSIGN)
                        sub = 2;

                    frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - sub].indent + indent_size;
                }
            }

            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
            frm.paren_count++;
        }
        else if (pc->type == CT_ASSIGN)
        {
            /**
             * if there is a newline after the '=', just indent one level,
             * otherwise align on the '='.
             * Never update indent_column.
             */
            next = chunk_get_next(pc);

            if (next != NULL)
            {
                indent_pse_push(frm, pc);

                if (chunk_is_newline(next))
                    frm.pse[frm.pse_tos].indent = frm.pse[frm.pse_tos - 1].indent_tmp + indent_size;
                else
                    frm.pse[frm.pse_tos].indent = pc->column + pc->len + 1;

                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;
            }
        }
        else if (pc->type == CT_RETURN)
        {
            /* don't count returns inside a () or [] */
            if (pc->level == pc->brace_level)
            {
                indent_pse_push(frm, pc);
                frm.pse[frm.pse_tos].indent     = frm.pse[frm.pse_tos - 1].indent + pc->len + 1;
                frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos - 1].indent;
            }
        }
        else if (chunk_is_str(pc, "<<", 2))
        {
            if (cout_col == 0)
            {
                cout_col   = pc->column;
                cout_level = pc->level;
            }
        }
        else
        {
            /* anything else? */
        }

        /**
         * Indent the line if needed
         */
        if (did_newline && !chunk_is_newline(pc) && (pc->len != 0))
        {
            /**
             * Check for special continuations.
             * Note that some of these could be done as a stack item like
             * everything else
             */

            prev = chunk_get_prev_ncnl(pc);

            if ((pc->type == CT_MEMBER) ||
                    (pc->type == CT_DC_MEMBER) ||
                    ((prev != NULL) &&
                     ((prev->type == CT_MEMBER) ||
                      (prev->type == CT_DC_MEMBER))))
            {
                tmp = cpd.settings[UO_indent_member].n + indent_column;
                LOG_FMT(LINDENT, "%s: %d] member => %d\n",
                        __func__, pc->orig_line, tmp);
                reindent_line(pc, tmp);
            }
            else if (chunk_is_str(pc, "<<", 2) && (cout_col > 0))
            {
                LOG_FMT(LINDENT, "%s: %d] cout_col => %d\n",
                        __func__, pc->orig_line, cout_col);
                reindent_line(pc, cout_col);
            }
            else if ((vardefcol > 0) &&
                     (pc->type == CT_WORD) &&
                     ((pc->flags & PCF_VAR_DEF) != 0) &&
                     (prev != NULL) && (prev->type == CT_COMMA))
            {
                LOG_FMT(LINDENT, "%s: %d] Vardefcol => %d\n",
                        __func__, pc->orig_line, vardefcol);
                reindent_line(pc, vardefcol);
            }
            else if ((pc->type == CT_STRING) && (prev->type == CT_STRING) &&
                     cpd.settings[UO_indent_align_string].b)
            {
                LOG_FMT(LINDENT, "%s: %d] String => %d\n",
                        __func__, pc->orig_line, prev->column);
                reindent_line(pc, prev->column);
            }
            else if (chunk_is_comment(pc))
            {
                LOG_FMT(LINDENT, "%s: %d] comment => %d\n",
                        __func__, pc->orig_line, frm.pse[frm.pse_tos].indent_tmp);
                indent_comment(pc, frm.pse[frm.pse_tos].indent_tmp);
            }
            else if (pc->type == CT_PREPROC)
            {
                /* Preprocs are always in column 1. See indent_preproc() */
                if (pc->column != 1)
                    reindent_line(pc, 1);
            }
            else
            {
                if (pc->column != indent_column)
                {
                    LOG_FMT(LINDENT, "%s: %d] indent => %d [%.*s]\n",
                            __func__, pc->orig_line, indent_column, pc->len, pc->str);
                    reindent_line(pc, indent_column);
                }
            }

            did_newline = false;
        }

        /**
         * Handle variable definition continuation indenting
         */
        if ((pc->type == CT_WORD) &&
                ((pc->flags & PCF_IN_FCN_DEF) == 0) &&
                ((pc->flags & PCF_VAR_1ST_DEF) == PCF_VAR_1ST_DEF))
            vardefcol = pc->column;

        if (chunk_is_semicolon(pc) ||
                ((pc->type == CT_BRACE_OPEN) && (pc->parent_type == CT_FUNCTION)))
            vardefcol = 0;

        /* if we hit a newline, reset indent_tmp */
        if (chunk_is_newline(pc) ||
                (pc->type == CT_COMMENT_MULTI) ||
                (pc->type == CT_COMMENT_CPP))
        {
            frm.pse[frm.pse_tos].indent_tmp = frm.pse[frm.pse_tos].indent;

            /**
             * Handle the case of a multi-line #define w/o anything on the
             * first line (indent_tmp will be 1 or 0)
             */
            if ((pc->type == CT_NL_CONT) &&
                    (frm.pse[frm.pse_tos].indent_tmp <= indent_size))
                frm.pse[frm.pse_tos].indent_tmp = indent_size + 1;

            /* Get ready to indent the next item */
            did_newline = true;
        }

        if (!chunk_is_comment(pc) && !chunk_is_newline(pc))
            prev = pc;

        pc = chunk_get_next(pc);
    }

    /* Throw out any stuff inside a preprocessor - no need to warn */
    while ((frm.pse_tos > 0) && frm.pse[frm.pse_tos].in_preproc)
        indent_pse_pop(frm, pc);

    for (idx = 1; idx <= frm.pse_tos; idx++)
    {
        LOG_FMT(LWARN, "%s:%d Unmatched %s\n",
                cpd.filename, frm.pse[idx].open_line,
                get_token_name(frm.pse[idx].type));
        cpd.error_count++;
    }
}
예제 #24
0
/**
 * Figures out where to split a function def/proto/call
 *
 * For fcn protos and defs. Also fcn calls where level == brace_level:
 *   - find the open fparen
 *     + if it doesn't have a newline right after it
 *       * see if all parameters will fit individually after the paren
 *       * if not, throw a newline after the open paren & return
 *   - scan backwards to the open fparen or comma
 *     + if there isn't a newline after that item, add one & return
 *     + otherwise, add a newline before the start token
 *
 * @param start   the offending token
 * @return        the token that should have a newline
 *                inserted before it
 */
static void split_fcn_params(chunk_t *start)
{
   LOG_FUNC_ENTRY();
   LOG_FMT(LSPLIT, "  %s: ", __func__);

   chunk_t *prev;
   chunk_t *fpo;
   chunk_t *pc;
   int     cur_width = 0;
   int     last_col  = -1;
   int     min_col;

   /* Find the opening fparen */
   fpo = start;
   while (((fpo = chunk_get_prev(fpo)) != NULL) &&
          (fpo->type != CT_FPAREN_OPEN))
   {
      /* do nothing */
   }

   pc      = chunk_get_next_ncnl(fpo);
   min_col = pc->column;

   LOG_FMT(LSPLIT, " mincol=%d, max_width=%d ",
           min_col, cpd.settings[UO_code_width].n - min_col);

   while (pc != NULL)
   {
      if (chunk_is_newline(pc))
      {
         cur_width = 0;
         last_col  = -1;
      }
      else
      {
         if (last_col < 0)
         {
            last_col = pc->column;
         }
         cur_width += (pc->column - last_col) + pc->len();
         last_col   = pc->column + pc->len();

         if ((pc->type == CT_COMMA) ||
             (pc->type == CT_FPAREN_CLOSE))
         {
            cur_width--;
            LOG_FMT(LSPLIT, " width=%d ", cur_width);
            if (((last_col - 1) > cpd.settings[UO_code_width].n) ||
                (pc->type == CT_FPAREN_CLOSE))
            {
               break;
            }
         }
      }
      pc = chunk_get_next(pc);
   }

   /* back up until the prev is a comma */
   prev = pc;
   while ((prev = chunk_get_prev(prev)) != NULL)
   {
      if (chunk_is_newline(prev) || (prev->type == CT_COMMA))
      {
         break;
      }
      last_col -= pc->len();
      if (prev->type == CT_FPAREN_OPEN)
      {
         pc = chunk_get_next(prev);
         if (!cpd.settings[UO_indent_paren_nl].b)
         {
            min_col = pc->brace_level * cpd.settings[UO_indent_columns].n + 1;
            if (cpd.settings[UO_indent_continue].n == 0)
            {
               min_col += cpd.settings[UO_indent_columns].n;
            }
            else
            {
               min_col += abs(cpd.settings[UO_indent_continue].n);
            }
         }
         /* Don't split "()" */
         if (pc->type != c_token_t(prev->type + 1))
         {
            break;
         }
      }
   }
   if ((prev != NULL) && !chunk_is_newline(prev))
   {
      LOG_FMT(LSPLIT, " -- ended on [%s] --\n", get_token_name(prev->type));
      pc = chunk_get_next(prev);
      newline_add_before(pc);
      reindent_line(pc, min_col);
      cpd.changes++;
   }
} // split_fcn_params
예제 #25
0
void remove_extra_semicolons(void)
{
   LOG_FUNC_ENTRY();

   chunk_t *pc = chunk_get_head();
   while (pc != nullptr)
   {
      chunk_t *next = chunk_get_next_ncnl(pc);
      chunk_t *prev;
      if (  pc->type == CT_SEMICOLON
         && !(pc->flags & PCF_IN_PREPROC)
         && (prev = chunk_get_prev_ncnl(pc)) != nullptr)
      {
         LOG_FMT(LSCANSEMI, "Semi on %zu:%zu parent=%s, prev = '%s' [%s/%s]\n",
                 pc->orig_line, pc->orig_col, get_token_name(pc->parent_type),
                 prev->text(),
                 get_token_name(prev->type), get_token_name(prev->parent_type));

         if (pc->parent_type == CT_TYPEDEF)
         {
            // keep it
         }
         else if (  prev->type == CT_BRACE_CLOSE
                 && (  prev->parent_type == CT_IF
                    || prev->parent_type == CT_ELSEIF
                    || prev->parent_type == CT_ELSE
                    || prev->parent_type == CT_SWITCH
                    || prev->parent_type == CT_WHILE
                    || prev->parent_type == CT_USING_STMT
                    || prev->parent_type == CT_FOR
                    || prev->parent_type == CT_FUNC_DEF
                    || prev->parent_type == CT_OC_MSG_DECL
                    || prev->parent_type == CT_FUNC_CLASS_DEF
                    || prev->parent_type == CT_NAMESPACE))
         {
            LOG_FUNC_CALL();
            remove_semicolon(pc);
         }
         else if (  prev->type == CT_BRACE_CLOSE
                 && prev->parent_type == CT_NONE)
         {
            check_unknown_brace_close(pc, prev);
         }
         else if (prev->type == CT_SEMICOLON && prev->parent_type != CT_FOR)
         {
            LOG_FUNC_CALL();
            remove_semicolon(pc);
         }
         else if (  (cpd.lang_flags & LANG_D)
                 && (  prev->parent_type == CT_ENUM
                    || prev->parent_type == CT_UNION
                    || prev->parent_type == CT_STRUCT))
         {
            LOG_FUNC_CALL();
            remove_semicolon(pc);
         }
         else if (  (cpd.lang_flags & LANG_JAVA)
                 && prev->parent_type == CT_SYNCHRONIZED)
         {
            LOG_FUNC_CALL();
            remove_semicolon(pc);
         }
         else if (prev->type == CT_BRACE_OPEN)
         {
            LOG_FUNC_CALL();
            remove_semicolon(pc);
         }
      }

      pc = next;
   }
} // remove_extra_semicolons
예제 #26
0
파일: width.cpp 프로젝트: CDanU/uncrustify
static void split_fcn_params(chunk_t *start)
{
   LOG_FUNC_ENTRY();
   LOG_FMT(LSPLIT, "%s(%d): '%s'\n", __func__, __LINE__, start->text());

   // Find the opening function parenthesis
   chunk_t *fpo = start;
   LOG_FMT(LSPLIT, "%s(%d): Find the opening function parenthesis\n", __func__, __LINE__);
   while (  ((fpo = chunk_get_prev(fpo)) != nullptr)
         && fpo->type != CT_FPAREN_OPEN)
   {
      // do nothing
      LOG_FMT(LSPLIT, "%s(%d): '%s', orig_col is %zu, level is %zu\n",
              __func__, __LINE__, fpo->text(), fpo->orig_col, fpo->level);
   }

   chunk_t *pc     = chunk_get_next_ncnl(fpo);
   size_t  min_col = pc->column;

   LOG_FMT(LSPLIT, "    mincol is %zu, max_width is %zu\n",
           min_col, cpd.settings[UO_code_width].u - min_col);

   int cur_width = 0;
   int last_col  = -1;
   LOG_FMT(LSPLIT, "%s(%d):look forward until CT_COMMA or CT_FPAREN_CLOSE\n", __func__, __LINE__);
   while (pc != nullptr)
   {
      LOG_FMT(LSPLIT, "%s(%d): pc->text() '%s', type is %s\n",
              __func__, __LINE__, pc->text(), get_token_name(pc->type));
      if (chunk_is_newline(pc))
      {
         cur_width = 0;
         last_col  = -1;
      }
      else
      {
         if (last_col < 0)
         {
            last_col = pc->column;
            LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
                    __func__, __LINE__, last_col);
         }
         cur_width += (pc->column - last_col) + pc->len();
         last_col   = pc->column + pc->len();

         LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
                 __func__, __LINE__, last_col);
         if (pc->type == CT_COMMA || pc->type == CT_FPAREN_CLOSE)
         {
            cur_width--;
            LOG_FMT(LSPLIT, "%s(%d): cur_width is %d\n",
                    __func__, __LINE__, cur_width);
            if (  ((last_col - 1) > static_cast<int>(cpd.settings[UO_code_width].u))
               || pc->type == CT_FPAREN_CLOSE)
            {
               break;
            }
         }
      }
      pc = chunk_get_next(pc);
   }

   // back up until the prev is a comma
   chunk_t *prev = pc;
   LOG_FMT(LSPLIT, "  %s(%d): back up until the prev is a comma\n", __func__, __LINE__);
   while ((prev = chunk_get_prev(prev)) != nullptr)
   {
      LOG_FMT(LSPLIT, "%s(%d): pc '%s', pc->level is %zu, prev '%s', prev->type is %s\n",
              __func__, __LINE__, pc->text(), pc->level, prev->text(), get_token_name(prev->type));
      if (chunk_is_newline(prev) || prev->type == CT_COMMA)
      {
         LOG_FMT(LSPLIT, "%s(%d): found at %zu\n",
                 __func__, __LINE__, prev->orig_col);
         break;
      }
      LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
              __func__, __LINE__, last_col);
      last_col -= pc->len();
      LOG_FMT(LSPLIT, "%s(%d): last_col is %d\n",
              __func__, __LINE__, last_col);
      if (prev->type == CT_FPAREN_OPEN)
      {
         pc = chunk_get_next(prev);
         if (!cpd.settings[UO_indent_paren_nl].b)
         {
            min_col = pc->brace_level * cpd.settings[UO_indent_columns].u + 1;
            LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n",
                    __func__, __LINE__, min_col);
            if (cpd.settings[UO_indent_continue].n == 0)
            {
               min_col += cpd.settings[UO_indent_columns].u;
            }
            else
            {
               min_col += abs(cpd.settings[UO_indent_continue].n);
            }
            LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n",
                    __func__, __LINE__, min_col);
         }

         // Don't split "()"
         if (pc->type != c_token_t(prev->type + 1))
         {
            break;
         }
      }
   }
   if (prev != nullptr && !chunk_is_newline(prev))
   {
      LOG_FMT(LSPLIT, "%s(%d): -- ended on [%s] --\n",
              __func__, __LINE__, get_token_name(prev->type));
      LOG_FMT(LSPLIT, "%s(%d): min_col is %zu\n",
              __func__, __LINE__, min_col);
      pc = chunk_get_next(prev);
      newline_add_before(pc);
      reindent_line(pc, min_col);
      cpd.changes++;
   }
} // split_fcn_params
예제 #27
0
void tokenize_cleanup(void)
{
   chunk_t *pc   = chunk_get_head();
   chunk_t *prev = NULL;
   chunk_t *next;
   chunk_t *tmp;
   chunk_t *tmp2;
   bool    in_type_cast = false;

   pc   = chunk_get_head();
   next = chunk_get_next_ncnl(pc);
   while ((pc != NULL) && (next != NULL))
   {
      /* Change '[' + ']' into '[]' */
      if ((pc->type == CT_SQUARE_OPEN) && (next->type == CT_SQUARE_CLOSE))
      {
         pc->type = CT_TSQUARE;
         pc->str  = "[]";
         pc->len  = 2;
         chunk_del(next);
         pc->orig_col_end += 1;
         next              = chunk_get_next_ncnl(pc);
      }

      if ((pc->type == CT_DOT) && ((cpd.lang_flags & LANG_ALLC) != 0))
      {
         pc->type = CT_MEMBER;
      }

      /* Determine the version stuff (D only) */
      if (pc->type == CT_VERSION)
      {
         if (next->type == CT_PAREN_OPEN)
         {
            pc->type = CT_IF;
         }
         else
         {
            if (next->type != CT_ASSIGN)
            {
               LOG_FMT(LERR, "%s:%d %s: version: Unexpected token %s\n",
                       cpd.filename, pc->orig_line, __func__, get_token_name(next->type));
               cpd.error_count++;
            }
            pc->type = CT_WORD;
         }
      }

      /**
       * Change CT_BASE before CT_PAREN_OPEN to CT_WORD.
       * public myclass() : base() {
       * }
       */
      if ((pc->type == CT_BASE) && (next->type == CT_PAREN_OPEN))
      {
         pc->type = CT_WORD;
      }

      /**
       * Change CT_WORD after CT_ENUM, CT_UNION, or CT_STRUCT to CT_TYPE
       * Change CT_WORD before CT_WORD to CT_TYPE
       */
      if (next->type == CT_WORD)
      {
         if ((pc->type == CT_ENUM) ||
             (pc->type == CT_UNION) ||
             (pc->type == CT_STRUCT))
         {
            next->type = CT_TYPE;
         }
         if (pc->type == CT_WORD)
         {
            pc->type = CT_TYPE;
         }
      }

      /* change extern to qualifier if extern isn't followed by a string or
       * an open paren
       */
      if (pc->type == CT_EXTERN)
      {
         if (next->type == CT_STRING)
         {
            /* Probably 'extern "C"' */
         }
         else if (next->type == CT_PAREN_OPEN)
         {
            /* Probably 'extern (C)' */
         }
         else
         {
            /* Something else followed by a open brace */
            tmp = chunk_get_next_ncnl(next);
            if ((tmp != NULL) || (tmp->type != CT_BRACE_OPEN))
            {
               pc->type = CT_QUALIFIER;
            }
         }
      }

      /**
       * Change CT_STAR to CT_PTR_TYPE if preceded by CT_TYPE,
       * CT_QUALIFIER, or CT_PTR_TYPE.
       */
      if ((next->type == CT_STAR) &&
          ((pc->type == CT_TYPE) ||
           (pc->type == CT_QUALIFIER) ||
           (pc->type == CT_PTR_TYPE)))
      {
         next->type = CT_PTR_TYPE;
      }

      if ((pc->type == CT_TYPE_CAST) &&
          (next->type == CT_ANGLE_OPEN))
      {
         next->parent_type = CT_TYPE_CAST;
         in_type_cast      = true;
      }

      /**
       * Change angle open/close to CT_COMPARE, if not a template thingy
       */
      if ((pc->type == CT_ANGLE_OPEN) && (pc->parent_type != CT_TYPE_CAST))
      {
         check_template(pc);
      }
      if ((pc->type == CT_ANGLE_CLOSE) && (pc->parent_type != CT_TEMPLATE))
      {
         if (in_type_cast)
         {
            in_type_cast    = false;
            pc->parent_type = CT_TYPE_CAST;
         }
         else
         {
            pc->type = CT_COMPARE;
         }
      }

      if ((cpd.lang_flags & LANG_D) != 0)
      {
         /* Check for the D string concat symbol '~' */
         if ((pc->type == CT_INV) &&
             ((prev->type == CT_STRING) ||
              (prev->type == CT_WORD) ||
              (next->type == CT_STRING)))
         {
            pc->type = CT_CONCAT;
         }

         /* Check for the D template symbol '!' */
         if ((pc->type == CT_NOT) &&
             (prev->type == CT_WORD) &&
             (next->type == CT_PAREN_OPEN))
         {
            pc->type = CT_D_TEMPLATE;
         }
      }

      if ((cpd.lang_flags & LANG_CPP) != 0)
      {
         /* Change Word before '::' into a type */
         if ((pc->type == CT_WORD) && (next->type == CT_DC_MEMBER))
         {
            pc->type = CT_TYPE;
         }
      }

      /* Change get/set to CT_WORD if not followed by a brace open */
      if ((pc->type == CT_GETSET) && (next->type != CT_BRACE_OPEN))
      {
         if ((next->type == CT_SEMICOLON) &&
             ((prev->type == CT_BRACE_CLOSE) ||
              (prev->type == CT_BRACE_OPEN) ||
              (prev->type == CT_SEMICOLON)))
         {
            pc->type          = CT_GETSET_EMPTY;
            next->parent_type = CT_GETSET;
         }
         else
         {
            pc->type = CT_WORD;
         }
      }

      /* Change item after operator (>=, ==, etc) to a CT_OPERATOR_VAL
       * Usually the next item is part of the operator.
       * In a few cases the next few tokens are part of it:
       *  operator +       - common case
       *  operator ()
       *  operator []      - already converted to TSQUARE
       *  operator new []
       *  operator delete []
       *  operator const char *
       * This will put the entire operator value in one chunk.
       */
      if (pc->type == CT_OPERATOR)
      {
         /* Handle special case of () operator -- [] already handled */
         if (next->type == CT_PAREN_OPEN)
         {
            tmp = chunk_get_next(next);
            if ((tmp != NULL) && (tmp->type == CT_PAREN_CLOSE))
            {
               next->str  = "()";
               next->len  = 2;
               next->type = CT_OPERATOR_VAL;
               chunk_del(tmp);
               next->orig_col_end += 1;
            }
         }
         else if (next->flags & PCF_PUNCTUATOR)
         {
            next->type = CT_OPERATOR_VAL;
         }
         else
         {
            next->type = CT_TYPE;

            /* Replace next with a collection of all tokens that are part of
             * the type.
             */
            char opbuf[256];
            int  len;

            len = snprintf(opbuf, sizeof(opbuf), "%.*s",
                           next->len, next->str);

            tmp2 = next;
            while ((tmp = chunk_get_next(tmp2)) != NULL)
            {
               if ((tmp->type != CT_WORD) &&
                   (tmp->type != CT_TYPE) &&
                   (tmp->type != CT_QUALIFIER) &&
                   (tmp->type != CT_STAR) &&
                   (tmp->type != CT_AMP) &&
                   (tmp->type != CT_TSQUARE))
               {
                  break;
               }
               len += snprintf(opbuf + len, sizeof(opbuf) - len, "%s%.*s",
                               space_needed(tmp2, tmp) ? " " : "",
                               tmp->len, tmp->str);
               tmp2 = tmp;
            }

            while ((tmp2 = chunk_get_next(next)) != tmp)
            {
               chunk_del(tmp2);
            }

            next->str    = strdup(opbuf);
            next->len    = len;
            next->flags |= PCF_OWN_STR;
            next->type   = CT_OPERATOR_VAL;

            next->orig_col_end = next->orig_col + next->len;
         }
         next->parent_type = CT_OPERATOR;

         LOG_FMT(LOPERATOR, "%s: %d:%d operator '%.*s'\n",
                 __func__, pc->orig_line, pc->orig_col,
                 next->len, next->str);
      }

      /* Change private, public, protected into either a qualifier or label */
      if (pc->type == CT_PRIVATE)
      {
         /* Handle Qt slots - maybe should just check for a CT_WORD? */
         if (chunk_is_str(next, "slots", 5))
         {
            tmp = chunk_get_next(next);
            if ((tmp != NULL) && (tmp->type == CT_COLON))
            {
               next = tmp;
            }
         }
         if (next->type == CT_COLON)
         {
            next->type = CT_PRIVATE_COLON;
            if ((tmp = chunk_get_next_ncnl(next)) != NULL)
            {
               tmp->flags |= PCF_STMT_START | PCF_EXPR_START;
            }
         }
         else
         {
            pc->type = chunk_is_str(pc, "signals", 7) ? CT_WORD : CT_QUALIFIER;
         }
      }

      /* Look for <newline> 'EXEC' 'SQL' */
      if (chunk_is_str(pc, "EXEC", 4) && chunk_is_str(next, "SQL", 3))
      {
         tmp = chunk_get_prev(pc);
         if (chunk_is_newline(tmp))
         {
            tmp = chunk_get_next(next);
            if (chunk_is_str_case(tmp, "BEGIN", 5))
            {
               pc->type = CT_SQL_BEGIN;
            }
            else if (chunk_is_str_case(tmp, "END", 3))
            {
               pc->type = CT_SQL_END;
            }
            else
            {
               pc->type = CT_SQL_EXEC;
            }

            /* Change words into CT_SQL_WORD until CT_SEMICOLON */
            while (tmp != NULL)
            {
               if (tmp->type == CT_SEMICOLON)
               {
                  break;
               }
               if ((tmp->len > 0) && isalpha(*tmp->str))
               {
                  tmp->type = CT_SQL_WORD;
               }
               tmp = chunk_get_next_ncnl(tmp);
            }
         }
      }

      /* Detect Objective C class name */
      if ((pc->type == CT_OC_IMPL) || (pc->type == CT_OC_INTF))
      {
         next->type        = CT_OC_CLASS;
         next->parent_type = pc->type;

         tmp = chunk_get_next_ncnl(next);
         if (tmp != NULL)
         {
            tmp->flags |= PCF_STMT_START | PCF_EXPR_START;
         }

         tmp = chunk_get_next_type(pc, CT_OC_END, pc->level);
         if (tmp != NULL)
         {
            tmp->parent_type = pc->type;
         }
      }

      /* Detect Objective-C categories and class extensions */
      /* @interface ClassName (CategoryName) */
      /* @implementation ClassName (CategoryName) */
      /* @interface ClassName () */
      /* @implementation ClassName () */
      if (((pc->parent_type == CT_OC_IMPL) ||
           (pc->parent_type == CT_OC_INTF) ||
           (pc->type == CT_OC_CLASS)) &&
          (next->type == CT_PAREN_OPEN))
      {
         next->parent_type = pc->parent_type;

         tmp = chunk_get_next(next);
         if ((tmp != NULL) && (tmp->next != NULL))
         {
            if (tmp->type == CT_PAREN_CLOSE)
            {
               tmp->type        = CT_OC_CLASS_EXT;
               tmp->parent_type = pc->parent_type;
            }
            else
            {
               tmp->type        = CT_OC_CATEGORY;
               tmp->parent_type = pc->parent_type;
            }
         }

         tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level);
         if (tmp != NULL)
         {
            tmp->parent_type = pc->parent_type;
         }
      }

      /**
       * Objective C @dynamic and @synthesize
       *  @dynamic xxx, yyy;
       *  @synthesize xxx, yyy;
       * Just find the semicolon and mark it.
       */
      if (pc->type == CT_OC_DYNAMIC)
      {
         tmp = chunk_get_next_type(pc, CT_SEMICOLON, pc->level);
         if (tmp != NULL)
         {
            tmp->parent_type = pc->type;
         }
      }

      /* Detect Objective C @property
       *  @property NSString *stringProperty;
       *  @property(nonatomic, retain) NSMutableDictionary *shareWith;
       */
      if (pc->type == CT_OC_PROPERTY)
      {
         if (next->type != CT_PAREN_OPEN)
         {
            next->flags |= PCF_STMT_START | PCF_EXPR_START;
         }
         else
         {
            next->parent_type = pc->type;

            tmp = chunk_get_next_type(pc, CT_PAREN_CLOSE, pc->level);
            if (tmp != NULL)
            {
               tmp->parent_type = pc->type;
               tmp = chunk_get_next_ncnl(tmp);
               if (tmp != NULL)
               {
                  tmp->flags |= PCF_STMT_START | PCF_EXPR_START;

                  tmp = chunk_get_next_type(tmp, CT_SEMICOLON, pc->level);
                  if (tmp != NULL)
                  {
                     tmp->parent_type = pc->type;
                  }
               }
            }
         }
      }

      /* Detect Objective C @selector
       *  @selector(msgNameWithNoArg)
       *  @selector(msgNameWith1Arg:)
       *  @selector(msgNameWith2Args:arg2Name:)
       */
      if ((pc->type == CT_OC_SEL) && (next->type == CT_PAREN_OPEN))
      {
         next->parent_type = pc->type;

         tmp = chunk_get_next(next);
         if (tmp != NULL)
         {
            tmp->type        = CT_OC_SEL_NAME;
            tmp->parent_type = pc->type;

            while ((tmp = chunk_get_next_ncnl(tmp)) != NULL)
            {
               if (tmp->type == CT_PAREN_CLOSE)
               {
                  tmp->parent_type = CT_OC_SEL;
                  break;
               }
               tmp->type        = CT_OC_SEL_NAME;
               tmp->parent_type = pc->type;
            }
         }
      }

      /* Mark Objective-C blocks (aka lambdas or closures)
       *  The syntax and usage is exactly like C function pointers with two exceptions:
       *  Instead of an asterisk they have a caret as pointer symbol.
       *  In method declarations which take a block as parameter, there can be anonymous blocks, e.g.: (^)
       *  1. block literal: ^{ ... };
       *  2. block declaration: return_t (^name) (int arg1, int arg2, ...) NB: return_t is optional and name can be optional if found as param in a method declaration.
       *  3. block expression: ^ return_t (int arg) { ... }; NB: return_t is optional
       *
       *  See http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Blocks for more info...
       */
      if ((cpd.lang_flags & LANG_OC) &&
          (pc->type == CT_ARITH) &&
          (chunk_is_str(pc, "^", 1)) &&
          (prev->type != CT_NUMBER) &&
          (prev->type != CT_NUMBER_FP))
      {
         /* mark objc blocks caret so that we can process it later*/
         pc->type = CT_OC_BLOCK_CARET;

         if (prev->type == CT_PAREN_OPEN)
         {
            /* block declaration */
            pc->parent_type = CT_OC_BLOCK_TYPE;
         }
         else if ((next->type == CT_PAREN_OPEN) ||
                  (next->type == CT_BRACE_OPEN))
         {
            /* block expression without return type */
            /* block literal */
            pc->parent_type = CT_OC_BLOCK_EXPR;
         }
         else
         {
            /* block expression with return type (seldomly used) */
            if (prev->type == CT_ASSIGN)
            {
               /* shortcut to spare the peeking below
                * the XOR operator wouldn't be used directly
                * after an assign all by itself */
               pc->parent_type = CT_OC_BLOCK_EXPR;
            }
            else
            {
               /* this ones tricky because we don't know how many
                * stars the return type has - if there even is one */
               tmp = pc;
               while ((tmp = chunk_get_next(tmp)) != NULL)
               {
                  /* we just peek ahead and see if the line contains
                   * an open brace somewhere.
                   * FIXME: this check needs to be more thorough. */
                  if (tmp->type == CT_BRACE_OPEN)
                  {
                     pc->parent_type = CT_OC_BLOCK_EXPR;
                     break;
                  }
               }
            }
         }
      }

      /* Handle special preprocessor junk */
      if (pc->type == CT_PREPROC)
      {
         pc->parent_type = next->type;
      }

      /* Detect "pragma region" and "pragma endregion" */
      if ((pc->type == CT_PP_PRAGMA) && (next->type == CT_PREPROC_BODY))
      {
         if ((memcmp(next->str, "region", 6) == 0) ||
             (memcmp(next->str, "endregion", 9) == 0))
         {
            pc->type = (*next->str == 'r') ? CT_PP_REGION : CT_PP_ENDREGION;

            prev->parent_type = pc->type;
         }
      }

      /* Check for C# nullable types '?' is in next */
      if ((cpd.lang_flags & LANG_CS) &&
          (next->type == CT_QUESTION) &&
          (next->orig_col == (pc->orig_col + pc->len)))
      {
         tmp = chunk_get_next_ncnl(next);
         if (tmp != NULL)
         {
            bool doit = ((tmp->type == CT_PAREN_CLOSE) ||
                         (tmp->type == CT_ANGLE_CLOSE));

            if (tmp->type == CT_WORD)
            {
               tmp2 = chunk_get_next_ncnl(tmp);
               if ((tmp2 != NULL) &&
                   ((tmp2->type == CT_SEMICOLON) ||
                    (tmp2->type == CT_ASSIGN) ||
                    (tmp2->type == CT_COMMA)))
               {
                  doit = true;
               }
            }

            if (doit)
            {
               pc->len++;
               chunk_del(next);
               next = tmp;
            }
         }
      }

      /* Convert '>' + '>' into '>>' */
      if ((cpd.lang_flags & LANG_CS) &&
          (pc->type == CT_ANGLE_CLOSE) &&
          (next->type == CT_ANGLE_CLOSE) &&
          (pc->parent_type == CT_NONE) &&
          ((pc->orig_col + pc->len) == next->orig_col) &&
          (next->parent_type == CT_NONE))
      {
         pc->len++;
         pc->type = CT_ARITH;
         tmp      = chunk_get_next_ncnl(next);
         chunk_del(next);
         next = tmp;
      }

      /* Change 'default(' into a sizeof-like statement */
      if ((cpd.lang_flags & LANG_CS) &&
          (pc->type == CT_DEFAULT) &&
          (next->type == CT_PAREN_OPEN))
      {
         pc->type = CT_SIZEOF;
      }

      if ((pc->type == CT_UNSAFE) && (next->type != CT_BRACE_OPEN))
      {
         pc->type = CT_QUALIFIER;
      }

      /* TODO: determine other stuff here */

      prev = pc;
      pc   = next;
      next = chunk_get_next_ncnl(pc);
   }
}
예제 #28
0
/*
 * See also it's preprocessor counterpart
 *   add_long_preprocessor_conditional_block_comment
 * in defines.cpp
 */
void add_long_closebrace_comment(void)
{
   LOG_FUNC_ENTRY();
   chunk_t  *br_close;
   chunk_t  *fcn_pc     = NULL;
   chunk_t  *sw_pc      = NULL;
   chunk_t  *ns_pc      = NULL;
   chunk_t  *cl_pc      = NULL;
   chunk_t  *cl_semi_pc = NULL;
   unc_text xstr;

   for (chunk_t *pc = chunk_get_head(); pc; pc = chunk_get_next_ncnl(pc))
   {
      if ((pc->type == CT_FUNC_DEF) ||
          (pc->type == CT_OC_MSG_DECL))
      {
         fcn_pc = pc;
      }
      else if (pc->type == CT_SWITCH)
      {
         /* kinda pointless, since it always has the text "switch" */
         sw_pc = pc;
      }
      else if (pc->type == CT_NAMESPACE)
      {
         ns_pc = pc;
      }
      else if (pc->type == CT_CLASS)
      {
         cl_pc = pc;
      }
      if ((pc->type != CT_BRACE_OPEN) || (pc->flags & PCF_IN_PREPROC))
      {
         continue;
      }

      chunk_t *br_open = pc;
      size_t  nl_count = 0;

      chunk_t *tmp = pc;
      while ((tmp = chunk_get_next(tmp)) != NULL)
      {
         if (chunk_is_newline(tmp))
         {
            nl_count += tmp->nl_count;
         }
         else if ((tmp->level == br_open->level) &&
                  (tmp->type == CT_BRACE_CLOSE))
         {
            br_close = tmp;

            //LOG_FMT(LSYS, "found brace pair on lines %d and %d, nl_count=%d\n",
            //        br_open->orig_line, br_close->orig_line, nl_count);

            /* Found the matching close brace - make sure a newline is next */
            tmp = chunk_get_next(tmp);

            // Check for end of class
            if (tmp != NULL && tmp->parent_type == CT_CLASS && tmp->type == CT_SEMICOLON)
            {
               cl_semi_pc = tmp;
               tmp        = chunk_get_next(tmp);
               if (tmp != NULL && !chunk_is_newline(tmp))
               {
                  tmp        = cl_semi_pc;
                  cl_semi_pc = NULL;
               }
            }
            if ((tmp == NULL) || chunk_is_newline(tmp))
            {
               size_t  nl_min  = 0;
               chunk_t *tag_pc = NULL;

               if (br_open->parent_type == CT_SWITCH)
               {
                  nl_min = cpd.settings[UO_mod_add_long_switch_closebrace_comment].u;
                  tag_pc = sw_pc;
                  xstr   = sw_pc ? sw_pc->str : NULL; /* \todo NULL is no unc_text structure */
               }
               else if ((br_open->parent_type == CT_FUNC_DEF) ||
                        (br_open->parent_type == CT_OC_MSG_DECL))
               {
                  nl_min = cpd.settings[UO_mod_add_long_function_closebrace_comment].u;
                  // 76006 Explicit null dereferenced, 2016-03-17
                  tag_pc = fcn_pc;
                  xstr.clear();
                  append_tag_name(xstr, tag_pc);
               }
               else if (br_open->parent_type == CT_NAMESPACE)
               {
                  nl_min = cpd.settings[UO_mod_add_long_namespace_closebrace_comment].u;
                  // 76007 Explicit null dereferenced, 2016-03-17
                  tag_pc = ns_pc;

                  /* obtain the next chunck, normally this is the name of the namespace
                   * and append it to generate "namespace xyz" */
                  xstr = ns_pc->str;
                  xstr.append(" ");
                  append_tag_name(xstr, chunk_get_next(ns_pc));
               }
               else if (br_open->parent_type == CT_CLASS && cl_semi_pc && cl_pc)
               {
                  nl_min = cpd.settings[UO_mod_add_long_class_closebrace_comment].u;
                  tag_pc = cl_pc;
                  xstr   = tag_pc->str;
                  xstr.append(" ");
                  append_tag_name(xstr, chunk_get_next(cl_pc));
                  br_close   = cl_semi_pc;
                  cl_semi_pc = NULL;
                  cl_pc      = NULL;
               }

               if ((nl_min > 0) && (nl_count >= nl_min) && (tag_pc != NULL))
               {
                  /* determine the added comment style */
                  c_token_t style = (cpd.lang_flags & (LANG_CPP | LANG_CS)) ?
                                    CT_COMMENT_CPP : CT_COMMENT;

                  /* Add a comment after the close brace */
                  insert_comment_after(br_close, style, xstr);
               }
            }
            break;
         }
      }
   }
} // add_long_closebrace_comment
예제 #29
0
/**
 * If there is nothing but CT_WORD and CT_MEMBER, then it's probably a
 * template thingy.  Otherwise, it's likely a comparison.
 */
static void check_template(chunk_t *start)
{
   chunk_t *pc;
   chunk_t *end;
   chunk_t *prev;
   chunk_t *next;
   bool    in_if = false;

   LOG_FMT(LTEMPL, "%s: Line %d, col %d:", __func__, start->orig_line, start->orig_col);

   prev = chunk_get_prev_ncnl(start, CNAV_PREPROC);
   if (prev == NULL)
   {
      return;
   }

   if (prev->type == CT_TEMPLATE)
   {
      LOG_FMT(LTEMPL, " CT_TEMPLATE:");

      /* We have: "template< ... >", which is a template declaration */
      int level = 1;
      for (pc = chunk_get_next_ncnl(start, CNAV_PREPROC);
           pc != NULL;
           pc = chunk_get_next_ncnl(pc, CNAV_PREPROC))
      {
         LOG_FMT(LTEMPL, " [%s,%d]", get_token_name(pc->type), level);

         if (chunk_is_str(pc, "<", 1))
         {
            level++;
         }
         else if (chunk_is_str(pc, ">", 1))
         {
            level--;
            if (level == 0)
            {
               break;
            }
         }
      }
      end = pc;
   }
   else
   {
      /* We may have something like "a< ... >", which is a template use
       * '...' may consist of anything except braces {}, a semicolon, and
       * unbalanced parens.
       * if we are inside an 'if' statement and hit a CT_BOOL, then it isn't a
       * template.
       */

      /* A template requires a word/type right before the open angle */
      if ((prev->type != CT_WORD) &&
          (prev->type != CT_TYPE) &&
          (prev->type != CT_OPERATOR_VAL) &&
          (prev->parent_type != CT_OPERATOR))
      {
         LOG_FMT(LTEMPL, " - after %s + ( - Not a template\n", get_token_name(prev->type));
         start->type = CT_COMPARE;
         return;
      }

      LOG_FMT(LTEMPL, " - prev %s -", get_token_name(prev->type));

      /* Scan back and make sure we aren't inside square parens */
      pc = start;
      while ((pc = chunk_get_prev_ncnl(pc, CNAV_PREPROC)) != NULL)
      {
         if ((pc->type == CT_SEMICOLON) ||
             (pc->type == CT_BRACE_OPEN) ||
             (pc->type == CT_BRACE_CLOSE) ||
             (pc->type == CT_SQUARE_CLOSE) ||
             (pc->type == CT_SEMICOLON))
         {
            break;
         }
         if (pc->type == CT_IF)
         {
            in_if = true;
            break;
         }
         if (pc->type == CT_SQUARE_OPEN)
         {
            LOG_FMT(LTEMPL, " - Not a template: after a square open\n");
            start->type = CT_COMPARE;
            return;
         }
      }

      /* Scan forward to the angle close
       * If we have a comparison in there, then it can't be a template.
       */
      c_token_t tokens[16];
      int       num_tokens = 1;

      tokens[0] = CT_ANGLE_OPEN;
      for (pc = chunk_get_next_ncnl(start, CNAV_PREPROC);
           pc != NULL;
           pc = chunk_get_next_ncnl(pc, CNAV_PREPROC))
      {
         LOG_FMT(LTEMPL, " [%s,%d]", get_token_name(pc->type), num_tokens);

         if (chunk_is_str(pc, "<", 1))
         {
            tokens[num_tokens++] = CT_ANGLE_OPEN;
         }
         else if (chunk_is_str(pc, ">", 1))
         {
            if (--num_tokens <= 0)
            {
               break;
            }
            if (tokens[num_tokens] != CT_ANGLE_OPEN)
            {
               /* unbalanced parens */
               break;
            }
         }
         else if (in_if &&
                  ((pc->type == CT_BOOL) ||
                   (pc->type == CT_COMPARE)))
         {
            break;
         }
         else if ((pc->type == CT_BRACE_OPEN) ||
                  (pc->type == CT_BRACE_CLOSE) ||
                  (pc->type == CT_SEMICOLON))
         {
            break;
         }
         else if (pc->type == CT_PAREN_OPEN)
         {
            if (num_tokens >= (int)(ARRAY_SIZE(tokens) - 1))
            {
               break;
            }
            tokens[num_tokens++] = pc->type;
         }
         else if (pc->type == CT_PAREN_CLOSE)
         {
            num_tokens--;
            if (tokens[num_tokens] != (pc->type - 1))
            {
               /* unbalanced parens */
               break;
            }
         }
      }
      end = pc;
   }

   if ((end != NULL) && (end->type == CT_ANGLE_CLOSE))
   {
      pc = chunk_get_next_ncnl(end, CNAV_PREPROC);
      if ((pc != NULL) && (pc->type != CT_NUMBER))
      {
         LOG_FMT(LTEMPL, " - Template Detected\n");

         start->parent_type = CT_TEMPLATE;

         pc = start;
         while (pc != end)
         {
            next       = chunk_get_next_ncnl(pc, CNAV_PREPROC);
            pc->flags |= PCF_IN_TEMPLATE;
            if (next->type != CT_PAREN_OPEN)
            {
               make_type(pc);
            }
            pc = next;
         }
         end->parent_type = CT_TEMPLATE;
         end->flags      |= PCF_IN_TEMPLATE;
         return;
      }
   }

   LOG_FMT(LTEMPL, " - Not a template: end = %s\n",
           (end != NULL) ? get_token_name(end->type) : "<null>");
   start->type = CT_COMPARE;
}
예제 #30
0
static chunk_t *mod_case_brace_add(chunk_t *cl_colon)
{
   LOG_FUNC_ENTRY();
   chunk_t *pc   = cl_colon;
   chunk_t *last = NULL;
   chunk_t *next = chunk_get_next_ncnl(cl_colon, CNAV_PREPROC);

   LOG_FMT(LMCB, "%s: line %zu", __func__, pc->orig_line);

   while ((pc = chunk_get_next_ncnl(pc, CNAV_PREPROC)) != NULL)
   {
      if (pc->level < cl_colon->level)
      {
         LOG_FMT(LMCB, " - level drop\n");
         return(next);
      }

      if ((pc->level == cl_colon->level) &&
          ((pc->type == CT_CASE) ||
           (pc->type == CT_BREAK)))
      {
         last = pc;
         //if (pc->type == CT_BREAK)
         //{
         //   /* Step past the semicolon */
         //   last = chunk_get_next_ncnl(chunk_get_next_ncnl(last));
         //}
         break;
      }
   }

   if (last == NULL)
   {
      LOG_FMT(LMCB, " - NULL last\n");
      return(next);
   }

   LOG_FMT(LMCB, " - adding before '%s' on line %zu\n", last->text(), last->orig_line);

   chunk_t chunk;
   chunk.type        = CT_BRACE_OPEN;
   chunk.orig_line   = cl_colon->orig_line;
   chunk.parent_type = CT_CASE;
   chunk.level       = cl_colon->level;
   chunk.brace_level = cl_colon->brace_level;
   chunk.flags       = pc->flags & PCF_COPY_FLAGS;
   chunk.str         = "{";

   chunk_t *br_open = chunk_add_after(&chunk, cl_colon);

   chunk.type      = CT_BRACE_CLOSE;
   chunk.orig_line = last->orig_line;
   chunk.str       = "}";

   chunk_t *br_close = chunk_add_before(&chunk, last);
   newline_add_before(last);

   for (pc = chunk_get_next(br_open, CNAV_PREPROC);
        pc != br_close;
        pc = chunk_get_next(pc, CNAV_PREPROC))
   {
      pc->level++;
      pc->brace_level++;
   }

   return(br_open);
} // mod_case_brace_add