/** * 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) { LOG_FUNC_ENTRY(); 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 parent=%s, prev = '%s' [%s/%s]\n", pc->orig_line, pc->orig_col, get_token_name(pc->parent_type), prev->str.c_str(), 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 (prev->type == CT_BRACE_OPEN) { LOG_FUNC_CALL(); remove_semicolon(pc); } } pc = next; } }
/** * 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 ((pc->str[0] == '>') && (pc->len() > 1)) { LOG_FMT(LTEMPL, " {split '%s' at %d:%d}", pc->str.c_str(), pc->orig_line, pc->orig_col); split_off_angle_close(pc); } 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 where * '...' 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_COMMA) && (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)) { break; } if ((pc->type == CT_IF) || (pc->type == CT_RETURN)) { 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[1024]; 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 ((tokens[num_tokens - 1] == CT_ANGLE_OPEN) && (pc->str[0] == '>') && (pc->len() > 1) && (cpd.settings[UO_tok_split_gte].b || chunk_is_str(pc, ">>", 2))) { LOG_FMT(LTEMPL, " {split '%s' at %d:%d}", pc->str.c_str(), pc->orig_line, pc->orig_col); split_off_angle_close(pc); } if (chunk_is_str(pc, "<", 1)) { tokens[num_tokens++] = CT_ANGLE_OPEN; } else if (chunk_is_str(pc, ">", 1)) { if ((num_tokens > 0) && (tokens[num_tokens - 1] == CT_PAREN_OPEN)) { handle_double_angle_close(pc); } else if (--num_tokens <= 0) { break; } else 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; }
static bool split_line(chunk_t *start) { LOG_FUNC_ENTRY(); LOG_FMT(LSPLIT, "%s(%d): start->text() '%s', orig_line is %zu, orig_col is %zu, type is %s\n", __func__, __LINE__, start->text(), start->orig_line, start->orig_col, get_token_name(start->type)); LOG_FMT(LSPLIT, " start->flags "); log_pcf_flags(LSPLIT, start->flags); LOG_FMT(LSPLIT, " start->parent_type %s, (PCF_IN_FCN_DEF is %s), (PCF_IN_FCN_CALL is %s)\n", get_token_name(start->parent_type), ((start->flags & (PCF_IN_FCN_DEF)) != 0) ? "TRUE" : "FALSE", ((start->flags & (PCF_IN_FCN_CALL)) != 0) ? "TRUE" : "FALSE"); // break at maximum line length if ls_code_width is true if (start->flags & PCF_ONE_LINER) { LOG_FMT(LSPLIT, "%s(%d): ** ONCE LINER SPLIT **\n", __func__, __LINE__); undo_one_liner(start); newlines_cleanup_braces(false); // Issue #1352 cpd.changes++; return(false); } LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); if (cpd.settings[UO_ls_code_width].b) { } // Check to see if we are in a for statement else if (start->flags & PCF_IN_FOR) { LOG_FMT(LSPLIT, " ** FOR SPLIT **\n"); split_for_stmt(start); if (!is_past_width(start)) { return(true); } LOG_FMT(LSPLIT, "%s(%d): for split didn't work\n", __func__, __LINE__); } /* * If this is in a function call or prototype, split on commas or right * after the open parenthesis */ else if ( (start->flags & PCF_IN_FCN_DEF) || start->parent_type == CT_FUNC_PROTO // Issue #1169 || ( (start->level == (start->brace_level + 1)) && (start->flags & PCF_IN_FCN_CALL))) { LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n"); if (cpd.settings[UO_ls_func_split_full].b) { split_fcn_params_full(start); if (!is_past_width(start)) { return(true); } } split_fcn_params(start); return(true); } /* * If this is in a template, split on commas, Issue #1170 */ else if (start->flags & PCF_IN_TEMPLATE) { LOG_FMT(LSPLIT, " ** TEMPLATE SPLIT **\n"); split_template(start); return(true); } LOG_FMT(LSPLIT, "%s(%d):\n", __func__, __LINE__); // Try to find the best spot to split the line cw_entry ent; memset(&ent, 0, sizeof(ent)); chunk_t *pc = start; chunk_t *prev; while (((pc = chunk_get_prev(pc)) != nullptr) && !chunk_is_newline(pc)) { LOG_FMT(LSPLIT, "%s(%d): at %s, orig_line=%zu, orig_col=%zu\n", __func__, __LINE__, pc->text(), pc->orig_line, pc->orig_col); if (pc->type != CT_SPACE) { try_split_here(ent, pc); // break at maximum line length if (ent.pc != nullptr && (cpd.settings[UO_ls_code_width].b)) { break; } } } if (ent.pc == nullptr) { LOG_FMT(LSPLIT, "\n%s(%d): TRY_SPLIT yielded NO SOLUTION for orig_line %zu at '%s' [%s]\n", __func__, __LINE__, start->orig_line, start->text(), get_token_name(start->type)); } else { LOG_FMT(LSPLIT, "\n%s(%d): TRY_SPLIT yielded '%s' [%s] on orig_line %zu\n", __func__, __LINE__, ent.pc->text(), get_token_name(ent.pc->type), ent.pc->orig_line); LOG_FMT(LSPLIT, "%s(%d): ent at '%s', orig_col is %zu\n", __func__, __LINE__, ent.pc->text(), ent.pc->orig_col); } // Break before the token instead of after it according to the pos_xxx rules if (ent.pc == nullptr) { pc = nullptr; } else { if ( ( ( chunk_is_token(ent.pc, CT_ARITH) || chunk_is_token(ent.pc, CT_CARET)) && (cpd.settings[UO_pos_arith].tp & TP_LEAD)) || ( chunk_is_token(ent.pc, CT_ASSIGN) && (cpd.settings[UO_pos_assign].tp & TP_LEAD)) || ( chunk_is_token(ent.pc, CT_COMPARE) && (cpd.settings[UO_pos_compare].tp & TP_LEAD)) || ( ( chunk_is_token(ent.pc, CT_COND_COLON) || chunk_is_token(ent.pc, CT_QUESTION)) && (cpd.settings[UO_pos_conditional].tp & TP_LEAD)) || ( chunk_is_token(ent.pc, CT_BOOL) && (cpd.settings[UO_pos_bool].tp & TP_LEAD))) { pc = ent.pc; } else { pc = chunk_get_next(ent.pc); } LOG_FMT(LSPLIT, "%s(%d): at '%s', orig_col is %zu\n", __func__, __LINE__, pc->text(), pc->orig_col); } if (pc == nullptr) { pc = start; // Don't break before a close, comma, or colon if ( start->type == CT_PAREN_CLOSE || start->type == CT_PAREN_OPEN || start->type == CT_FPAREN_CLOSE || start->type == CT_FPAREN_OPEN || start->type == CT_SPAREN_CLOSE || start->type == CT_SPAREN_OPEN || start->type == CT_ANGLE_CLOSE || start->type == CT_BRACE_CLOSE || start->type == CT_COMMA || start->type == CT_SEMICOLON || start->type == CT_VSEMICOLON || start->len() == 0) { LOG_FMT(LSPLIT, " ** NO GO **\n"); // TODO: Add in logic to handle 'hard' limits by backing up a token return(true); } } // add a newline before pc prev = chunk_get_prev(pc); if ( prev != nullptr && !chunk_is_newline(pc) && !chunk_is_newline(prev)) { //int plen = (pc->len() < 5) ? pc->len() : 5; //int slen = (start->len() < 5) ? start->len() : 5; //LOG_FMT(LSPLIT, " '%.*s' [%s], started on token '%.*s' [%s]\n", // plen, pc->text(), get_token_name(pc->type), // slen, start->text(), get_token_name(start->type)); LOG_FMT(LSPLIT, "%s(%d): text() '%s', type [%s], started on token '%s', type [%s]\n", __func__, __LINE__, pc->text(), get_token_name(pc->type), start->text(), get_token_name(start->type)); split_before_chunk(pc); } return(true); } // split_line
bool close_statement(parse_frame_t *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *vbc = pc; LOG_FMT(LTOK, "%s:%zu] %s '%s' type %s stage %d\n", __func__, pc->orig_line, get_token_name(pc->type), pc->text(), get_token_name(frm->pse[frm->pse_tos].type), frm->pse[frm->pse_tos].stage); if (cpd.consumed) { frm->stmt_count = 0; frm->expr_count = 0; LOG_FMT(LSTMT, "%s: %zu> reset2 stmt on %s\n", __func__, pc->orig_line, pc->text()); } /** * Insert a CT_VBRACE_CLOSE, if needed: * If we are in a virtual brace and we are not ON a CT_VBRACE_CLOSE add one */ if (frm->pse[frm->pse_tos].type == CT_VBRACE_OPEN) { /* If the current token has already been consumed, then add after it */ if (cpd.consumed) { insert_vbrace_close_after(pc, frm); } else { /* otherwise, add before it and consume the vbrace */ vbc = chunk_get_prev_ncnl(pc); vbc = insert_vbrace_close_after(vbc, frm); set_chunk_parent(vbc, frm->pse[frm->pse_tos].parent); frm->level--; frm->brace_level--; frm->pse_tos--; /* Update the token level */ pc->level = frm->level; pc->brace_level = frm->brace_level; print_stack(LBCSPOP, "-CS VB ", frm, pc); /* And repeat the close */ close_statement(frm, pc); return(true); } } /* See if we are done with a complex statement */ if (frm->pse[frm->pse_tos].stage != BS_NONE) { if (handle_complex_close(frm, vbc)) { return(true); } } return(false); } // close_statement
static bool check_complex_statements(parse_frame_t *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); c_token_t parent; /* Turn an optional paren into either a real paren or a brace */ if (frm->pse[frm->pse_tos].stage == BS_OP_PAREN1) { frm->pse[frm->pse_tos].stage = (pc->type != CT_PAREN_OPEN) ? BS_BRACE2 : BS_PAREN1; } /* Check for CT_ELSE after CT_IF */ while (frm->pse[frm->pse_tos].stage == BS_ELSE) { if (pc->type == CT_ELSE) { /* Replace CT_IF with CT_ELSE on the stack & we are done */ frm->pse[frm->pse_tos].type = CT_ELSE; frm->pse[frm->pse_tos].stage = BS_ELSEIF; print_stack(LBCSSWAP, "=Swap ", frm, pc); return(true); } /* Remove the CT_IF and close the statement */ frm->pse_tos--; print_stack(LBCSPOP, "-IF-CCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } /* Check for CT_IF after CT_ELSE */ if (frm->pse[frm->pse_tos].stage == BS_ELSEIF) { if (pc->type == CT_IF) { if (!cpd.settings[UO_indent_else_if].b || !chunk_is_newline(chunk_get_prev_nc(pc))) { /* Replace CT_ELSE with CT_IF */ set_chunk_type(pc, CT_ELSEIF); frm->pse[frm->pse_tos].type = CT_ELSEIF; frm->pse[frm->pse_tos].stage = BS_PAREN1; return(true); } } /* Jump to the 'expecting brace' stage */ frm->pse[frm->pse_tos].stage = BS_BRACE2; } /* Check for CT_CATCH or CT_FINALLY after CT_TRY or CT_CATCH */ while (frm->pse[frm->pse_tos].stage == BS_CATCH) { if ((pc->type == CT_CATCH) || (pc->type == CT_FINALLY)) { /* Replace CT_TRY with CT_CATCH on the stack & we are done */ frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = (pc->type == CT_CATCH) ? BS_CATCH_WHEN : BS_BRACE2; print_stack(LBCSSWAP, "=Swap ", frm, pc); return(true); } /* Remove the CT_TRY and close the statement */ frm->pse_tos--; print_stack(LBCSPOP, "-TRY-CCS ", frm, pc); if (close_statement(frm, pc)) { return(true); } } /* Check for optional paren and optional CT_WHEN after CT_CATCH */ if (frm->pse[frm->pse_tos].stage == BS_CATCH_WHEN) { if (pc->type == CT_PAREN_OPEN) // this is for the paren after "catch" { /* Replace CT_PAREN_OPEN with CT_SPAREN_OPEN */ set_chunk_type(pc, CT_SPAREN_OPEN); frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = BS_PAREN1; return(false); } else if (pc->type == CT_WHEN) { frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = BS_OP_PAREN1; return(true); } else if (pc->type == CT_BRACE_OPEN) { frm->pse[frm->pse_tos].stage = BS_BRACE2; return(false); } } /* Check for CT_WHILE after the CT_DO */ if (frm->pse[frm->pse_tos].stage == BS_WHILE) { if (pc->type == CT_WHILE) { set_chunk_type(pc, CT_WHILE_OF_DO); frm->pse[frm->pse_tos].type = CT_WHILE_OF_DO; //CT_WHILE; frm->pse[frm->pse_tos].stage = BS_WOD_PAREN; return(true); } LOG_FMT(LWARN, "%s:%zu Error: Expected 'while', got '%s'\n", cpd.filename, pc->orig_line, pc->text()); frm->pse_tos--; print_stack(LBCSPOP, "-Error ", frm, pc); cpd.error_count++; } /* Insert a CT_VBRACE_OPEN, if needed */ if ((pc->type != CT_BRACE_OPEN) && ((frm->pse[frm->pse_tos].stage == BS_BRACE2) || (frm->pse[frm->pse_tos].stage == BS_BRACE_DO))) { if ((cpd.lang_flags & LANG_CS) && (pc->type == CT_USING_STMT) && (!cpd.settings[UO_indent_using_block].b)) { // don't indent the using block } else { parent = frm->pse[frm->pse_tos].type; chunk_t *vbrace = insert_vbrace_open_before(pc, frm); set_chunk_parent(vbrace, parent); frm->level++; frm->brace_level++; push_fmr_pse(frm, vbrace, BS_NONE, "+VBrace "); frm->pse[frm->pse_tos].parent = parent; /* update the level of pc */ pc->level = frm->level; pc->brace_level = frm->brace_level; /* Mark as a start of a statement */ frm->stmt_count = 0; frm->expr_count = 0; pc->flags |= PCF_STMT_START | PCF_EXPR_START; frm->stmt_count = 1; frm->expr_count = 1; LOG_FMT(LSTMT, "%zu] 2.marked %s as stmt start\n", pc->orig_line, pc->text()); } } /* Verify open paren in complex statement */ if ((pc->type != CT_PAREN_OPEN) && ((frm->pse[frm->pse_tos].stage == BS_PAREN1) || (frm->pse[frm->pse_tos].stage == BS_WOD_PAREN))) { LOG_FMT(LWARN, "%s:%zu Error: Expected '(', got '%s' for '%s'\n", cpd.filename, pc->orig_line, pc->text(), get_token_name(frm->pse[frm->pse_tos].type)); /* Throw out the complex statement */ frm->pse_tos--; print_stack(LBCSPOP, "-Error ", frm, pc); cpd.error_count++; } return(false); } // check_complex_statements
Error ScriptClassParser::parse(const String &p_code) { code = p_code; idx = 0; line = 0; error_str = String(); error = false; value = Variant(); classes.clear(); Token tk = get_token(); Map<int, NameDecl> name_stack; int curly_stack = 0; int type_curly_stack = 0; while (!error && tk != TK_EOF) { if (tk == TK_IDENTIFIER && String(value) == "class") { tk = get_token(); if (tk == TK_IDENTIFIER) { String name = value; int at_level = type_curly_stack; ClassDecl class_decl; for (Map<int, NameDecl>::Element *E = name_stack.front(); E; E = E->next()) { const NameDecl &name_decl = E->value(); if (name_decl.type == NameDecl::NAMESPACE_DECL) { if (E != name_stack.front()) class_decl.namespace_ += "."; class_decl.namespace_ += name_decl.name; } else { class_decl.name += name_decl.name + "."; } } class_decl.name += name; class_decl.nested = type_curly_stack > 0; bool generic = false; while (true) { tk = get_token(); if (tk == TK_COLON) { Error err = _parse_class_base(class_decl.base); if (err) return err; curly_stack++; type_curly_stack++; break; } else if (tk == TK_CURLY_BRACKET_OPEN) { curly_stack++; type_curly_stack++; break; } else if (tk == TK_OP_LESS && !generic) { generic = true; Error err = _skip_generic_type_params(); if (err) return err; } else if (tk == TK_IDENTIFIER && String(value) == "where") { Error err = _parse_type_constraints(); if (err) { return err; } // An open curly bracket was parsed by _parse_type_constraints, so we can exit curly_stack++; type_curly_stack++; break; } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } NameDecl name_decl; name_decl.name = name; name_decl.type = NameDecl::CLASS_DECL; name_stack[at_level] = name_decl; if (!generic) { // no generics, thanks classes.push_back(class_decl); } else if (OS::get_singleton()->is_stdout_verbose()) { String full_name = class_decl.namespace_; if (full_name.length()) full_name += "."; full_name += class_decl.name; OS::get_singleton()->print(String("Ignoring generic class declaration: " + class_decl.name).utf8()); } } } else if (tk == TK_IDENTIFIER && String(value) == "struct") { String name; int at_level = type_curly_stack; while (true) { tk = get_token(); if (tk == TK_IDENTIFIER && name.empty()) { name = String(value); } else if (tk == TK_CURLY_BRACKET_OPEN) { if (name.empty()) { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN); error = true; return ERR_PARSE_ERROR; } curly_stack++; type_curly_stack++; break; } else if (tk == TK_EOF) { error_str = "Expected " + get_token_name(TK_CURLY_BRACKET_OPEN) + " after struct decl, found " + get_token_name(TK_EOF); error = true; return ERR_PARSE_ERROR; } } NameDecl name_decl; name_decl.name = name; name_decl.type = NameDecl::STRUCT_DECL; name_stack[at_level] = name_decl; } else if (tk == TK_IDENTIFIER && String(value) == "namespace") { if (type_curly_stack > 0) { error_str = "Found namespace nested inside type."; error = true; return ERR_PARSE_ERROR; } String name; int at_level = curly_stack; Error err = _parse_namespace_name(name, curly_stack); if (err) return err; NameDecl name_decl; name_decl.name = name; name_decl.type = NameDecl::NAMESPACE_DECL; name_stack[at_level] = name_decl; } else if (tk == TK_CURLY_BRACKET_OPEN) { curly_stack++; } else if (tk == TK_CURLY_BRACKET_CLOSE) { curly_stack--; if (name_stack.has(curly_stack)) { if (name_stack[curly_stack].type != NameDecl::NAMESPACE_DECL) type_curly_stack--; name_stack.erase(curly_stack); } } tk = get_token(); } if (!error && tk == TK_EOF && curly_stack > 0) { error_str = "Reached EOF with missing close curly brackets."; error = true; } if (error) return ERR_PARSE_ERROR; return OK; }
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 * * 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) { /* 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) || (pc->type == CT_OC_PROTOCOL)) { if (next->type != CT_PAREN_OPEN) { 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); } }
/** * 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_FMT(LSPLIT, " %s: ", __func__); chunk_t *next; chunk_t *prev; 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 */ } pc = chunk_get_next(fpo); if (!chunk_is_newline(pc)) { int min_col = pc->column; int max_width = 0; int cur_width = 0; int last_col = -1; 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)) { 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 (cur_width > max_width) { max_width = cur_width; if ((max_width + min_col) > cpd.settings[UO_code_width].n) { break; } } cur_width = 0; last_col = -1; if (pc->type == CT_FPAREN_CLOSE) { break; } } } pc = chunk_get_next(pc); } // don't split function w/o parameters next = chunk_get_next(fpo); if (((max_width + min_col) > cpd.settings[UO_code_width].n) && next->type != CT_FPAREN_CLOSE) { LOG_FMT(LSPLIT, " - A param won't fit, nl after open paren."); split_before_chunk(chunk_get_next(fpo)); return; } } /* 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; } if (prev->type == CT_FPAREN_OPEN) { /* Don't split "()" */ pc = chunk_get_next(prev); if (pc->type != c_token_t(prev->type + 1)) { break; } } } if (prev != NULL) { LOG_FMT(LSPLIT, " -- ended on [%s] -- ", get_token_name(prev->type)); } if (prev != NULL) { split_before_chunk(chunk_get_next(prev)); } }
/** * Traverse the if chain and see if all can be removed */ static void process_if_chain(chunk_t *br_start) { chunk_t *braces[256]; chunk_t *br_close; int br_cnt = 0; chunk_t *pc; bool must_have_braces = false; bool tmp; pc = br_start; LOG_FMT(LBRCH, "%s: if starts on line %d\n", __func__, br_start->orig_line); while (pc != NULL) { if (pc->type == CT_BRACE_OPEN) { tmp = can_remove_braces(pc); LOG_FMT(LBRCH, " [%d] line %d - can%s remove %s\n", br_cnt, pc->orig_line, tmp ? "" : "not", get_token_name(pc->type)); if (!tmp) { must_have_braces = true; } } else { tmp = should_add_braces(pc); if (tmp) { must_have_braces = true; } LOG_FMT(LBRCH, " [%d] line %d - %s %s\n", br_cnt, pc->orig_line, tmp ? "should add" : "ignore", get_token_name(pc->type)); } braces[br_cnt++] = pc; br_close = chunk_skip_to_match(pc, CNAV_PREPROC); if (br_close == NULL) { break; } braces[br_cnt++] = br_close; pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC); if ((pc == NULL) || (pc->type != CT_ELSE)) { break; } pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_ELSEIF)) { while ((pc != NULL) && (pc->type != CT_VBRACE_OPEN) && (pc->type != CT_BRACE_OPEN)) { pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); } } if (pc == NULL) { break; } if ((pc->type != CT_BRACE_OPEN) && (pc->type != CT_VBRACE_OPEN)) { break; } } if (must_have_braces) { LOG_FMT(LBRCH, "%s: add braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { braces[br_cnt]->flags |= PCF_KEEP_BRACE; if ((braces[br_cnt]->type == CT_VBRACE_OPEN) || (braces[br_cnt]->type == CT_VBRACE_CLOSE)) { LOG_FMT(LBRCH, " %d", braces[br_cnt]->orig_line); convert_vbrace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " {%d}", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } else { LOG_FMT(LBRCH, "%s: remove braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { if ((braces[br_cnt]->type == CT_BRACE_OPEN) || (braces[br_cnt]->type == CT_BRACE_CLOSE)) { LOG_FMT(LBRCH, " {%d}", braces[br_cnt]->orig_line); convert_brace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " %d", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } }
/** * Adds an item to the align stack and adjust the nl_count and max_col. * Adjust max_col as needed * * @param pc the item to add * @param max_col pointer to the column variable * @param extra_pad extra padding */ static void align_add(ChunkStack& cs, chunk_t *pc, int& max_col, int min_pad, bool squeeze) { chunk_t *prev; int min_col; prev = chunk_get_prev(pc); if ((prev == NULL) || chunk_is_newline(prev)) { min_col = squeeze ? 1 : pc->column; LOG_FMT(LALADD, "%s: pc->col=%d max_col=%d min_pad=%d min_col=%d\n", __func__, pc->column, max_col, min_pad, min_col); } else { if (prev->type == CT_COMMENT_MULTI) { min_col = prev->orig_col_end + min_pad; } else { min_col = prev->column + prev->len + min_pad; } if (!squeeze) { if (min_col < pc->column) { min_col = pc->column; } } LOG_FMT(LALADD, "%s: pc->col=%d max_col=%d min_pad=%d min_col=%d multi:%s prev->col=%d prev->len=%d %s\n", __func__, pc->column, max_col, min_pad, min_col, (prev->type == CT_COMMENT_MULTI) ? "Y" : "N", (prev->type == CT_COMMENT_MULTI) ? prev->orig_col_end : prev->column, prev->len, get_token_name(prev->type)); } if (cs.Empty()) { max_col = 0; } cs.Push(pc); if (min_col > max_col) { max_col = min_col; } }
/** * Scan everything at the current level until the close brace and find the * variable def align column. Also aligns bit-colons, but that assumes that * bit-types are the same! But that should always be the case... */ static chunk_t *align_var_def_brace(chunk_t *start, int span, int *p_nl_count) { chunk_t *pc; chunk_t *next; chunk_t *prev; UINT64 align_mask = PCF_IN_FCN_DEF | PCF_VAR_1ST; int myspan = span; int mythresh = 0; int mygap = 0; AlignStack as; /* var/proto/def */ AlignStack as_bc; /* bit-colon */ AlignStack as_at; /* attribute */ AlignStack as_br; /* one-liner brace open */ bool fp_active = cpd.settings[UO_align_mix_var_proto].b; bool fp_look_bro = false; if (start == NULL) { return(NULL); } /* Override the span, if this is a struct/union */ if ((start->parent_type == CT_STRUCT) || (start->parent_type == CT_UNION)) { myspan = cpd.settings[UO_align_var_struct_span].n; mythresh = cpd.settings[UO_align_var_struct_thresh].n; mygap = cpd.settings[UO_align_var_struct_gap].n; } else { mythresh = cpd.settings[UO_align_var_def_thresh].n; mygap = cpd.settings[UO_align_var_def_gap].n; } /* can't be any variable definitions in a "= {" block */ prev = chunk_get_prev_ncnl(start); if ((prev != NULL) && (prev->type == CT_ASSIGN)) { LOG_FMT(LAVDB, "%s: start=%.*s [%s] on line %d (abort due to assign)\n", __func__, start->len, start->str, get_token_name(start->type), start->orig_line); pc = chunk_get_next_type(start, CT_BRACE_CLOSE, start->level); return(chunk_get_next_ncnl(pc)); } LOG_FMT(LAVDB, "%s: start=%.*s [%s] on line %d\n", __func__, start->len, start->str, get_token_name(start->type), start->orig_line); if (!cpd.settings[UO_align_var_def_inline].b) { align_mask |= PCF_VAR_INLINE; } /* Set up the var/proto/def aligner */ as.Start(myspan, mythresh); as.m_gap = mygap; as.m_star_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_star_style].n; as.m_amp_style = (AlignStack::StarStyle)cpd.settings[UO_align_var_def_amp_style].n; /* Set up the bit colon aligner */ as_bc.Start(myspan, 0); as_bc.m_gap = cpd.settings[UO_align_var_def_colon_gap].n; as_at.Start(myspan, 0); /* Set up the brace open aligner */ as_br.Start(myspan, mythresh); as_br.m_gap = cpd.settings[UO_align_single_line_brace_gap].n; bool did_this_line = false; pc = chunk_get_next(start); while ((pc != NULL) && ((pc->level >= start->level) || (pc->level == 0))) { if (chunk_is_comment(pc)) { if (pc->nl_count > 0) { as.NewLines(pc->nl_count); as_bc.NewLines(pc->nl_count); as_at.NewLines(pc->nl_count); as_br.NewLines(pc->nl_count); } pc = chunk_get_next(pc); continue; } if (fp_active) { if ((pc->type == CT_FUNC_PROTO) || ((pc->type == CT_FUNC_DEF) && cpd.settings[UO_align_single_line_func].b)) { LOG_FMT(LAVDB, " add=[%.*s] line=%d col=%d level=%d\n", pc->len, pc->str, pc->orig_line, pc->orig_col, pc->level); as.Add(pc); fp_look_bro = (pc->type == CT_FUNC_DEF) && cpd.settings[UO_align_single_line_brace].b; } else if (fp_look_bro && (pc->type == CT_BRACE_OPEN) && (pc->flags & PCF_ONE_LINER)) { as_br.Add(pc); fp_look_bro = false; } } /* process nested braces */ if (pc->type == CT_BRACE_OPEN) { int sub_nl_count = 0; pc = align_var_def_brace(pc, span, &sub_nl_count); if (sub_nl_count > 0) { fp_look_bro = false; did_this_line = false; as.NewLines(sub_nl_count); as_bc.NewLines(sub_nl_count); as_at.NewLines(sub_nl_count); as_br.NewLines(sub_nl_count); if (p_nl_count != NULL) { *p_nl_count += sub_nl_count; } } continue; } /* Done with this brace set? */ if (pc->type == CT_BRACE_CLOSE) { pc = chunk_get_next(pc); break; } if (chunk_is_newline(pc)) { fp_look_bro = false; did_this_line = false; as.NewLines(pc->nl_count); as_bc.NewLines(pc->nl_count); as_at.NewLines(pc->nl_count); as_br.NewLines(pc->nl_count); if (p_nl_count != NULL) { *p_nl_count += pc->nl_count; } } /* don't align stuff inside parens/squares/angles */ if (pc->level > pc->brace_level) { pc = chunk_get_next(pc); continue; } /* If this is a variable def, update the max_col */ if ((pc->type != CT_FUNC_CLASS) && ((pc->flags & align_mask) == PCF_VAR_1ST) && ((pc->level == (start->level + 1)) || (pc->level == 0))) { if (!did_this_line) { LOG_FMT(LAVDB, " add=[%.*s] line=%d col=%d level=%d\n", pc->len, pc->str, pc->orig_line, pc->orig_col, pc->level); as.Add(pc); if (cpd.settings[UO_align_var_def_colon].b) { next = chunk_get_next_nc(pc); if (next->type == CT_BIT_COLON) { as_bc.Add(next); } } if (cpd.settings[UO_align_var_def_attribute].b) { next = pc; while ((next = chunk_get_next_nc(next)) != NULL) { if (next->type == CT_ATTRIBUTE) { as_at.Add(next); break; } if ((next->type == CT_SEMICOLON) || chunk_is_newline(next)) { break; } } } } did_this_line = true; } else if (pc->type == CT_BIT_COLON) { if (!did_this_line) { as_bc.Add(pc); did_this_line = true; } } pc = chunk_get_next(pc); } as.End(); as_bc.End(); as_at.End(); as_br.End(); return(pc); }
/** * Generically aligns on '=', '{', '(' and item after ',' * It scans the first line and picks up the location of those tags. * It then scans subsequent lines and adjusts the column. * Finally it does a second pass to align everything. * * Aligns all the '=' signs in stucture assignments. * a = { * .a = 1; * .type = fast; * }; * * And aligns on '{', numbers, strings, words. * colors[] = { * {"red", {255, 0, 0}}, {"blue", { 0, 255, 0}}, * {"green", { 0, 0, 255}}, {"purple", {255, 255, 0}}, * }; * * For the C99 indexed array assignment, the leading []= is skipped (no aligning) * struct foo_t bars[] = * { * [0] = { .name = "bar", * .age = 21 }, * [1] = { .name = "barley", * .age = 55 }, * }; * * NOTE: this assumes that spacing is at the minimum correct spacing (ie force) * if it isn't, some extra spaces will be inserted. * * @param start Points to the open brace chunk */ static void align_init_brace(chunk_t *start) { int idx; chunk_t *pc; chunk_t *next; chunk_t *prev; chunk_t *num_token = NULL; cpd.al_cnt = 0; cpd.al_c99_array = false; LOG_FMT(LALBR, "%s: line %d, col %d\n", __func__, start->orig_line, start->orig_col); pc = chunk_get_next_ncnl(start); pc = scan_ib_line(pc, true); if ((pc == NULL) || ((pc->type == CT_BRACE_CLOSE) && (pc->parent_type == CT_ASSIGN))) { /* single line - nothing to do */ return; } do { pc = scan_ib_line(pc, false); /* debug dump the current frame */ align_log_al(LALBR, pc->orig_line); while (chunk_is_newline(pc)) { pc = chunk_get_next(pc); } } while ((pc != NULL) && (pc->level > start->level)); /* debug dump the current frame */ align_log_al(LALBR, start->orig_line); if (cpd.settings[UO_align_on_tabstop].b && (cpd.al_cnt >= 1) && (cpd.al[0].type == CT_ASSIGN)) { int rem = (cpd.al[0].col - 1) % cpd.settings[UO_output_tab_size].n; if (rem != 0) { LOG_FMT(LALBR, "%s: col=%d rem=%d", __func__, cpd.al[0].col, rem); cpd.al[0].col += cpd.settings[UO_output_tab_size].n - rem; } } pc = chunk_get_next(start); idx = 0; do { if ((idx == 0) && (pc->type == CT_SQUARE_OPEN)) { pc = chunk_get_next_type(pc, CT_ASSIGN, pc->level); pc = chunk_get_next(pc); if (pc != NULL) { LOG_FMT(LALBR, " -%d- skipped '[] =' to %s\n", pc->orig_line, get_token_name(pc->type)); } continue; } next = pc; if (idx < cpd.al_cnt) { LOG_FMT(LALBR, " (%d) check %s vs %s -- ", idx, get_token_name(pc->type), get_token_name(cpd.al[idx].type)); if (pc->type == cpd.al[idx].type) { if ((idx == 0) && cpd.al_c99_array) { prev = chunk_get_prev(pc); if (chunk_is_newline(prev)) { pc->flags |= PCF_DONT_INDENT; } } LOG_FMT(LALBR, " [%.*s] to col %d\n", pc->len, pc->str, cpd.al[idx].col); if (num_token != NULL) { int col_diff = pc->column - num_token->column; reindent_line(num_token, cpd.al[idx].col - col_diff); //LOG_FMT(LSYS, "-= %d =- NUM indent [%.*s] col=%d diff=%d\n", // num_token->orig_line, // num_token->len, num_token->str, cpd.al[idx - 1].col, col_diff); num_token->flags |= PCF_WAS_ALIGNED; num_token = NULL; } /* Comma's need to 'fall back' to the previous token */ if (pc->type == CT_COMMA) { next = chunk_get_next(pc); if ((next != NULL) && !chunk_is_newline(next)) { //LOG_FMT(LSYS, "-= %d =- indent [%.*s] col=%d len=%d\n", // next->orig_line, // next->len, next->str, cpd.al[idx].col, cpd.al[idx].len); if ((idx < (cpd.al_cnt - 1)) && cpd.settings[UO_align_number_left].b && ((next->type == CT_NUMBER_FP) || (next->type == CT_NUMBER) || (next->type == CT_POS) || (next->type == CT_NEG))) { /* Need to wait until the next match to indent numbers */ num_token = next; } else { reindent_line(next, cpd.al[idx].col + cpd.al[idx].len); next->flags |= PCF_WAS_ALIGNED; } } } else { /* first item on the line */ reindent_line(pc, cpd.al[idx].col); pc->flags |= PCF_WAS_ALIGNED; /* see if we need to right-align a number */ if ((idx < (cpd.al_cnt - 1)) && cpd.settings[UO_align_number_left].b) { next = chunk_get_next(pc); if ((next != NULL) && !chunk_is_newline(next) && ((next->type == CT_NUMBER_FP) || (next->type == CT_NUMBER) || (next->type == CT_POS) || (next->type == CT_NEG))) { /* Need to wait until the next match to indent numbers */ num_token = next; } } } idx++; } else { LOG_FMT(LALBR, " no match\n"); } } if (chunk_is_newline(pc) || chunk_is_newline(next)) { idx = 0; } pc = chunk_get_next(pc); } while ((pc != NULL) && (pc->level > start->level)); }
/** * Scans a line for stuff to align on. * * We trigger on BRACE_OPEN, FPAREN_OPEN, ASSIGN, and COMMA. * We want to align the NEXT item. */ static chunk_t *scan_ib_line(chunk_t *start, bool first_pass) { chunk_t *pc; chunk_t *next; chunk_t *prev_match = NULL; int token_width; int idx = 0; bool last_was_comment = false; /* Skip past C99 "[xx] =" stuff */ if (start->type == CT_SQUARE_OPEN) { start->parent_type = CT_TSQUARE; start = chunk_get_next_type(start, CT_ASSIGN, start->level); start = chunk_get_next_ncnl(start); cpd.al_c99_array = true; } pc = start; if (pc != NULL) { LOG_FMT(LSIB, "%s: start=%s col %d/%d line %d\n", __func__, get_token_name(pc->type), pc->column, pc->orig_col, pc->orig_line); } while ((pc != NULL) && !chunk_is_newline(pc) && (pc->level >= start->level)) { //LOG_FMT(LSIB, "%s: '%.*s' col %d/%d line %d\n", __func__, // pc->len, pc->str, pc->column, pc->orig_col, pc->orig_line); next = chunk_get_next(pc); if ((next == NULL) || chunk_is_comment(next)) { /* do nothing */ } else if ((pc->type == CT_ASSIGN) || (pc->type == CT_BRACE_OPEN) || (pc->type == CT_BRACE_CLOSE) || (pc->type == CT_COMMA)) { token_width = space_col_align(pc, next); /*TODO: need to handle missing structure defs? ie NULL vs { ... } ?? */ /* Is this a new entry? */ if (idx >= cpd.al_cnt) { LOG_FMT(LSIB, " - New [%d] %.2d/%d - %10.10s\n", idx, pc->column, token_width, get_token_name(pc->type)); cpd.al[cpd.al_cnt].type = pc->type; cpd.al[cpd.al_cnt].col = pc->column; cpd.al[cpd.al_cnt].len = token_width; cpd.al_cnt++; idx++; last_was_comment = false; } else { /* expect to match stuff */ if (cpd.al[idx].type == pc->type) { LOG_FMT(LSIB, " - Match [%d] %.2d/%d - %10.10s", idx, pc->column, token_width, get_token_name(pc->type)); /* Shift out based on column */ if (prev_match == NULL) { if (pc->column > cpd.al[idx].col) { LOG_FMT(LSIB, " [ pc->col(%d) > col(%d) ] ", pc->column, cpd.al[idx].col); ib_shift_out(idx, pc->column - cpd.al[idx].col); cpd.al[idx].col = pc->column; } } else if (idx > 0) { int min_col_diff = pc->column - prev_match->column; int cur_col_diff = cpd.al[idx].col - cpd.al[idx - 1].col; if (cur_col_diff < min_col_diff) { LOG_FMT(LSIB, " [ min_col_diff(%d) > cur_col_diff(%d) ] ", min_col_diff, cur_col_diff); ib_shift_out(idx, min_col_diff - cur_col_diff); } } LOG_FMT(LSIB, " - now col %d, len %d\n", cpd.al[idx].col, cpd.al[idx].len); idx++; } } prev_match = pc; } last_was_comment = chunk_is_comment(pc); pc = chunk_get_next_nc(pc); } //if (last_was_comment && (cpd.al[cpd.al_cnt - 1].type == CT_COMMA)) //{ // cpd.al_cnt--; //} return(pc); }
/** * For a series of lines ending in a comment, align them. * The series ends when more than align_right_cmt_span newlines are found. * * Interesting info: * - least pysically allowed column * - intended column * - least original cmt column * * min_col is the minimum allowed column (based on prev token col/size) * cmt_col less than * * @param start Start point * @return pointer the last item looked at */ chunk_t *align_trailing_comments(chunk_t *start) { int min_col = 0; int min_orig = -1; chunk_t *pc = start; int nl_count = 0; ChunkStack cs; CmtAlignType cmt_type_start, cmt_type_cur; int col; int intended_col = cpd.settings[UO_align_right_cmt_at_col].n; cmt_type_start = get_comment_align_type(pc); LOG_FMT(LALADD, "%s: start on line=%d\n", __func__, pc->orig_line); /* Find the max column */ while ((pc != NULL) && (nl_count < cpd.settings[UO_align_right_cmt_span].n)) { if (((pc->flags & PCF_RIGHT_COMMENT) != 0) && (pc->column > 1)) { cmt_type_cur = get_comment_align_type(pc); if (cmt_type_cur == cmt_type_start) { col = 1 + (pc->brace_level * cpd.settings[UO_indent_columns].n); LOG_FMT(LALADD, "%s: line=%d col=%d max_col=%d pc->col=%d pc->len=%d %s\n", __func__, pc->orig_line, col, min_col, pc->column, pc->len, get_token_name(pc->type)); if ((min_orig < 0) || (min_orig > pc->column)) { min_orig = pc->column; } if (pc->column < col) { pc->column = col; } align_add(cs, pc, min_col, 1, true);//(intended_col < col)); nl_count = 0; } } if (chunk_is_newline(pc)) { nl_count += pc->nl_count; } pc = chunk_get_next(pc); } /* Start with the minimum original column */ col = min_orig; /* fall back to the intended column */ if ((intended_col > 0) && (col > intended_col)) { col = intended_col; } /* if less than allowed, bump it out */ if (col < min_col) { col = min_col; } /* bump out to the intended column */ if (col < intended_col) { col = intended_col; } LOG_FMT(LALADD, "%s: -- min_orig=%d intend=%d min_allowed=%d ==> col=%d\n", __func__, min_orig, intended_col, min_col, col); align_stack(cs, col, (intended_col != 0), LALTC); return(chunk_get_next(pc)); }
static void examine_brace(chunk_t *bopen) { LOG_FUNC_ENTRY(); chunk_t *next; chunk_t *prev = NULL; size_t semi_count = 0; size_t level = bopen->level + 1; bool hit_semi = false; bool was_fcn = false; size_t nl_max = cpd.settings[UO_mod_full_brace_nl].u; size_t nl_count = 0; size_t if_count = 0; int br_count = 0; LOG_FMT(LBRDEL, "%s: start on %zu : ", __func__, bopen->orig_line); chunk_t *pc = chunk_get_next_nc(bopen); while ((pc != NULL) && (pc->level >= level)) { if (pc->flags & PCF_IN_PREPROC) { LOG_FMT(LBRDEL, " PREPROC\n"); return; } if (chunk_is_newline(pc)) { nl_count += pc->nl_count; if ((nl_max > 0) && (nl_count > nl_max)) { LOG_FMT(LBRDEL, " exceeded %zu newlines\n", nl_max); return; } } else { if (pc->type == CT_BRACE_OPEN) { br_count++; } else if (pc->type == CT_BRACE_CLOSE) { br_count--; if (br_count == 0) { next = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((next == NULL) || (next->type != CT_BRACE_CLOSE)) { LOG_FMT(LBRDEL, " junk after close brace\n"); return; } } } else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF)) { if (br_count == 0) { if_count++; } } if (pc->level == level) { if ((semi_count > 0) && hit_semi) { /* should have bailed due to close brace level drop */ LOG_FMT(LBRDEL, " no close brace\n"); return; } LOG_FMT(LBRDEL, " [%s %zu-%zu]", pc->text(), pc->orig_line, semi_count); if (pc->type == CT_ELSE) { LOG_FMT(LBRDEL, " bailed on %s on line %zu\n", pc->text(), pc->orig_line); return; } was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE); if (chunk_is_semicolon(pc) || (pc->type == CT_IF) || (pc->type == CT_ELSEIF) || (pc->type == CT_FOR) || (pc->type == CT_DO) || (pc->type == CT_WHILE) || (pc->type == CT_SWITCH) || (pc->type == CT_USING_STMT) || ((pc->type == CT_BRACE_OPEN) && was_fcn)) { hit_semi |= chunk_is_semicolon(pc); if (++semi_count > 1) { LOG_FMT(LBRDEL, " bailed on %zu because of %s on line %zu\n", bopen->orig_line, pc->text(), pc->orig_line); return; } } } } prev = pc; pc = chunk_get_next_nc(pc); } if (pc == NULL) { LOG_FMT(LBRDEL, " NULL\n"); return; } LOG_FMT(LBRDEL, " - end on '%s' on line %zu. if_count=%zu semi_count=%zu\n", get_token_name(pc->type), pc->orig_line, if_count, semi_count); if (pc->type == CT_BRACE_CLOSE) { next = chunk_get_next_ncnl(pc); while ((next != NULL) && (next->type == CT_VBRACE_CLOSE)) { next = chunk_get_next_ncnl(next); } LOG_FMT(LBRDEL, " next is '%s'\n", get_token_name(next->type)); if ((if_count > 0) && ((next->type == CT_ELSE) || (next->type == CT_ELSEIF))) { LOG_FMT(LBRDEL, " bailed on because 'else' is next and %zu ifs\n", if_count); return; } if (semi_count > 0) { if (bopen->parent_type == CT_ELSE) { next = chunk_get_next_ncnl(bopen); if (next->type == CT_IF) { prev = chunk_get_prev_ncnl(bopen); LOG_FMT(LBRDEL, " else-if removing braces on line %zu and %zu\n", bopen->orig_line, pc->orig_line); chunk_del(bopen); chunk_del(pc); newline_del_between(prev, next); if (cpd.settings[UO_nl_else_if].a & AV_ADD) { newline_add_between(prev, next); } return; } } /* we have a pair of braces with only 1 statement inside */ convert_brace(bopen); convert_brace(pc); LOG_FMT(LBRDEL, " removing braces on line %zu and %zu\n", bopen->orig_line, pc->orig_line); } else { LOG_FMT(LBRDEL, " empty statement\n"); } } else { LOG_FMT(LBRDEL, " not a close brace? - '%s'\n", pc->text()); } } // examine_brace
void print_token(int token) { printf("Token: %s (%d)\n", get_token_name(token), token); if(token == IDENTIFIER) printf("\t'%ls'\n", identifier); if(token == INTEGER) printf("\t%d\n", integer); }
Error ScriptClassParser::_parse_type_constraints() { Token tk = get_token(); if (tk != TK_IDENTIFIER) { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } tk = get_token(); if (tk != TK_COLON) { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } while (true) { tk = get_token(); if (tk == TK_IDENTIFIER) { if (String(value) == "where") { return _parse_type_constraints(); } tk = get_token(); if (tk == TK_PERIOD) { while (true) { tk = get_token(); if (tk != TK_IDENTIFIER) { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } tk = get_token(); if (tk != TK_PERIOD) break; } } } if (tk == TK_COMMA) { continue; } else if (tk == TK_IDENTIFIER && String(value) == "where") { return _parse_type_constraints(); } else if (tk == TK_SYMBOL && String(value) == "(") { tk = get_token(); if (tk != TK_SYMBOL || String(value) != ")") { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } else if (tk == TK_OP_LESS) { Error err = _skip_generic_type_params(); if (err) return err; } else if (tk == TK_CURLY_BRACKET_OPEN) { return OK; } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } }
/** * Scan backwards to find the most appropriate spot to split the line * and insert a newline. * * See if this needs special function handling. * Scan backwards and find the best token for the split. * * @param start The first chunk that exceeded the limit */ static void split_line(chunk_t *start) { LOG_FMT(LSPLIT, "%s: line %d, col %d token:%s[%s] (IN_FUNC=%d) ", __func__, start->orig_line, start->column, start->str.c_str(), get_token_name(start->type), (start->flags & (PCF_IN_FCN_DEF | PCF_IN_FCN_CALL)) != 0); /** * break at maximum line length if ls_code_width is true */ if (cpd.settings[UO_ls_code_width].b) { } /* Check to see if we are in a for statement */ else if ((start->flags & PCF_IN_FOR) != 0) { LOG_FMT(LSPLIT, " ** FOR SPLIT **\n"); split_for_stmt(start); if (!is_past_width(start)) { return; } LOG_FMT(LSPLIT, "%s: for split didn't work\n", __func__); } /* If this is in a function call or prototype, split on commas or right * after the open paren */ else if (((start->flags & PCF_IN_FCN_DEF) != 0) || ((start->level == (start->brace_level + 1)) && ((start->flags & PCF_IN_FCN_CALL) != 0))) { LOG_FMT(LSPLIT, " ** FUNC SPLIT **\n"); if (cpd.settings[UO_ls_func_split_full].b) { split_fcn_params_full(start); if (!is_past_width(start)) { return; } } split_fcn_params(start); return; } /** * Try to find the best spot to split the line */ cw_entry ent; memset(&ent, 0, sizeof(ent)); chunk_t *pc = start; chunk_t *prev; while (((pc = chunk_get_prev(pc)) != NULL) && !chunk_is_newline(pc)) { if (pc->type != CT_SPACE) { try_split_here(ent, pc); /* break at maximum line length */ if ((ent.pc != NULL) && (cpd.settings[UO_ls_code_width].b)) break; } } if (ent.pc == NULL) { LOG_FMT(LSPLIT, "%s: TRY_SPLIT yielded NO SOLUTION for line %d at %s [%s]\n", __func__, start->orig_line, start->str.c_str(), get_token_name(start->type)); } else { LOG_FMT(LSPLIT, "%s: TRY_SPLIT yielded '%s' [%s] on line %d\n", __func__, ent.pc->str.c_str(), get_token_name(ent.pc->type), ent.pc->orig_line); } /* Break before the token instead of after it according to the pos_xxx rules */ if (((chunk_is_token(ent.pc, CT_ARITH) || chunk_is_token(ent.pc, CT_CARET)) && (cpd.settings[UO_pos_arith].tp & TP_LEAD)) || (chunk_is_token(ent.pc, CT_ASSIGN) && (cpd.settings[UO_pos_assign].tp & TP_LEAD)) || (chunk_is_token(ent.pc, CT_COMPARE) && (cpd.settings[UO_pos_compare].tp & TP_LEAD)) || ((chunk_is_token(ent.pc, CT_COND_COLON) || chunk_is_token(ent.pc, CT_QUESTION)) && (cpd.settings[UO_pos_conditional].tp & TP_LEAD)) || (chunk_is_token(ent.pc, CT_BOOL) && (cpd.settings[UO_pos_bool].tp & TP_LEAD))) { pc = ent.pc; } else { pc = chunk_get_next(ent.pc); } if (pc == NULL) { pc = start; /* Don't break before a close, comma, or colon */ if ((start->type == CT_PAREN_CLOSE) || (start->type == CT_PAREN_OPEN) || (start->type == CT_FPAREN_CLOSE) || (start->type == CT_FPAREN_OPEN) || (start->type == CT_SPAREN_CLOSE) || (start->type == CT_SPAREN_OPEN) || (start->type == CT_ANGLE_CLOSE) || (start->type == CT_BRACE_CLOSE) || (start->type == CT_COMMA) || (start->type == CT_SEMICOLON) || (start->type == CT_VSEMICOLON) || (start->len() == 0)) { LOG_FMT(LSPLIT, " ** NO GO **\n"); /*TODO: Add in logic to handle 'hard' limits by backing up a token */ return; } } /* add a newline before pc */ prev = chunk_get_prev(pc); if ((prev != NULL) && !chunk_is_newline(pc) && !chunk_is_newline(prev)) { int plen = (pc->len() < 5) ? pc->len() : 5; int slen = (start->len() < 5) ? start->len() : 5; LOG_FMT(LSPLIT, " '%.*s' [%s], started on token '%.*s' [%s]\n", plen, pc->str.c_str(), get_token_name(pc->type), slen, start->str.c_str(), get_token_name(start->type)); split_before_chunk(pc); } }
/** * 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) { LOG_FUNC_ENTRY(); 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->flags & PCF_IN_PREPROC) { LOG_FMT(LPARADD2, " -- bail on PP %s [%s] at line %d col %d, level %d\n", get_token_name(pc->type), pc->str.c_str(), pc->orig_line, pc->orig_col, pc->level); return; } if ((pc->type == CT_BOOL) || (pc->type == CT_QUESTION) || (pc->type == CT_COND_COLON) || (pc->type == CT_COMMA)) { LOG_FMT(LPARADD2, " -- %s [%s] at line %d col %d, level %d\n", get_token_name(pc->type), pc->str.c_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->str.c_str(), pc->orig_line, pc->orig_col, pc->level); hit_compare = true; } else if (chunk_is_paren_open(pc)) { next = chunk_skip_to_match(pc); 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_skip_to_match(pc); } } if (hit_compare && (ref != popen)) { add_parens_between(ref, pclose); } }
/** * 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_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] -- ", get_token_name(prev->type)); pc = chunk_get_next(prev); newline_add_before(pc); reindent_line(pc, min_col); cpd.changes++; } }
/** * This function parses or tokenizes the whole buffer into a list. * It has to do some tricks to parse preprocessors. * * If output_text() were called immediately after, two things would happen: * - trailing whitespace are removed. * - leading space & tabs are converted to the appropriate format. * * All the tokens are inserted before ref. If ref is NULL, they are inserted * at the end of the list. Line numbers are relative to the start of the data. */ void tokenize(const deque<int> &data, chunk_t *ref) { tok_ctx ctx(data); chunk_t chunk; chunk_t *pc = NULL; chunk_t *rprev = NULL; struct parse_frame frm; bool last_was_tab = false; int prev_sp = 0; cpd.unc_stage = US_TOKENIZE; memset(&frm, 0, sizeof(frm)); while (ctx.more()) { chunk.reset(); if (!parse_next(ctx, chunk)) { LOG_FMT(LERR, "%s:%d Bailed before the end?\n", cpd.filename, ctx.c.row); cpd.error_count++; break; } /* Don't create an entry for whitespace */ if (chunk.type == CT_WHITESPACE) { last_was_tab = chunk.after_tab; prev_sp = chunk.orig_prev_sp; continue; } chunk.orig_prev_sp = prev_sp; prev_sp = 0; if (chunk.type == CT_NEWLINE) { last_was_tab = chunk.after_tab; chunk.after_tab = false; chunk.str.clear(); } else if (chunk.type == CT_NL_CONT) { last_was_tab = chunk.after_tab; chunk.after_tab = false; chunk.str = "\\\n"; } else { chunk.after_tab = last_was_tab; last_was_tab = false; } /* Strip trailing whitespace (for CPP comments and PP blocks) */ while ((chunk.str.size() > 0) && ((chunk.str[chunk.str.size() - 1] == ' ') || (chunk.str[chunk.str.size() - 1] == '\t'))) { // If comment contains backslash '\' followed by whitespace chars, keep last one; // this will prevent it from turning '\' into line continuation. if ((chunk.str.size() > 1) && (chunk.str[chunk.str.size() - 2] == '\\')) { break; } chunk.str.pop_back(); } /* Store off the end column */ chunk.orig_col_end = ctx.c.col; /* Add the chunk to the list */ rprev = pc; if (rprev != NULL) { chunk_flags_set(pc, rprev->flags & PCF_COPY_FLAGS); /* a newline can't be in a preprocessor */ if (pc->type == CT_NEWLINE) { chunk_flags_clr(pc, PCF_IN_PREPROC); } } if (ref != NULL) { chunk.flags |= PCF_INSERTED; } else { chunk.flags &= ~PCF_INSERTED; } pc = chunk_add_before(&chunk, ref); /* A newline marks the end of a preprocessor */ if (pc->type == CT_NEWLINE) // || (pc->type == CT_COMMENT_MULTI)) { cpd.in_preproc = CT_NONE; cpd.preproc_ncnl_count = 0; } /* Special handling for preprocessor stuff */ if (cpd.in_preproc != CT_NONE) { chunk_flags_set(pc, PCF_IN_PREPROC); /* Count words after the preprocessor */ if (!chunk_is_comment(pc) && !chunk_is_newline(pc)) { cpd.preproc_ncnl_count++; } /* Figure out the type of preprocessor for #include parsing */ if (cpd.in_preproc == CT_PREPROC) { if ((pc->type < CT_PP_DEFINE) || (pc->type > CT_PP_OTHER)) { set_chunk_type(pc, CT_PP_OTHER); } cpd.in_preproc = pc->type; } } else { /* Check for a preprocessor start */ if ((pc->type == CT_POUND) && ((rprev == NULL) || (rprev->type == CT_NEWLINE))) { set_chunk_type(pc, CT_PREPROC); pc->flags |= PCF_IN_PREPROC; cpd.in_preproc = CT_PREPROC; } } if (pc->type == CT_NEWLINE) { LOG_FMT(LGUY, "%s(%d): (%d)<NL> col=%d\n", __func__, __LINE__, pc->orig_line, pc->orig_col); } else { LOG_FMT(LGUY, "%s(%d): text():%s, type:%s, orig_col=%d, orig_col_end=%d\n", __func__, __LINE__, pc->text(), get_token_name(pc->type), pc->orig_col, pc->orig_col_end); } } /* Set the cpd.newline string for this file */ if ((cpd.settings[UO_newlines].le == LE_LF) || ((cpd.settings[UO_newlines].le == LE_AUTO) && (cpd.le_counts[LE_LF] >= cpd.le_counts[LE_CRLF]) && (cpd.le_counts[LE_LF] >= cpd.le_counts[LE_CR]))) { /* LF line ends */ cpd.newline = "\n"; LOG_FMT(LLINEENDS, "Using LF line endings\n"); } else if ((cpd.settings[UO_newlines].le == LE_CRLF) || ((cpd.settings[UO_newlines].le == LE_AUTO) && (cpd.le_counts[LE_CRLF] >= cpd.le_counts[LE_LF]) && (cpd.le_counts[LE_CRLF] >= cpd.le_counts[LE_CR]))) { /* CRLF line ends */ cpd.newline = "\r\n"; LOG_FMT(LLINEENDS, "Using CRLF line endings\n"); } else { /* CR line ends */ cpd.newline = "\r"; LOG_FMT(LLINEENDS, "Using CR line endings\n"); } } // tokenize
Error ScriptClassParser::_skip_generic_type_params() { Token tk; while (true) { tk = get_token(); if (tk == TK_IDENTIFIER) { tk = get_token(); // Type specifications can end with "?" to denote nullable types, such as IList<int?> if (tk == TK_SYMBOL) { tk = get_token(); if (value.operator String() != "?") { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found unexpected symbol '" + value + "'"; error = true; return ERR_PARSE_ERROR; } if (tk != TK_OP_GREATER && tk != TK_COMMA) { error_str = "Nullable type symbol '?' is only allowed after an identifier, but found " + get_token_name(tk) + " next."; error = true; return ERR_PARSE_ERROR; } } if (tk == TK_PERIOD) { while (true) { tk = get_token(); if (tk != TK_IDENTIFIER) { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } tk = get_token(); if (tk != TK_PERIOD) break; } } if (tk == TK_OP_LESS) { Error err = _skip_generic_type_params(); if (err) return err; continue; } else if (tk == TK_OP_GREATER) { return OK; } else if (tk != TK_COMMA) { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } else if (tk == TK_OP_LESS) { error_str = "Expected " + get_token_name(TK_IDENTIFIER) + ", found " + get_token_name(TK_OP_LESS); error = true; return ERR_PARSE_ERROR; } else if (tk == TK_OP_GREATER) { return OK; } else { error_str = "Unexpected token: " + get_token_name(tk); error = true; return ERR_PARSE_ERROR; } } }
/** * 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(parse_frame_t *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); LOG_FMT(LTOK, "%s:%zu] %16s - tos:%zu/%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)) { chunk_flags_set(pc, PCF_EXPR_START | ((frm->stmt_count == 0) ? PCF_STMT_START : 0)); LOG_FMT(LSTMT, "%zu] 1.marked %s as %s start st:%d ex:%d\n", pc->orig_line, pc->text(), (pc->flags & PCF_STMT_START) ? "stmt" : "expr", frm->stmt_count, frm->expr_count); } frm->stmt_count++; frm->expr_count++; if (frm->sparen_count > 0) { chunk_flags_set(pc, PCF_IN_SPAREN); /* Mark everything in the a for statement */ for (int tmp = frm->pse_tos - 1; tmp >= 0; tmp--) { if (frm->pse[tmp].type == CT_FOR) { chunk_flags_set(pc, 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)) { set_chunk_parent(pc, 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) { 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))) { set_chunk_type(pc, (c_token_t)(frm->pse[frm->pse_tos].type + 1)); if (pc->type == CT_SPAREN_CLOSE) { frm->sparen_count--; chunk_flags_clr(pc, 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: %s:%zu Error: Unexpected '%s' for '%s', which was on line %zu\n", __func__, cpd.filename, pc->orig_line, pc->text(), 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 */ set_chunk_parent(pc, 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; set_chunk_parent(pc, CT_WHILE_OF_DO); } else { LOG_FMT(LWARN, "%s:%zu: 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 */ c_token_t 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)) { chunk_t *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) { set_chunk_type(pc, CT_SPAREN_OPEN); parent = frm->pse[frm->pse_tos].type; frm->sparen_count++; } else if (prev->type == CT_FUNCTION) { set_chunk_type(pc, CT_FPAREN_OPEN); parent = CT_FUNCTION; } /* NS_ENUM and NS_OPTIONS are followed by a (type, name) pair */ else if ((prev->type == CT_ENUM) && (cpd.lang_flags & LANG_OC)) { /* Treat both as CT_ENUM since the syntax is identical */ set_chunk_type(pc, CT_FPAREN_OPEN); parent = CT_ENUM; } 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; } /* Carry through CT_ENUM parent in NS_ENUM (type, name) { */ else if ((prev->type == CT_FPAREN_CLOSE) && (cpd.lang_flags & LANG_OC) && (prev->parent_type == CT_ENUM)) { parent = CT_ENUM; } 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; set_chunk_parent(pc, parent); } pattern_class patcls = get_token_pattern_class(pc->type); /** Create a stack entry for complex statements: */ /** if, elseif, switch, for, while, synchronized, using, lock, with, version, CT_D_SCOPE_IF */ 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)) { set_chunk_type(pc, 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)) || (pc->type == CT_COLON) || (pc->type == CT_OC_END) || (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: %zu> reset1 stmt on %s\n", __func__, pc->orig_line, pc->text()); 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_CARET) || (pc->type == CT_ANGLE_OPEN) || (pc->type == CT_ANGLE_CLOSE) || (pc->type == CT_RETURN) || (pc->type == CT_THROW) || (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: %zu> reset expr on %s\n", __func__, pc->orig_line, pc->text()); } else if (pc->type == CT_BRACE_CLOSE) { if (!cpd.consumed) { if (!cpd.unc_off_used) { /* fatal error */ fprintf(stderr, "Unmatched BRACE_CLOSE\nat line=%zu, column=%zu\n", pc->orig_line, pc->orig_col); exit(EXIT_FAILURE); } } } } // parse_cleanup
void SSceneSummary::FillProp(PropItemVec& items) { // fill items ButtonValue* B =PHelper().CreateButton (items,"Common\\File","Export...",0); B->OnBtnClickEvent.bind(this,&SSceneSummary::OnFileClick); // fill items PHelper().CreateCaption(items,"Common\\Level Name", Scene->m_LevelOp.m_FNLevelPath.c_str()); PHelper().CreateCaption(items,"Geometry\\Bounding\\Min", shared_str().printf("{%3.2f, %3.2f, %3.2f}",VPUSH(bbox.min))); PHelper().CreateCaption(items,"Geometry\\Bounding\\Max", shared_str().printf("{%3.2f, %3.2f, %3.2f}",VPUSH(bbox.max))); PHelper().CreateCaption(items,"Geometry\\Mesh\\Total Faces", shared_str().printf("%d",face_cnt)); PHelper().CreateCaption(items,"Geometry\\Mesh\\Total Vertices", shared_str().printf("%d",vert_cnt)); PHelper().CreateCaption(items,"Geometry\\MU\\Objects", shared_str().printf("%d",mu_objects.size())); PHelper().CreateCaption(items,"Geometry\\MU\\References", shared_str().printf("%d",object_mu_ref_cnt)); PHelper().CreateCaption(items,"Geometry\\LOD\\Objects", shared_str().printf("%d",lod_objects.size())); PHelper().CreateCaption(items,"Geometry\\LOD\\References", shared_str().printf("%d",object_lod_ref_cnt)); PHelper().CreateCaption(items,"Visibility\\HOM\\Faces", shared_str().printf("%d",hom_face_cnt)); PHelper().CreateCaption(items,"Visibility\\HOM\\Vertices", shared_str().printf("%d",hom_vert_cnt)); PHelper().CreateCaption(items,"Visibility\\Sectors", shared_str().printf("%d",sector_cnt)); PHelper().CreateCaption(items,"Visibility\\Portals", shared_str().printf("%d",portal_cnt)); PHelper().CreateCaption(items,"Lights\\Count", shared_str().printf("%d",light_point_cnt+light_spot_cnt)); PHelper().CreateCaption(items,"Lights\\By Type\\Point", shared_str().printf("%d",light_point_cnt)); PHelper().CreateCaption(items,"Lights\\By Type\\Spot", shared_str().printf("%d",light_spot_cnt)); PHelper().CreateCaption(items,"Lights\\By Usage\\Dynamic", shared_str().printf("%d",light_dynamic_cnt)); PHelper().CreateCaption(items,"Lights\\By Usage\\Static", shared_str().printf("%d",light_static_cnt)); PHelper().CreateCaption(items,"Lights\\By Usage\\Breakable",shared_str().printf("%d",light_breakable_cnt)); PHelper().CreateCaption(items,"Lights\\By Usage\\Procedural",shared_str().printf("%d",light_procedural_cnt)); PHelper().CreateCaption(items,"Glows\\Count", shared_str().printf("%d",glow_cnt)); // objects for (OISetIt o_it=objects.begin(); o_it!=objects.end(); o_it++){ SObjectInfo* info= (SObjectInfo*)(&(*o_it)); info->FillProp (items,"Objects"); } // textures CaptionValue* total_count=PHelper().CreateCaption (items,"Textures\\Count",""); CaptionValue* total_mem = PHelper().CreateCaption (items,"Textures\\Memory Usage",""); u32 total_mem_usage = 0; ButtonValue* BB = PHelper().CreateButton (items,"Textures\\Highlight Textures\\Command", "Pixel Density,Clear", ButtonValue::flFirstOnly); BB->OnBtnClickEvent.bind(this,&SSceneSummary::OnHighlightClick); for (PDVecIt pd_it=pm_colors.begin(); pd_it!=pm_colors.end(); pd_it++){ string128 tmp; sprintf (tmp,"Textures\\Highlight Textures\\Color Legend\\Item #%d",pd_it-pm_colors.begin()); PHelper().CreateColor(items,PrepareKey(tmp,"Color").c_str(),&pd_it->color); FloatValue* V = PHelper().CreateFloat(items,PrepareKey(tmp,"Weight (p/m)").c_str(),&pd_it->pm,0,1000000,1,0); V->OnAfterEditEvent.bind(this,&SSceneSummary::OnWeightAfterEditClick); V->tag = pd_it-pm_colors.begin(); } for (u32 stt=sttFirst; stt<sttLast; stt++){ LPCSTR nm = get_token_name(summary_texture_type_tokens,stt); if (nm&&nm[0]){ u32 cur_mem_usage = 0; float cur_area = 0; shared_str pref = PrepareKey("Textures",nm); CaptionValue* mem = PHelper().CreateCaption(items,PrepareKey(pref.c_str(),"Memory Usage").c_str(), ""); CaptionValue* area = PHelper().CreateCaption(items,PrepareKey(pref.c_str(),"Effective Area").c_str(), ""); for (TISetIt it=textures.begin(); it!=textures.end(); it++){ STextureInfo* info= (STextureInfo*)(&(*it)); if (info->type==stt){ cur_area += info->effective_area; info->FillProp(items,pref.c_str(),cur_mem_usage); } } mem->ApplyValue (shared_str().printf("%d Kb",iFloor(cur_mem_usage/1024))); area->ApplyValue (shared_str().printf("%3.2f m^2",cur_area)); total_mem_usage += cur_mem_usage; } } total_count->ApplyValue (shared_str().printf("%d", textures.size())); total_mem->ApplyValue (shared_str().printf("%d Kb", iFloor(total_mem_usage/1024))); // sound PHelper().CreateCaption (items,"Sounds\\Occluder\\Faces", shared_str().printf("%d",snd_occ_face_cnt)); PHelper().CreateCaption (items,"Sounds\\Occluder\\Vertices", shared_str().printf("%d",snd_occ_vert_cnt)); PHelper().CreateCaption (items,"Sounds\\Sources", shared_str().printf("%d",sound_source_cnt)); PHelper().CreateCaption (items,"Sounds\\Waves\\Count", shared_str().printf("%d",waves.size())); for (RStringSetIt w_it=waves.begin(); w_it!=waves.end(); w_it++) PHelper().CreateCaption(items,PrepareKey("Sounds\\Waves",w_it->c_str()),"-"); // particles PHelper().CreateCaption (items,"Particle System\\Sources", shared_str().printf("%d",pe_static_cnt)); PHelper().CreateCaption (items,"Particle System\\Refs\\Count", shared_str().printf("%d",pe_static.size())); for (RStringSetIt pe_it=pe_static.begin(); pe_it!=pe_static.end(); pe_it++) PHelper().CreateCaption(items,PrepareKey("Particle System\\Refs",pe_it->c_str()),"-"); }
static bool handle_complex_close(parse_frame_t *frm, chunk_t *pc) { LOG_FUNC_ENTRY(); chunk_t *next; if (frm->pse[frm->pse_tos].stage == BS_PAREN1) { if ((pc->next != NULL) && (pc->next->type == CT_WHEN)) { frm->pse[frm->pse_tos].type = pc->type; frm->pse[frm->pse_tos].stage = BS_CATCH_WHEN; return(true); } else { /* 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:%zu 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); } // handle_complex_close
static void process_if_chain(chunk_t *br_start) { LOG_FUNC_ENTRY(); chunk_t *braces[256]; int br_cnt = 0; bool must_have_braces = false; chunk_t *pc = br_start; LOG_FMT(LBRCH, "%s: if starts on line %zu\n", __func__, br_start->orig_line); while (pc != NULL) { if (pc->type == CT_BRACE_OPEN) { bool tmp = can_remove_braces(pc); LOG_FMT(LBRCH, " [%d] line %zu - can%s remove %s\n", br_cnt, pc->orig_line, tmp ? "" : "not", get_token_name(pc->type)); if (!tmp) { must_have_braces = true; } } else { bool tmp = should_add_braces(pc); if (tmp) { must_have_braces = true; } LOG_FMT(LBRCH, " [%d] line %zu - %s %s\n", br_cnt, pc->orig_line, tmp ? "should add" : "ignore", get_token_name(pc->type)); } braces[br_cnt++] = pc; chunk_t *br_close = chunk_skip_to_match(pc, CNAV_PREPROC); if (br_close == NULL) { break; } braces[br_cnt++] = br_close; pc = chunk_get_next_ncnl(br_close, CNAV_PREPROC); if ((pc == NULL) || (pc->type != CT_ELSE)) { break; } if (cpd.settings[UO_mod_full_brace_if_chain_only].b) { // There is an 'else' - we want full braces. must_have_braces = true; } pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_ELSEIF)) { while ((pc != NULL) && (pc->type != CT_VBRACE_OPEN) && (pc->type != CT_BRACE_OPEN)) { pc = chunk_get_next_ncnl(pc, CNAV_PREPROC); } } if (pc == NULL) { break; } if ((pc->type != CT_BRACE_OPEN) && (pc->type != CT_VBRACE_OPEN)) { break; } } if (must_have_braces) { LOG_FMT(LBRCH, "%s: add braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { chunk_flags_set(braces[br_cnt], PCF_KEEP_BRACE); if ((braces[br_cnt]->type == CT_VBRACE_OPEN) || (braces[br_cnt]->type == CT_VBRACE_CLOSE)) { LOG_FMT(LBRCH, " %zu", braces[br_cnt]->orig_line); convert_vbrace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " {%zu}", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } else if (cpd.settings[UO_mod_full_brace_if_chain].b) { // This might run because either UO_mod_full_brace_if_chain or UO_mod_full_brace_if_chain_only is used. // We only want to remove braces if the first one is active. LOG_FMT(LBRCH, "%s: remove braces on lines[%d]:", __func__, br_cnt); while (--br_cnt >= 0) { if ((braces[br_cnt]->type == CT_BRACE_OPEN) || (braces[br_cnt]->type == CT_BRACE_CLOSE)) { LOG_FMT(LBRCH, " {%zu}", braces[br_cnt]->orig_line); convert_brace(braces[br_cnt]); } else { LOG_FMT(LBRCH, " %zu", braces[br_cnt]->orig_line); } braces[br_cnt] = NULL; } LOG_FMT(LBRCH, "\n"); } } // process_if_chain
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; /* 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 '[]' */ pc->type = CT_TSQUARE; pc->str = "[]"; chunk_del(next); pc->orig_col_end += 1; } } 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) != 0)) { pc->type = CT_MEMBER; } /* Determine the version stuff (D only) */ if (pc->type == CT_D_VERSION) { if (next->type == CT_PAREN_OPEN) { pc->type = 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++; } pc->type = CT_WORD; } } /* Determine the scope stuff (D only) */ if (pc->type == CT_D_SCOPE) { if (next->type == CT_PAREN_OPEN) { pc->type = CT_D_SCOPE_IF; } else { pc->type = 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)) { pc->type = CT_WORD; } if ((pc->type == CT_ENUM) && (next->type == CT_CLASS)) { next->type = 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)) { 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)) { /* 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)) { check_template(pc); } else { /* convert CT_ANGLE_OPEN to CT_COMPARE */ pc->type = CT_COMPARE; } } 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 { next = handle_double_angle_close(pc); } } 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 '!' (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))) { pc->type = CT_D_TEMPLATE; } /* handle "version(unittest) { }" vs "unittest { }" */ if (prev && (pc->type == CT_UNITTEST) && (prev->type == CT_PAREN_OPEN)) { pc->type = CT_WORD; } } 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; } } /* 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])) { 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 >> - 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 = "()"; next->type = 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++; next->type = CT_OPERATOR_VAL; chunk_del(tmp2); } 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. */ 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; } /* 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); } 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->str.c_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) || 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) { 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) || 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)) { 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) && unc_isalpha(*tmp->str)) { tmp->type = 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)) { tmp->type = 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)) { pc->type = CT_WORD; } if ((pc->type == CT_DO) && (chunk_is_token(prev, CT_MINUS) || chunk_is_token(next, CT_SQUARE_CLOSE))) { pc->type = 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))) { pc->type = 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) { 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; } } 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->str.c_str(), get_token_name(tmp->type)); tmp->type = 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)) { 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; } } /* 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; } } } /* 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->str += next->str; 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; } if (((pc->type == CT_USING) || ((pc->type == CT_TRY) && (cpd.lang_flags & LANG_JAVA))) && (next->type == CT_PAREN_OPEN)) { pc->type = 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) { pc->type = 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)) { pc->type = CT_QUALIFIER; } /* TODO: determine other stuff here */ prev = pc; pc = next; next = chunk_get_next_ncnl(pc); } }
static bool can_remove_braces(chunk_t *bopen) { LOG_FUNC_ENTRY(); chunk_t *prev = NULL; size_t semi_count = 0; size_t level = bopen->level + 1; bool hit_semi = false; bool was_fcn = false; size_t nl_max = cpd.settings[UO_mod_full_brace_nl].u; size_t nl_count = 0; size_t if_count = 0; int br_count = 0; /* Cannot remove braces inside a preprocessor */ if (bopen->flags & PCF_IN_PREPROC) { return(false); } chunk_t *pc = chunk_get_next_ncnl(bopen, CNAV_PREPROC); if ((pc != NULL) && (pc->type == CT_BRACE_CLOSE)) { /* Can't remove empty statement */ return(false); } LOG_FMT(LBRDEL, "%s: start on %zu : ", __func__, bopen->orig_line); pc = chunk_get_next_nc(bopen, CNAV_ALL); while ((pc != NULL) && (pc->level >= level)) { if (pc->flags & PCF_IN_PREPROC) { /* Cannot remove braces that contain a preprocessor */ return(false); } if (chunk_is_newline(pc)) { nl_count += pc->nl_count; if ((nl_max > 0) && (nl_count > nl_max)) { LOG_FMT(LBRDEL, " exceeded %zu newlines\n", nl_max); return(false); } } else { if (pc->type == CT_BRACE_OPEN) { br_count++; } else if (pc->type == CT_BRACE_CLOSE) { br_count--; } else if ((pc->type == CT_IF) || (pc->type == CT_ELSEIF)) { if (br_count == 0) { if_count++; } } if (pc->level == level) { if ((semi_count > 0) && hit_semi) { /* should have bailed due to close brace level drop */ LOG_FMT(LBRDEL, " no close brace\n"); return(false); } LOG_FMT(LBRDEL, " [%s %zu-%zu]", pc->text(), pc->orig_line, semi_count); if (pc->type == CT_ELSE) { LOG_FMT(LBRDEL, " bailed on %s on line %zu\n", pc->text(), pc->orig_line); return(false); } was_fcn = (prev != NULL) && (prev->type == CT_FPAREN_CLOSE); if (chunk_is_semicolon(pc) || (pc->type == CT_IF) || (pc->type == CT_ELSEIF) || (pc->type == CT_FOR) || (pc->type == CT_DO) || (pc->type == CT_WHILE) || (pc->type == CT_USING_STMT) || ((pc->type == CT_BRACE_OPEN) && was_fcn)) { hit_semi |= chunk_is_semicolon(pc); if (++semi_count > 1) { LOG_FMT(LBRDEL, " bailed on %zu because of %s on line %zu\n", bopen->orig_line, pc->text(), pc->orig_line); return(false); } } } } prev = pc; pc = chunk_get_next_nc(pc); } if (pc == NULL) { LOG_FMT(LBRDEL, " NULL\n"); return(false); } if ((pc->type == CT_BRACE_CLOSE) && (pc->parent_type == CT_IF)) { chunk_t *next = chunk_get_next_ncnl(pc, CNAV_PREPROC); prev = chunk_get_prev_ncnl(pc, CNAV_PREPROC); if ((next != NULL) && (next->type == CT_ELSE) && ((prev->type == CT_BRACE_CLOSE) || (prev->type == CT_VBRACE_CLOSE)) && (prev->parent_type == CT_IF)) { LOG_FMT(LBRDEL, " - bailed on '%s'[%s] on line %zu due to 'if' and 'else' sequence\n", get_token_name(pc->type), get_token_name(pc->parent_type), pc->orig_line); return(false); } } LOG_FMT(LBRDEL, " - end on '%s' on line %zu. if_count=%zu semi_count=%zu\n", get_token_name(pc->type), pc->orig_line, if_count, semi_count); return((pc->type == CT_BRACE_CLOSE) && (pc->pp_level == bopen->pp_level)); } // can_remove_braces
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
LPCSTR STextureParams::FormatString () { return get_token_name(tfmt_token,fmt); }