From 80250c0729d382aa60b4c6ff6210b66b470ad40b Mon Sep 17 00:00:00 2001 From: Kurtis Rader Date: Mon, 2 May 2016 17:22:44 -0700 Subject: [PATCH] restyle parser module to match project style Reduces lint errors from 72 to 44 (-43%). Line count from 1698 to 1313 (-23%). Another step in resolving issue #2902. --- src/parse_constants.h | 45 -- src/parser.cpp | 1025 +++++++++++++++------------------------ src/parser.h | 448 +++++++---------- src/parser_keywords.cpp | 58 +-- src/parser_keywords.h | 46 +- 5 files changed, 596 insertions(+), 1026 deletions(-) diff --git a/src/parse_constants.h b/src/parse_constants.h index c43ba7de9..01580d151 100644 --- a/src/parse_constants.h +++ b/src/parse_constants.h @@ -268,49 +268,4 @@ void parse_error_offset_source_start(parse_error_list_t *errors, size_t amt); #define ERROR_BAD_COMMAND_ASSIGN_ERR_MSG \ _(L"Unsupported use of '='. In fish, please use 'set %ls %ls'.") -/// While block description. -#define WHILE_BLOCK N_(L"'while' block") - -/// For block description. -#define FOR_BLOCK N_(L"'for' block") - -/// Breakpoint block. -#define BREAKPOINT_BLOCK N_(L"Block created by breakpoint") - -/// If block description. -#define IF_BLOCK N_(L"'if' conditional block") - -/// Function definition block description. -#define FUNCTION_DEF_BLOCK N_(L"function definition block") - -/// Function invocation block description. -#define FUNCTION_CALL_BLOCK N_(L"function invocation block") - -/// Function invocation block description. -#define FUNCTION_CALL_NO_SHADOW_BLOCK N_(L"function invocation block with no variable shadowing") - -/// Switch block description. -#define SWITCH_BLOCK N_(L"'switch' block") - -/// Fake block description. -#define FAKE_BLOCK N_(L"unexecutable block") - -/// Top block description. -#define TOP_BLOCK N_(L"global root block") - -/// Command substitution block description. -#define SUBST_BLOCK N_(L"command substitution block") - -/// Begin block description. -#define BEGIN_BLOCK N_(L"'begin' unconditional block") - -/// Source block description. -#define SOURCE_BLOCK N_(L"Block created by the . builtin") - -/// Source block description. -#define EVENT_BLOCK N_(L"event handler block") - -/// Unknown block description. -#define UNKNOWN_BLOCK N_(L"unknown/invalid block") - #endif diff --git a/src/parser.cpp b/src/parser.cpp index 9202d7fd0..ff10ea8ed 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,274 +1,190 @@ -/** \file parser.c - -The fish parser. Contains functions for parsing and evaluating code. -*/ +// The fish parser. Contains functions for parsing and evaluating code. +#include +#include #include #include -#include #include #include -#include -#include "fallback.h" // IWYU pragma: keep #include "common.h" -#include "wutil.h" // IWYU pragma: keep -#include "proc.h" -#include "parser.h" -#include "function.h" #include "env.h" +#include "event.h" #include "expand.h" +#include "fallback.h" // IWYU pragma: keep +#include "function.h" +#include "intern.h" +#include "parse_constants.h" +#include "parse_execution.h" +#include "parse_tree.h" +#include "parse_util.h" +#include "parser.h" +#include "proc.h" #include "reader.h" #include "sanity.h" -#include "event.h" -#include "intern.h" -#include "parse_util.h" -#include "parse_tree.h" -#include "parse_execution.h" -#include "parse_constants.h" +#include "wutil.h" // IWYU pragma: keep class io_chain_t; -/** - Error for evaluating in illegal scope -*/ -#define INVALID_SCOPE_ERR_MSG _( L"Tried to evaluate commands using invalid block type '%ls'" ) +/// Error for evaluating in illegal scope. +#define INVALID_SCOPE_ERR_MSG _(L"Tried to evaluate commands using invalid block type '%ls'") -/** - While block description -*/ -#define WHILE_BLOCK N_( L"'while' block" ) +/// While block description. +#define WHILE_BLOCK N_(L"'while' block") -/** - For block description -*/ -#define FOR_BLOCK N_( L"'for' block" ) +/// For block description. +#define FOR_BLOCK N_(L"'for' block") -/** - Breakpoint block -*/ -#define BREAKPOINT_BLOCK N_( L"Block created by breakpoint" ) +/// Breakpoint block. +#define BREAKPOINT_BLOCK N_(L"Block created by breakpoint") -/** - If block description -*/ -#define IF_BLOCK N_( L"'if' conditional block" ) +/// If block description. +#define IF_BLOCK N_(L"'if' conditional block") -/** - Function definition block description -*/ -#define FUNCTION_DEF_BLOCK N_( L"function definition block" ) +/// Function definition block description. +#define FUNCTION_DEF_BLOCK N_(L"function definition block") -/** - Function invocation block description -*/ -#define FUNCTION_CALL_BLOCK N_( L"function invocation block" ) +/// Function invocation block description. +#define FUNCTION_CALL_BLOCK N_(L"function invocation block") -/** - Function invocation block description -*/ -#define FUNCTION_CALL_NO_SHADOW_BLOCK N_( L"function invocation block with no variable shadowing" ) +/// Function invocation block description. +#define FUNCTION_CALL_NO_SHADOW_BLOCK N_(L"function invocation block with no variable shadowing") -/** - Switch block description -*/ -#define SWITCH_BLOCK N_( L"'switch' block" ) +/// Switch block description. +#define SWITCH_BLOCK N_(L"'switch' block") -/** - Fake block description -*/ -#define FAKE_BLOCK N_( L"unexecutable block" ) +/// Fake block description. +#define FAKE_BLOCK N_(L"unexecutable block") -/** - Top block description -*/ -#define TOP_BLOCK N_( L"global root block" ) +/// Top block description. +#define TOP_BLOCK N_(L"global root block") -/** - Command substitution block description -*/ -#define SUBST_BLOCK N_( L"command substitution block" ) +/// Command substitution block description. +#define SUBST_BLOCK N_(L"command substitution block") -/** - Begin block description -*/ -#define BEGIN_BLOCK N_( L"'begin' unconditional block" ) +/// Begin block description. +#define BEGIN_BLOCK N_(L"'begin' unconditional block") -/** - Source block description -*/ -#define SOURCE_BLOCK N_( L"Block created by the . builtin" ) +/// Source block description. +#define SOURCE_BLOCK N_(L"Block created by the . builtin") -/** - Source block description -*/ -#define EVENT_BLOCK N_( L"event handler block" ) +/// Source block description. +#define EVENT_BLOCK N_(L"event handler block") -/** - Unknown block description -*/ -#define UNKNOWN_BLOCK N_( L"unknown/invalid block" ) +/// Unknown block description. +#define UNKNOWN_BLOCK N_(L"unknown/invalid block") - -/** - Datastructure to describe a block type, like while blocks, command substitution blocks, etc. -*/ -struct block_lookup_entry -{ - - /** - The block type id. The legal values are defined in parser.h. - */ +/// Datastructure to describe a block type, like while blocks, command substitution blocks, etc. +struct block_lookup_entry { + // The block type id. The legal values are defined in parser.h. block_type_t type; - - /** - The name of the builtin that creates this type of block, if any. - */ + // The name of the builtin that creates this type of block, if any. const wchar_t *name; - - /** - A description of this block type - */ + // A description of this block type. const wchar_t *desc; -} -; - -/** - List of all legal block types -*/ -static const struct block_lookup_entry block_lookup[]= -{ - { WHILE, L"while", WHILE_BLOCK }, - { FOR, L"for", FOR_BLOCK }, - { IF, L"if", IF_BLOCK }, - { FUNCTION_DEF, L"function", FUNCTION_DEF_BLOCK }, - { FUNCTION_CALL, 0, FUNCTION_CALL_BLOCK }, - { FUNCTION_CALL_NO_SHADOW, 0, FUNCTION_CALL_NO_SHADOW_BLOCK }, - { SWITCH, L"switch", SWITCH_BLOCK }, - { FAKE, 0, FAKE_BLOCK }, - { TOP, 0, TOP_BLOCK }, - { SUBST, 0, SUBST_BLOCK }, - { BEGIN, L"begin", BEGIN_BLOCK }, - { SOURCE, L".", SOURCE_BLOCK }, - { EVENT, 0, EVENT_BLOCK }, - { BREAKPOINT, L"breakpoint", BREAKPOINT_BLOCK }, - { (block_type_t)0, 0, 0 } }; +/// List of all legal block types. +static const struct block_lookup_entry block_lookup[] = { + {WHILE, L"while", WHILE_BLOCK}, + {FOR, L"for", FOR_BLOCK}, + {IF, L"if", IF_BLOCK}, + {FUNCTION_DEF, L"function", FUNCTION_DEF_BLOCK}, + {FUNCTION_CALL, 0, FUNCTION_CALL_BLOCK}, + {FUNCTION_CALL_NO_SHADOW, 0, FUNCTION_CALL_NO_SHADOW_BLOCK}, + {SWITCH, L"switch", SWITCH_BLOCK}, + {FAKE, 0, FAKE_BLOCK}, + {TOP, 0, TOP_BLOCK}, + {SUBST, 0, SUBST_BLOCK}, + {BEGIN, L"begin", BEGIN_BLOCK}, + {SOURCE, L".", SOURCE_BLOCK}, + {EVENT, 0, EVENT_BLOCK}, + {BREAKPOINT, L"breakpoint", BREAKPOINT_BLOCK}, + {(block_type_t)0, 0, 0}}; + // Given a file path, return something nicer. Currently we just "unexpand" tildes. -static wcstring user_presentable_path(const wcstring &path) -{ +static wcstring user_presentable_path(const wcstring &path) { return replace_home_directory_with_tilde(path); } +parser_t::parser_t() : cancellation_requested(false), is_within_fish_initialization(false) {} -parser_t::parser_t() : - cancellation_requested(false), - is_within_fish_initialization(false) -{ -} - -/* A pointer to the principal parser (which is a static local) */ +/// A pointer to the principal parser (which is a static local). static parser_t *s_principal_parser = NULL; -parser_t &parser_t::principal_parser(void) -{ +parser_t &parser_t::principal_parser(void) { ASSERT_IS_NOT_FORKED_CHILD(); ASSERT_IS_MAIN_THREAD(); static parser_t parser; - if (! s_principal_parser) - { + if (!s_principal_parser) { s_principal_parser = &parser; } return parser; } -void parser_t::set_is_within_fish_initialization(bool flag) -{ +void parser_t::set_is_within_fish_initialization(bool flag) { is_within_fish_initialization = flag; } -void parser_t::skip_all_blocks(void) -{ - /* Tell all blocks to skip */ - if (s_principal_parser) - { +void parser_t::skip_all_blocks(void) { + // Tell all blocks to skip. + if (s_principal_parser) { s_principal_parser->cancellation_requested = true; - //write(2, "Cancelling blocks\n", strlen("Cancelling blocks\n")); - for (size_t i=0; i < s_principal_parser->block_count(); i++) - { + // write(2, "Cancelling blocks\n", strlen("Cancelling blocks\n")); + for (size_t i = 0; i < s_principal_parser->block_count(); i++) { s_principal_parser->block_at_index(i)->skip = true; } } } -void parser_t::push_block(block_t *new_current) -{ +void parser_t::push_block(block_t *new_current) { const enum block_type_t type = new_current->type(); new_current->src_lineno = parser_t::get_lineno(); const wchar_t *filename = parser_t::current_filename(); - if (filename != NULL) - { + if (filename != NULL) { new_current->src_filename = intern(filename); } const block_t *old_current = this->current_block(); - if (old_current && old_current->skip) - { + if (old_current && old_current->skip) { new_current->skip = true; } - /* - New blocks should be skipped if the outer block is skipped, - except TOP ans SUBST block, which open up new environments. Fake - blocks should always be skipped. Rather complicated... :-( - */ + // New blocks should be skipped if the outer block is skipped, except TOP ans SUBST block, which + // open up new environments. Fake blocks should always be skipped. Rather complicated... :-( new_current->skip = old_current ? old_current->skip : 0; - /* - Type TOP and SUBST are never skipped - */ - if (type == TOP || type == SUBST) - { + // Type TOP and SUBST are never skipped. + if (type == TOP || type == SUBST) { new_current->skip = 0; } - /* - Fake blocks and function definition blocks are never executed - */ - if (type == FAKE || type == FUNCTION_DEF) - { + // Fake blocks and function definition blocks are never executed. + if (type == FAKE || type == FUNCTION_DEF) { new_current->skip = 1; } new_current->job = 0; - new_current->loop_status=LOOP_NORMAL; + new_current->loop_status = LOOP_NORMAL; this->block_stack.push_back(new_current); - // Types TOP and SUBST are not considered blocks for the purposes of `status -b` - if (type != TOP && type != SUBST) - { + // Types TOP and SUBST are not considered blocks for the purposes of `status -b`. + if (type != TOP && type != SUBST) { is_block = 1; } - if ((new_current->type() != FUNCTION_DEF) && - (new_current->type() != FAKE) && - (new_current->type() != TOP)) - { + if ((new_current->type() != FUNCTION_DEF) && (new_current->type() != FAKE) && + (new_current->type() != TOP)) { env_push(type == FUNCTION_CALL); new_current->wants_pop_env = true; } } -void parser_t::pop_block() -{ - if (block_stack.empty()) - { - debug(1, - L"function %s called on empty block stack.", - __func__); +void parser_t::pop_block() { + if (block_stack.empty()) { + debug(1, L"function %s called on empty block stack.", __func__); bugreport(); return; } @@ -276,18 +192,16 @@ void parser_t::pop_block() block_t *old = block_stack.back(); block_stack.pop_back(); - if (old->wants_pop_env) - env_pop(); + if (old->wants_pop_env) env_pop(); delete old; - // Figure out if `status -b` should consider us to be in a block now - int new_is_block=0; - for (std::vector::const_iterator it = block_stack.begin(), end = block_stack.end(); it != end; ++it) - { + // Figure out if `status -b` should consider us to be in a block now. + int new_is_block = 0; + for (std::vector::const_iterator it = block_stack.begin(), end = block_stack.end(); + it != end; ++it) { const enum block_type_t type = (*it)->type(); - if (type != TOP && type != SUBST) - { + if (type != TOP && type != SUBST) { new_is_block = 1; break; } @@ -295,37 +209,29 @@ void parser_t::pop_block() is_block = new_is_block; } -void parser_t::pop_block(const block_t *expected) -{ +void parser_t::pop_block(const block_t *expected) { assert(expected == this->current_block()); this->pop_block(); } -const wchar_t *parser_t::get_block_desc(int block) const -{ - for (size_t i=0; block_lookup[i].desc; i++) - { - if (block_lookup[i].type == block) - { +const wchar_t *parser_t::get_block_desc(int block) const { + for (size_t i = 0; block_lookup[i].desc; i++) { + if (block_lookup[i].type == block) { return _(block_lookup[i].desc); } } return _(UNKNOWN_BLOCK); } -wcstring parser_t::block_stack_description() const -{ +wcstring parser_t::block_stack_description() const { wcstring result; size_t idx = this->block_count(); size_t spaces = 0; - while (idx--) - { - if (spaces > 0) - { + while (idx--) { + if (spaces > 0) { result.push_back(L'\n'); } - for (size_t j=0; j < spaces; j++) - { + for (size_t j = 0; j < spaces; j++) { result.push_back(L' '); } result.append(this->block_at_index(idx)->description()); @@ -334,71 +240,49 @@ wcstring parser_t::block_stack_description() const return result; } -const block_t *parser_t::block_at_index(size_t idx) const -{ - /* 0 corresponds to the last element in our vector */ +const block_t *parser_t::block_at_index(size_t idx) const { + // Zero corresponds to the last element in our vector. size_t count = block_stack.size(); return idx < count ? block_stack.at(count - idx - 1) : NULL; } -block_t *parser_t::block_at_index(size_t idx) -{ +block_t *parser_t::block_at_index(size_t idx) { size_t count = block_stack.size(); return idx < count ? block_stack.at(count - idx - 1) : NULL; } -const block_t *parser_t::current_block() const -{ +const block_t *parser_t::current_block() const { return block_stack.empty() ? NULL : block_stack.back(); } -block_t *parser_t::current_block() -{ - return block_stack.empty() ? NULL : block_stack.back(); -} +block_t *parser_t::current_block() { return block_stack.empty() ? NULL : block_stack.back(); } -void parser_t::forbid_function(const wcstring &function) -{ - forbidden_function.push_back(function); -} +void parser_t::forbid_function(const wcstring &function) { forbidden_function.push_back(function); } -void parser_t::allow_function() -{ - forbidden_function.pop_back(); -} +void parser_t::allow_function() { forbidden_function.pop_back(); } -/** - Print profiling information to the specified stream -*/ -static void print_profile(const std::vector &items, - FILE *out) -{ - for (size_t pos = 0; pos < items.size(); pos++) - { +/// Print profiling information to the specified stream. +static void print_profile(const std::vector &items, FILE *out) { + for (size_t pos = 0; pos < items.size(); pos++) { const profile_item_t *me, *prev; size_t i; int my_time; me = items.at(pos); - if (!me->skipped) - { - my_time=me->parse+me->exec; + if (!me->skipped) { + my_time = me->parse + me->exec; - for (i=pos+1; iskipped) - { + if (prev->skipped) { continue; } - if (prev->level <= me->level) - { + if (prev->level <= me->level) { break; } - if (prev->level > me->level+1) - { + if (prev->level > me->level + 1) { continue; } @@ -406,199 +290,149 @@ static void print_profile(const std::vector &items, my_time -= prev->exec; } - if (me->cmd.size() > 0) - { - if (fwprintf(out, L"%d\t%d\t", my_time, me->parse+me->exec) < 0) - { + if (me->cmd.size() > 0) { + if (fwprintf(out, L"%d\t%d\t", my_time, me->parse + me->exec) < 0) { wperror(L"fwprintf"); return; } - for (i=0; ilevel; i++) - { - if (fwprintf(out, L"-") < 0) - { + for (i = 0; i < me->level; i++) { + if (fwprintf(out, L"-") < 0) { wperror(L"fwprintf"); return; } - } - if (fwprintf(out, L"> %ls\n", me->cmd.c_str()) < 0) - { + if (fwprintf(out, L"> %ls\n", me->cmd.c_str()) < 0) { wperror(L"fwprintf"); return; } - } } } } -void parser_t::emit_profiling(const char *path) const -{ - /* Save profiling information. OK to not use CLO_EXEC here because this is called while fish is dying (and hence will not fork) */ +void parser_t::emit_profiling(const char *path) const { + // Save profiling information. OK to not use CLO_EXEC here because this is called while fish is + // dying (and hence will not fork). FILE *f = fopen(path, "w"); - if (!f) - { - debug(1, - _(L"Could not write profiling information to file '%s'"), - path); - } - else - { - if (fwprintf(f, - _(L"Time\tSum\tCommand\n"), - profile_items.size()) < 0) - { + if (!f) { + debug(1, _(L"Could not write profiling information to file '%s'"), path); + } else { + if (fwprintf(f, _(L"Time\tSum\tCommand\n"), profile_items.size()) < 0) { wperror(L"fwprintf"); - } - else - { + } else { print_profile(profile_items, f); } - if (fclose(f)) - { + if (fclose(f)) { wperror(L"fclose"); } } } -void parser_t::expand_argument_list(const wcstring &arg_list_src, expand_flags_t eflags, std::vector *output_arg_list) -{ +void parser_t::expand_argument_list(const wcstring &arg_list_src, expand_flags_t eflags, + std::vector *output_arg_list) { assert(output_arg_list != NULL); - /* Parse the string as an argument list */ + // Parse the string as an argument list. parse_node_tree_t tree; - if (! parse_tree_from_string(arg_list_src, parse_flag_none, &tree, NULL /* errors */, symbol_freestanding_argument_list)) - { - /* Failed to parse. Here we expect to have reported any errors in test_args */ + if (!parse_tree_from_string(arg_list_src, parse_flag_none, &tree, NULL /* errors */, + symbol_freestanding_argument_list)) { + // Failed to parse. Here we expect to have reported any errors in test_args. return; } - /* Get the root argument list */ - assert(! tree.empty()); + // Get the root argument list. + assert(!tree.empty()); const parse_node_t *arg_list = &tree.at(0); assert(arg_list->type == symbol_freestanding_argument_list); - /* Extract arguments from it */ - while (arg_list != NULL) - { - const parse_node_t *arg_node = tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); - if (arg_node != NULL) - { + // Extract arguments from it. + while (arg_list != NULL) { + const parse_node_t *arg_node = + tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); + if (arg_node != NULL) { const wcstring arg_src = arg_node->get_source(arg_list_src); - if (expand_string(arg_src, output_arg_list, eflags, NULL) == EXPAND_ERROR) - { - /* Failed to expand a string */ - break; + if (expand_string(arg_src, output_arg_list, eflags, NULL) == EXPAND_ERROR) { + break; // failed to expand a string } } } } -wcstring parser_t::stack_trace() const -{ +wcstring parser_t::stack_trace() const { wcstring trace; this->stack_trace_internal(0, &trace); return trace; } -void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const -{ - /* - Check if we should end the recursion - */ - if (block_idx >= this->block_count()) - return; +void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const { + // Check if we should end the recursion. + if (block_idx >= this->block_count()) return; const block_t *b = this->block_at_index(block_idx); - if (b->type()==EVENT) - { - /* - This is an event handler - */ + if (b->type() == EVENT) { + // This is an event handler. const event_block_t *eb = static_cast(b); wcstring description = event_get_desc(eb->event); append_format(*buff, _(L"in event handler: %ls\n"), description.c_str()); buff->append(L"\n"); - /* - Stop recursing at event handler. No reason to believe that - any other code is relevant. - - It might make sense in the future to continue printing the - stack trace of the code that invoked the event, if this is a - programmatic event, but we can't currently detect that. - */ + // Stop recursing at event handler. No reason to believe that any other code is relevant. + // + // It might make sense in the future to continue printing the stack trace of the code that + // invoked the event, if this is a programmatic event, but we can't currently detect that. return; } - if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW || b->type()==SOURCE || b->type()==SUBST) - { - /* - These types of blocks should be printed - */ - + if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW || b->type() == SOURCE || + b->type() == SUBST) { + // These types of blocks should be printed. int i; - switch (b->type()) - { - case SOURCE: - { - const source_block_t *sb = static_cast(b); + switch (b->type()) { + case SOURCE: { + const source_block_t *sb = static_cast(b); const wchar_t *source_dest = sb->source_file; - append_format(*buff, _(L"from sourcing file %ls\n"), user_presentable_path(source_dest).c_str()); + append_format(*buff, _(L"from sourcing file %ls\n"), + user_presentable_path(source_dest).c_str()); break; } case FUNCTION_CALL: - case FUNCTION_CALL_NO_SHADOW: - { - const function_block_t *fb = static_cast(b); + case FUNCTION_CALL_NO_SHADOW: { + const function_block_t *fb = static_cast(b); append_format(*buff, _(L"in function '%ls'\n"), fb->name.c_str()); break; } - case SUBST: - { + case SUBST: { append_format(*buff, _(L"in command substitution\n")); break; } - - default: /* Can't get here */ - break; + default: { + break; // can't get here + } } const wchar_t *file = b->src_filename; - if (file) - { - append_format(*buff, - _(L"\tcalled on line %d of file %ls\n"), - b->src_lineno, + if (file) { + append_format(*buff, _(L"\tcalled on line %d of file %ls\n"), b->src_lineno, user_presentable_path(file).c_str()); - } - else if (is_within_fish_initialization) - { + } else if (is_within_fish_initialization) { append_format(*buff, _(L"\tcalled during startup\n")); - } - else - { + } else { append_format(*buff, _(L"\tcalled on standard input\n")); } - if (b->type() == FUNCTION_CALL) - { + if (b->type() == FUNCTION_CALL) { const function_block_t *fb = static_cast(b); - const process_t * const process = fb->process; - if (process->argv(1)) - { + const process_t *const process = fb->process; + if (process->argv(1)) { wcstring tmp; - for (i=1; process->argv(i); i++) - { - if (i > 1) - tmp.push_back(L' '); + for (i = 1; process->argv(i); i++) { + if (i > 1) tmp.push_back(L' '); tmp.append(process->argv(i)); } append_format(*buff, _(L"\twith parameter list '%ls'\n"), tmp.c_str()); @@ -608,100 +442,77 @@ void parser_t::stack_trace_internal(size_t block_idx, wcstring *buff) const append_format(*buff, L"\n"); } - /* - Recursively print the next block - */ + // Recursively print the next block. parser_t::stack_trace_internal(block_idx + 1, buff); } -/** - Returns the name of the currently evaluated function if we are - currently evaluating a function, null otherwise. This is tested by - moving down the block-scope-stack, checking every block if it is of - type FUNCTION_CALL. -*/ -const wchar_t *parser_t::is_function() const -{ - // PCA: Have to make this a string somehow +/// Returns the name of the currently evaluated function if we are currently evaluating a function, +/// null otherwise. This is tested by moving down the block-scope-stack, checking every block if it +/// is of type FUNCTION_CALL. +const wchar_t *parser_t::is_function() const { + // PCA: Have to make this a string somehow. ASSERT_IS_MAIN_THREAD(); const wchar_t *result = NULL; - for (size_t block_idx = 0; block_idx < this->block_count(); block_idx++) - { + for (size_t block_idx = 0; block_idx < this->block_count(); block_idx++) { const block_t *b = this->block_at_index(block_idx); - if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW) - { + if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW) { const function_block_t *fb = static_cast(b); result = fb->name.c_str(); break; - } - else if (b->type() == SOURCE) - { - /* If a function sources a file, obviously that function's offset doesn't contribute */ + } else if (b->type() == SOURCE) { + // If a function sources a file, obviously that function's offset doesn't contribute. break; } } return result; } - -int parser_t::get_lineno() const -{ +int parser_t::get_lineno() const { int lineno = -1; - if (! execution_contexts.empty()) - { + if (!execution_contexts.empty()) { lineno = execution_contexts.back()->get_current_line_number(); - /* If we are executing a function, we have to add in its offset */ + // If we are executing a function, we have to add in its offset. const wchar_t *function_name = is_function(); - if (function_name != NULL) - { + if (function_name != NULL) { lineno += function_get_definition_offset(function_name); } - } return lineno; } -const wchar_t *parser_t::current_filename() const -{ +const wchar_t *parser_t::current_filename() const { ASSERT_IS_MAIN_THREAD(); - for (size_t i=0; i < this->block_count(); i++) - { + for (size_t i = 0; i < this->block_count(); i++) { const block_t *b = this->block_at_index(i); - if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW) - { + if (b->type() == FUNCTION_CALL || b->type() == FUNCTION_CALL_NO_SHADOW) { const function_block_t *fb = static_cast(b); return function_get_definition_file(fb->name); - } - else if (b->type() == SOURCE) - { + } else if (b->type() == SOURCE) { const source_block_t *sb = static_cast(b); return sb->source_file; } } - /* We query a global array for the current file name, but only do that if we are the principal parser */ - if (this == &principal_parser()) - { + // We query a global array for the current file name, but only do that if we are the principal + // parser. + if (this == &principal_parser()) { return reader_current_filename(); } return NULL; } -wcstring parser_t::current_line() -{ - if (execution_contexts.empty()) - { +wcstring parser_t::current_line() { + if (execution_contexts.empty()) { return wcstring(); } const parse_execution_context_t *context = execution_contexts.back(); assert(context != NULL); int source_offset = context->get_current_source_offset(); - if (source_offset < 0) - { + if (source_offset < 0) { return wcstring(); } @@ -710,34 +521,29 @@ wcstring parser_t::current_line() wcstring prefix; - /* If we are not going to print a stack trace, at least print the line number and filename */ - if (!get_is_interactive() || is_function()) - { - if (file) - { - append_format(prefix, _(L"%ls (line %d): "), user_presentable_path(file).c_str(), lineno); - } - else if (is_within_fish_initialization) - { + // If we are not going to print a stack trace, at least print the line number and filename. + if (!get_is_interactive() || is_function()) { + if (file) { + append_format(prefix, _(L"%ls (line %d): "), user_presentable_path(file).c_str(), + lineno); + } else if (is_within_fish_initialization) { append_format(prefix, L"%ls: ", _(L"Startup"), lineno); - } - else - { + } else { append_format(prefix, L"%ls: ", _(L"Standard input"), lineno); } } bool is_interactive = get_is_interactive(); - bool skip_caret = is_interactive && ! is_function(); + bool skip_caret = is_interactive && !is_function(); - /* Use an error with empty text */ + // Use an error with empty text. assert(source_offset >= 0); parse_error_t empty_error = {}; empty_error.source_start = source_offset; - wcstring line_info = empty_error.describe_with_prefix(context->get_source(), prefix, is_interactive, skip_caret); - if (! line_info.empty()) - { + wcstring line_info = + empty_error.describe_with_prefix(context->get_source(), prefix, is_interactive, skip_caret); + if (!line_info.empty()) { line_info.push_back(L'\n'); } @@ -745,170 +551,150 @@ wcstring parser_t::current_line() return line_info; } -void parser_t::job_add(job_t *job) -{ +void parser_t::job_add(job_t *job) { assert(job != NULL); assert(job->first_process != NULL); this->my_job_list.push_front(job); } -bool parser_t::job_remove(job_t *j) -{ +bool parser_t::job_remove(job_t *j) { job_list_t::iterator iter = std::find(my_job_list.begin(), my_job_list.end(), j); - if (iter != my_job_list.end()) - { + if (iter != my_job_list.end()) { my_job_list.erase(iter); return true; - } - else - { + } else { debug(1, _(L"Job inconsistency")); sanity_lose(); return false; } } -void parser_t::job_promote(job_t *job) -{ +void parser_t::job_promote(job_t *job) { job_list_t::iterator loc = std::find(my_job_list.begin(), my_job_list.end(), job); assert(loc != my_job_list.end()); - /* Move the job to the beginning */ + // Move the job to the beginning. my_job_list.splice(my_job_list.begin(), my_job_list, loc); } -job_t *parser_t::job_get(job_id_t id) -{ +job_t *parser_t::job_get(job_id_t id) { job_iterator_t jobs(my_job_list); job_t *job; - while ((job = jobs.next())) - { - if (id <= 0 || job->job_id == id) - return job; + while ((job = jobs.next())) { + if (id <= 0 || job->job_id == id) return job; } return NULL; } -job_t *parser_t::job_get_from_pid(int pid) -{ +job_t *parser_t::job_get_from_pid(int pid) { job_iterator_t jobs; job_t *job; - while ((job = jobs.next())) - { - if (job->pgid == pid) - return job; + while ((job = jobs.next())) { + if (job->pgid == pid) return job; } return 0; } -profile_item_t *parser_t::create_profile_item() -{ +profile_item_t *parser_t::create_profile_item() { profile_item_t *result = NULL; - if (g_profiling_active) - { + if (g_profiling_active) { result = new profile_item_t(); profile_items.push_back(result); } return result; } -int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type) -{ - /* Parse the source into a tree, if we can */ +int parser_t::eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type) { + // Parse the source into a tree, if we can. parse_node_tree_t tree; parse_error_list_t error_list; - if (! parse_tree_from_string(cmd, parse_flag_none, &tree, &error_list)) - { - /* Get a backtrace. This includes the message. */ + if (!parse_tree_from_string(cmd, parse_flag_none, &tree, &error_list)) { + // Get a backtrace. This includes the message. wcstring backtrace_and_desc; this->get_backtrace(cmd, error_list, &backtrace_and_desc); - - /* Print it */ + + // Print it. fprintf(stderr, "%ls", backtrace_and_desc.c_str()); - + return 1; } return this->eval_acquiring_tree(cmd, io, block_type, moved_ref(tree)); } -int parser_t::eval_acquiring_tree(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type, moved_ref tree) -{ +int parser_t::eval_acquiring_tree(const wcstring &cmd, const io_chain_t &io, + enum block_type_t block_type, moved_ref tree) { CHECK_BLOCK(1); assert(block_type == TOP || block_type == SUBST); - if (tree.val.empty()) - { + if (tree.val.empty()) { return 0; } - /* Determine the initial eval level. If this is the first context, it's -1; otherwise it's the eval level of the top context. This is sort of wonky because we're stitching together a global notion of eval level from these separate objects. A better approach would be some profile object that all contexts share, and that tracks the eval levels on its own. */ - int exec_eval_level = (execution_contexts.empty() ? -1 : execution_contexts.back()->current_eval_level()); - - /* Append to the execution context stack */ - parse_execution_context_t *ctx = new parse_execution_context_t(tree, cmd, this, exec_eval_level); + // Determine the initial eval level. If this is the first context, it's -1; otherwise it's the + // eval level of the top context. This is sort of wonky because we're stitching together a + // global notion of eval level from these separate objects. A better approach would be some + // profile object that all contexts share, and that tracks the eval levels on its own. + int exec_eval_level = + (execution_contexts.empty() ? -1 : execution_contexts.back()->current_eval_level()); + + // Append to the execution context stack. + parse_execution_context_t *ctx = + new parse_execution_context_t(tree, cmd, this, exec_eval_level); execution_contexts.push_back(ctx); - - /* Execute the first node */ + + // Execute the first node. this->eval_block_node(0, io, block_type); - - /* Clean up the execution context stack */ - assert(! execution_contexts.empty() && execution_contexts.back() == ctx); + + // Clean up the execution context stack. + assert(!execution_contexts.empty() && execution_contexts.back() == ctx); execution_contexts.pop_back(); delete ctx; - + return 0; } -int parser_t::eval_block_node(node_offset_t node_idx, const io_chain_t &io, enum block_type_t block_type) -{ - /* Paranoia. It's a little frightening that we're given only a node_idx and we interpret this in the topmost execution context's tree. What happens if two trees were to be interleaved? Fortunately that cannot happen (yet); in the future we probably want some sort of reference counted trees. - */ +int parser_t::eval_block_node(node_offset_t node_idx, const io_chain_t &io, + enum block_type_t block_type) { + // Paranoia. It's a little frightening that we're given only a node_idx and we interpret this in + // the topmost execution context's tree. What happens if two trees were to be interleaved? + // Fortunately that cannot happen (yet); in the future we probably want some sort of reference + // counted trees. parse_execution_context_t *ctx = execution_contexts.back(); assert(ctx != NULL); CHECK_BLOCK(1); - /* Handle cancellation requests. If our block stack is currently empty, then we already did successfully cancel (or there was nothing to cancel); clear the flag. If our block stack is not empty, we are still in the process of cancelling; refuse to evaluate anything */ - if (this->cancellation_requested) - { - if (! block_stack.empty()) - { + // Handle cancellation requests. If our block stack is currently empty, then we already did + // successfully cancel (or there was nothing to cancel); clear the flag. If our block stack is + // not empty, we are still in the process of cancelling; refuse to evaluate anything. + if (this->cancellation_requested) { + if (!block_stack.empty()) { return 1; - } - else - { + } else { this->cancellation_requested = false; } } - /* Only certain blocks are allowed */ - if ((block_type != TOP) && - (block_type != SUBST)) - { - debug(1, - INVALID_SCOPE_ERR_MSG, - parser_t::get_block_desc(block_type)); + // Only certain blocks are allowed. + if ((block_type != TOP) && (block_type != SUBST)) { + debug(1, INVALID_SCOPE_ERR_MSG, parser_t::get_block_desc(block_type)); bugreport(); return 1; } - /* Not sure why we reap jobs here */ - job_reap(0); + job_reap(0); // not sure why we reap jobs here /* Start it up */ - const block_t * const start_current_block = current_block(); + const block_t *const start_current_block = current_block(); block_t *scope_block = new scope_block_t(block_type); this->push_block(scope_block); int result = ctx->eval_node_at_offset(node_idx, scope_block, io); - /* Clean up the block stack */ + // Clean up the block stack. this->pop_block(); - while (start_current_block != current_block()) - { - if (current_block() == NULL) - { - debug(0, - _(L"End of block mismatch. Program terminating.")); + while (start_current_block != current_block()) { + if (current_block() == NULL) { + debug(0, _(L"End of block mismatch. Program terminating.")); bugreport(); FATAL_EXIT(); break; @@ -916,104 +702,93 @@ int parser_t::eval_block_node(node_offset_t node_idx, const io_chain_t &io, enum this->pop_block(); } - /* Reap again */ - job_reap(0); + job_reap(0); // reap again return result; } -bool parser_t::detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out, const wchar_t *prefix) -{ +bool parser_t::detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out, + const wchar_t *prefix) { bool errored = false; parse_error_list_t errors; - /* Use empty string for the prefix if it's NULL */ - if (prefix == NULL) - { + // Use empty string for the prefix if it's NULL. + if (prefix == NULL) { prefix = L""; } - /* Parse the string as an argument list */ + // Parse the string as an argument list. parse_node_tree_t tree; - if (! parse_tree_from_string(arg_list_src, parse_flag_none, &tree, &errors, symbol_freestanding_argument_list)) - { - /* Failed to parse. */ + if (!parse_tree_from_string(arg_list_src, parse_flag_none, &tree, &errors, + symbol_freestanding_argument_list)) { + // Failed to parse. errored = true; } - if (! errored) - { - /* Get the root argument list */ - assert(! tree.empty()); + if (!errored) { + // Get the root argument list. + assert(!tree.empty()); const parse_node_t *arg_list = &tree.at(0); assert(arg_list->type == symbol_freestanding_argument_list); - /* Extract arguments from it */ - while (arg_list != NULL && ! errored) - { - const parse_node_t *arg_node = tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); - if (arg_node != NULL) - { + // Extract arguments from it. + while (arg_list != NULL && !errored) { + const parse_node_t *arg_node = + tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); + if (arg_node != NULL) { const wcstring arg_src = arg_node->get_source(arg_list_src); - if (parse_util_detect_errors_in_argument(*arg_node, arg_src, &errors)) - { + if (parse_util_detect_errors_in_argument(*arg_node, arg_src, &errors)) { errored = true; } } } } - if (! errors.empty() && out != NULL) - { - out->assign(errors.at(0).describe_with_prefix(arg_list_src, prefix, false /* not interactive */, false /* don't skip caret */)); + if (!errors.empty() && out != NULL) { + out->assign(errors.at(0).describe_with_prefix( + arg_list_src, prefix, false /* not interactive */, false /* don't skip caret */)); } return errored; } -void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring *output) const -{ +void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &errors, + wcstring *output) const { assert(output != NULL); - if (! errors.empty()) - { + if (!errors.empty()) { const parse_error_t &err = errors.at(0); const bool is_interactive = get_is_interactive(); - // Determine if we want to try to print a caret to point at the source error - // The err.source_start <= src.size() check is due to the nasty way that slices work, - // which is by rewriting the source (!) + // Determine if we want to try to print a caret to point at the source error. The + // err.source_start <= src.size() check is due to the nasty way that slices work, which is + // by rewriting the source. size_t which_line = 0; bool skip_caret = true; - if (err.source_start != SOURCE_LOCATION_UNKNOWN && err.source_start <= src.size()) - { - // Determine which line we're on + if (err.source_start != SOURCE_LOCATION_UNKNOWN && err.source_start <= src.size()) { + // Determine which line we're on. which_line = 1 + std::count(src.begin(), src.begin() + err.source_start, L'\n'); - // Don't include the caret if we're interactive, this is the first line of text, and our source is at its beginning, because then it's obvious + // Don't include the caret if we're interactive, this is the first line of text, and our + // source is at its beginning, because then it's obvious. skip_caret = (is_interactive && which_line == 1 && err.source_start == 0); } wcstring prefix; const wchar_t *filename = this->current_filename(); - if (filename) - { - if (which_line > 0) - { - prefix = format_string(_(L"%ls (line %lu): "), user_presentable_path(filename).c_str(), which_line); - } - else - { + if (filename) { + if (which_line > 0) { + prefix = format_string(_(L"%ls (line %lu): "), + user_presentable_path(filename).c_str(), which_line); + } else { prefix = format_string(_(L"%ls: "), user_presentable_path(filename).c_str()); } - } - else - { + } else { prefix = L"fish: "; } - const wcstring description = err.describe_with_prefix(src, prefix, is_interactive, skip_caret); - if (! description.empty()) - { + const wcstring description = + err.describe_with_prefix(src, prefix, is_interactive, skip_caret); + if (!description.empty()) { output->append(description); output->push_back(L'\n'); } @@ -1021,147 +796,115 @@ void parser_t::get_backtrace(const wcstring &src, const parse_error_list_t &erro } } -block_t::block_t(block_type_t t) : - block_type(t), - skip(), - tok_pos(), - node_offset(NODE_OFFSET_INVALID), - loop_status(LOOP_NORMAL), - job(), - src_filename(), - src_lineno(), - wants_pop_env(false), - event_blocks() -{ -} +block_t::block_t(block_type_t t) + : block_type(t), + skip(), + tok_pos(), + node_offset(NODE_OFFSET_INVALID), + loop_status(LOOP_NORMAL), + job(), + src_filename(), + src_lineno(), + wants_pop_env(false), + event_blocks() {} -block_t::~block_t() -{ -} +block_t::~block_t() {} -wcstring block_t::description() const -{ +wcstring block_t::description() const { wcstring result; - switch (this->type()) - { - case WHILE: + switch (this->type()) { + case WHILE: { result.append(L"while"); break; - - case FOR: + } + case FOR: { result.append(L"for"); break; - - case IF: + } + case IF: { result.append(L"if"); break; - - case FUNCTION_DEF: + } + case FUNCTION_DEF: { result.append(L"function_def"); break; - - case FUNCTION_CALL: + } + case FUNCTION_CALL: { result.append(L"function_call"); break; - - case FUNCTION_CALL_NO_SHADOW: + } + case FUNCTION_CALL_NO_SHADOW: { result.append(L"function_call_no_shadow"); break; - - case SWITCH: + } + case SWITCH: { result.append(L"switch"); break; - - case FAKE: + } + case FAKE: { result.append(L"fake"); break; - - case SUBST: + } + case SUBST: { result.append(L"substitution"); break; - - case TOP: + } + case TOP: { result.append(L"top"); break; - - case BEGIN: + } + case BEGIN: { result.append(L"begin"); break; - - case SOURCE: + } + case SOURCE: { result.append(L"source"); break; - - case EVENT: + } + case EVENT: { result.append(L"event"); break; - - case BREAKPOINT: + } + case BREAKPOINT: { result.append(L"breakpoint"); break; - - default: + } + default: { append_format(result, L"unknown type %ld", (long)this->type()); break; + } } - if (this->src_lineno >= 0) - { + if (this->src_lineno >= 0) { append_format(result, L" (line %d)", this->src_lineno); } - if (this->src_filename != NULL) - { + if (this->src_filename != NULL) { append_format(result, L" (file %ls)", this->src_filename); } return result; } -/* Various block constructors */ +// Various block constructors. -if_block_t::if_block_t() : block_t(IF) -{ -} +if_block_t::if_block_t() : block_t(IF) {} -event_block_t::event_block_t(const event_t &evt) : - block_t(EVENT), - event(evt) -{ -} +event_block_t::event_block_t(const event_t &evt) : block_t(EVENT), event(evt) {} -function_block_t::function_block_t(const process_t *p, const wcstring &n, bool shadows) : - block_t(shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW), - process(p), - name(n) -{ -} +function_block_t::function_block_t(const process_t *p, const wcstring &n, bool shadows) + : block_t(shadows ? FUNCTION_CALL : FUNCTION_CALL_NO_SHADOW), process(p), name(n) {} -source_block_t::source_block_t(const wchar_t *src) : - block_t(SOURCE), - source_file(src) -{ -} +source_block_t::source_block_t(const wchar_t *src) : block_t(SOURCE), source_file(src) {} -for_block_t::for_block_t() : block_t(FOR) -{ -} +for_block_t::for_block_t() : block_t(FOR) {} -while_block_t::while_block_t() : block_t(WHILE) -{ -} +while_block_t::while_block_t() : block_t(WHILE) {} -switch_block_t::switch_block_t() : block_t(SWITCH) -{ -} +switch_block_t::switch_block_t() : block_t(SWITCH) {} -fake_block_t::fake_block_t() : block_t(FAKE) -{ -} +fake_block_t::fake_block_t() : block_t(FAKE) {} -scope_block_t::scope_block_t(block_type_t type) : block_t(type) -{ +scope_block_t::scope_block_t(block_type_t type) : block_t(type) { assert(type == BEGIN || type == TOP || type == SUBST); } -breakpoint_block_t::breakpoint_block_t() : block_t(BREAKPOINT) -{ -} +breakpoint_block_t::breakpoint_block_t() : block_t(BREAKPOINT) {} diff --git a/src/parser.h b/src/parser.h index d40ca16be..4a6823061 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,428 +1,348 @@ -/** \file parser.h - The fish parser. -*/ +// The fish parser. #ifndef FISH_PARSER_H #define FISH_PARSER_H +#include #include #include #include -#include #include "common.h" -#include "proc.h" #include "event.h" -#include "parse_tree.h" -#include "parse_constants.h" #include "expand.h" +#include "parse_constants.h" +#include "parse_tree.h" +#include "proc.h" class io_chain_t; -/** - event_blockage_t represents a block on events of the specified type -*/ -struct event_blockage_t -{ - /** - The types of events to block. This is interpreted as a bitset - whete the value is 1 for every bit corresponding to a blocked - event type. For example, if EVENT_VARIABLE type events should - be blocked, (type & 1< event_blockage_list_t; -inline bool event_block_list_blocks_type(const event_blockage_list_t &ebls, int type) -{ - for (event_blockage_list_t::const_iterator iter = ebls.begin(); iter != ebls.end(); ++iter) - { - if (iter->typemask & (1<typemask & (1<typemask & (1 << EVENT_ANY)) return true; + if (iter->typemask & (1 << type)) return true; } return false; } - -/** - Types of blocks -*/ -enum block_type_t -{ - WHILE, /**< While loop block */ - FOR, /**< For loop block */ - IF, /**< If block */ - FUNCTION_DEF, /**< Function definition block */ - FUNCTION_CALL, /**< Function invocation block */ - FUNCTION_CALL_NO_SHADOW, /**< Function invocation block with no variable shadowing */ - SWITCH, /**< Switch block */ - FAKE, /**< Fake block */ - SUBST, /**< Command substitution scope */ - TOP, /**< Outermost block */ - BEGIN, /**< Unconditional block */ - SOURCE, /**< Block created by the . (source) builtin */ - EVENT, /**< Block created on event notifier invocation */ - BREAKPOINT, /**< Breakpoint block */ +/// Types of blocks. +enum block_type_t { + WHILE, /// While loop block + FOR, /// For loop block + IF, /// If block + FUNCTION_DEF, /// Function definition block + FUNCTION_CALL, /// Function invocation block + FUNCTION_CALL_NO_SHADOW, /// Function invocation block with no variable shadowing + SWITCH, /// Switch block + FAKE, /// Fake block + SUBST, /// Command substitution scope + TOP, /// Outermost block + BEGIN, /// Unconditional block + SOURCE, /// Block created by the . (source) builtin + EVENT, /// Block created on event notifier invocation + BREAKPOINT, /// Breakpoint block }; -/** Possible states for a loop */ -enum loop_status_t -{ - LOOP_NORMAL, /**< Current loop block executed as normal */ - LOOP_BREAK, /**< Current loop block should be removed */ - LOOP_CONTINUE, /**< Current loop block should be skipped */ +/// Possible states for a loop. +enum loop_status_t { + LOOP_NORMAL, /// current loop block executed as normal + LOOP_BREAK, /// current loop block should be removed + LOOP_CONTINUE, /// current loop block should be skipped }; -/** - block_t represents a block of commands. -*/ -struct block_t -{ -protected: - /** Protected constructor. Use one of the subclasses below. */ +/// block_t represents a block of commands. +struct block_t { + protected: + /// Protected constructor. Use one of the subclasses below. explicit block_t(block_type_t t); -private: - const block_type_t block_type; /**< Type of block. */ + private: + /// Type of block. + const block_type_t block_type; -public: - block_type_t type() const - { - return this->block_type; - } - - /** Description of the block, for debugging */ - wcstring description() const; - - bool skip; /**< Whether execution of the commands in this block should be skipped */ - int tok_pos; /**< The start index of the block */ - - node_offset_t node_offset; /* Offset of the node */ - - /** Status for the current loop block. Can be any of the values from the loop_status enum. */ + public: + /// Whether execution of the commands in this block should be skipped. + bool skip; + /// The start index of the block. + int tok_pos; + /// Offset of the node. + node_offset_t node_offset; + /// Status for the current loop block. Can be any of the values from the loop_status enum. enum loop_status_t loop_status; - - /** The job that is currently evaluated in the specified block. */ + /// The job that is currently evaluated in the specified block. job_t *job; - - /** Name of file that created this block. This string is intern'd. */ + /// Name of file that created this block. This string is intern'd. const wchar_t *src_filename; - - /** Line number where this block was created */ + /// Line number where this block was created. int src_lineno; - - /** Whether we should pop the environment variable stack when we're popped off of the block stack */ + /// Whether we should pop the environment variable stack when we're popped off of the block + /// stack. bool wants_pop_env; - /** List of event blocks. */ + block_type_t type() const { return this->block_type; } + + /// Description of the block, for debugging. + wcstring description() const; + + /// List of event blocks. event_blockage_list_t event_blocks; - /** Destructor */ + /// Destructor virtual ~block_t(); }; -struct if_block_t : public block_t -{ +struct if_block_t : public block_t { if_block_t(); }; -struct event_block_t : public block_t -{ +struct event_block_t : public block_t { event_t const event; explicit event_block_t(const event_t &evt); }; -struct function_block_t : public block_t -{ +struct function_block_t : public block_t { const process_t *process; wcstring name; function_block_t(const process_t *p, const wcstring &n, bool shadows); }; -struct source_block_t : public block_t -{ - const wchar_t * const source_file; +struct source_block_t : public block_t { + const wchar_t *const source_file; explicit source_block_t(const wchar_t *src); }; -struct for_block_t : public block_t -{ +struct for_block_t : public block_t { for_block_t(); }; -struct while_block_t : public block_t -{ +struct while_block_t : public block_t { while_block_t(); }; -struct switch_block_t : public block_t -{ +struct switch_block_t : public block_t { switch_block_t(); }; -struct fake_block_t : public block_t -{ +struct fake_block_t : public block_t { fake_block_t(); }; -struct scope_block_t : public block_t -{ - explicit scope_block_t(block_type_t type); //must be BEGIN, TOP or SUBST +struct scope_block_t : public block_t { + explicit scope_block_t(block_type_t type); // must be BEGIN, TOP or SUBST }; -struct breakpoint_block_t : public block_t -{ +struct breakpoint_block_t : public block_t { breakpoint_block_t(); }; -/** - Errors that can be generated by the parser -*/ -enum parser_error -{ - /** - No error - */ - NO_ERR=0, - /** - An error in the syntax - */ +/// Errors that can be generated by the parser. +enum parser_error { + /// No error. + NO_ERR = 0, + /// An error in the syntax. SYNTAX_ERROR, - /** - Error occured while evaluating commands - */ + /// Error occured while evaluating commands. EVAL_ERROR, - /** - Error while evaluating cmdsubst - */ + /// Error while evaluating cmdsubst. CMDSUBST_ERROR, }; -struct profile_item_t -{ - /** Time spent executing the specified command, including parse time for nested blocks. */ +struct profile_item_t { + /// Time spent executing the specified command, including parse time for nested blocks. int exec; - - /** Time spent parsing the specified command, including execution time for command substitutions. */ + /// Time spent parsing the specified command, including execution time for command + /// substitutions. int parse; - - /** The block level of the specified command. nested blocks and command substitutions both increase the block level. */ + /// The block level of the specified command. nested blocks and command substitutions both + /// increase the block level. size_t level; - - /** If the execution of this command was skipped. */ + /// If the execution of this command was skipped. bool skipped; - - /** The command string. */ + /// The command string. wcstring cmd; }; class parse_execution_context_t; class completion_t; -class parser_t -{ +class parser_t { friend class parse_execution_context_t; -private: - /** Indication that we should skip all blocks */ + + private: + /// Indication that we should skip all blocks. bool cancellation_requested; - - /** Indicates that we are within the process of initializing fish */ + /// Indicates that we are within the process of initializing fish. bool is_within_fish_initialization; - - /** Stack of execution contexts. We own these pointers and must delete them */ + /// Stack of execution contexts. We own these pointers and must delete them. std::vector execution_contexts; - - /** List of called functions, used to help prevent infinite recursion */ + /// List of called functions, used to help prevent infinite recursion. wcstring_list_t forbidden_function; - - /** The jobs associated with this parser */ + /// The jobs associated with this parser. job_list_t my_job_list; - - /** The list of blocks, allocated with new. It's our responsibility to delete these */ + /// The list of blocks, allocated with new. It's our responsibility to delete these. std::vector block_stack; - /** Gets a description of the block stack, for debugging */ + /// Gets a description of the block stack, for debugging. wcstring block_stack_description() const; - /** List of profile items, allocated with new */ + /// List of profile items, allocated with new. std::vector profile_items; - /* No copying allowed */ - parser_t(const parser_t&); - parser_t& operator=(const parser_t&); + // No copying allowed. + parser_t(const parser_t &); + parser_t &operator=(const parser_t &); - /** Adds a job to the beginning of the job list. */ + /// Adds a job to the beginning of the job list. void job_add(job_t *job); - /** - Returns the name of the currently evaluated function if we are - currently evaluating a function, null otherwise. This is tested by - moving down the block-scope-stack, checking every block if it is of - type FUNCTION_CALL. - */ + /// Returns the name of the currently evaluated function if we are currently evaluating a + /// function, null otherwise. This is tested by moving down the block-scope-stack, checking + /// every block if it is of type FUNCTION_CALL. const wchar_t *is_function() const; - /* Helper for stack_trace() */ + /// Helper for stack_trace(). void stack_trace_internal(size_t block_idx, wcstring *out) const; -public: - - /** Get the "principal" parser, whatever that is */ + public: + /// Get the "principal" parser, whatever that is. static parser_t &principal_parser(); - /** Indicates that execution of all blocks in the principal parser should stop. - This is called from signal handlers! - */ + /// Indicates that execution of all blocks in the principal parser should stop. This is called + /// from signal handlers! static void skip_all_blocks(); - /** Create a parser */ + /// Create a parser. parser_t(); - /** Global event blocks */ + /// Global event blocks. event_blockage_list_t global_event_blocks; - /** - Evaluate the expressions contained in cmd. - - \param cmd the string to evaluate - \param io io redirections to perform on all started jobs - \param block_type The type of block to push on the block stack - - \return 0 on success, 1 otherwise - */ + /// Evaluate the expressions contained in cmd. + /// + /// \param cmd the string to evaluate + /// \param io io redirections to perform on all started jobs + /// \param block_type The type of block to push on the block stack + /// + /// \return 0 on success, 1 otherwise int eval(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type); - - /** - Evaluate the expressions contained in cmd, which has been parsed into the given parse tree. This takes ownership of the tree. - */ - int eval_acquiring_tree(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type, moved_ref t); - /** Evaluates a block node at the given node offset in the topmost execution context */ + /// Evaluate the expressions contained in cmd, which has been parsed into the given parse tree. + /// This takes ownership of the tree. + int eval_acquiring_tree(const wcstring &cmd, const io_chain_t &io, enum block_type_t block_type, + moved_ref t); + + /// Evaluates a block node at the given node offset in the topmost execution context. int eval_block_node(node_offset_t node_idx, const io_chain_t &io, enum block_type_t block_type); - /** - Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and cmdsubst execution on the tokens. - The output is inserted into output. - Errors are ignored. + /// Evaluate line as a list of parameters, i.e. tokenize it and perform parameter expansion and + /// cmdsubst execution on the tokens. The output is inserted into output. Errors are ignored. + /// + /// \param arg_src String to evaluate as an argument list + /// \param flags Some expand flags to use + /// \param output List to insert output into + static void expand_argument_list(const wcstring &arg_src, expand_flags_t flags, + std::vector *output); - \param arg_src String to evaluate as an argument list - \param flags Some expand flags to use - \param output List to insert output into - */ - static void expand_argument_list(const wcstring &arg_src, expand_flags_t flags, std::vector *output); - - /** - Returns a string describing the current parser pisition in the format 'FILENAME (line LINE_NUMBER): LINE'. - Example: - - init.fish (line 127): ls|grep pancake - */ + /// Returns a string describing the current parser pisition in the format 'FILENAME (line + /// LINE_NUMBER): LINE'. Example: + /// + /// init.fish (line 127): ls|grep pancake wcstring current_line(); - /** Returns the current line number */ + /// Returns the current line number. int get_lineno() const; - /** Returns the block at the given index. 0 corresponds to the innermost block. Returns NULL when idx is at or equal to the number of blocks. */ + /// Returns the block at the given index. 0 corresponds to the innermost block. Returns NULL + /// when idx is at or equal to the number of blocks. const block_t *block_at_index(size_t idx) const; block_t *block_at_index(size_t idx); - /** Returns the current (innermost) block */ + /// Returns the current (innermost) block. const block_t *current_block() const; block_t *current_block(); - /** Count of blocks */ - size_t block_count() const - { - return block_stack.size(); - } + /// Count of blocks. + size_t block_count() const { return block_stack.size(); } - /** Get the list of jobs */ - job_list_t &job_list() - { - return my_job_list; - } + /// Get the list of jobs. + job_list_t &job_list() { return my_job_list; } - /* Hackish. In order to correctly report the origin of code with no associated file, we need to know whether it's run during initialization or not. */ + // Hackish. In order to correctly report the origin of code with no associated file, we need to + // know whether it's run during initialization or not. void set_is_within_fish_initialization(bool flag); - /** Pushes the block. pop_block will call delete on it. */ + /// Pushes the block. pop_block will call delete on it. void push_block(block_t *newv); - /** Remove the outermost block namespace */ + /// Remove the outermost block namespace. void pop_block(); - /** Remove the outermost block, asserting it's the given one */ + /// Remove the outermost block, asserting it's the given one. void pop_block(const block_t *b); - /** Return a description of the given blocktype */ + /// Return a description of the given blocktype. const wchar_t *get_block_desc(int block) const; - /** Removes a job */ + /// Removes a job. bool job_remove(job_t *job); - /** Promotes a job to the front of the list */ + /// Promotes a job to the front of the list. void job_promote(job_t *job); - /** Return the job with the specified job id. If id is 0 or less, return the last job used. */ + /// Return the job with the specified job id. If id is 0 or less, return the last job used. job_t *job_get(int job_id); - /** Returns the job with the given pid */ + /// Returns the job with the given pid. job_t *job_get_from_pid(int pid); - /* Returns a new profile item if profiling is active. The caller should fill it in. The parser_t will clean it up. */ + /// Returns a new profile item if profiling is active. The caller should fill it in. The + /// parser_t will clean it up. profile_item_t *create_profile_item(); - /** - Test if the specified string can be parsed, or if more bytes need - to be read first. The result will have the PARSER_TEST_ERROR bit - set if there is a syntax error in the code, and the - PARSER_TEST_INCOMPLETE bit set if the code contains unclosed - blocks. + /// Test if the specified string can be parsed, or if more bytes need to be read first. The + /// result will have the PARSER_TEST_ERROR bit set if there is a syntax error in the code, and + /// the PARSER_TEST_INCOMPLETE bit set if the code contains unclosed blocks. + /// + /// \param buff the text buffer to test + /// \param block_level if non-null, the block nesting level will be filled out into this array + /// \param out if non-null, any errors in the command will be filled out into this buffer + /// \param prefix the prefix string to prepend to each error message written to the \c out + /// buffer. + void get_backtrace(const wcstring &src, const parse_error_list_t &errors, + wcstring *output) const; - \param buff the text buffer to test - \param block_level if non-null, the block nesting level will be filled out into this array - \param out if non-null, any errors in the command will be filled out into this buffer - \param prefix the prefix string to prepend to each error message written to the \c out buffer - */ - void get_backtrace(const wcstring &src, const parse_error_list_t &errors, wcstring *output) const; + /// Detect errors in the specified string when parsed as an argument list. Returns true if an + /// error occurred. + bool detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out_err, + const wchar_t *prefix); - /** - Detect errors in the specified string when parsed as an argument list. Returns true if an error occurred. - */ - bool detect_errors_in_argument_list(const wcstring &arg_list_src, wcstring *out_err, const wchar_t *prefix); - - /** - Tell the parser that the specified function may not be run if not - inside of a conditional block. This is to remove some possibilities - of infinite recursion. - */ + /// Tell the parser that the specified function may not be run if not inside of a conditional + /// block. This is to remove some possibilities of infinite recursion. void forbid_function(const wcstring &function); - /** - Undo last call to parser_forbid_function(). - */ + /// Undo last call to parser_forbid_function(). void allow_function(); - /** - Output profiling data to the given filename - */ + /// Output profiling data to the given filename. void emit_profiling(const char *path) const; - /** - Returns the file currently evaluated by the parser. This can be - different than reader_current_filename, e.g. if we are evaulating a - function defined in a different file than the one curently read. - */ + /// Returns the file currently evaluated by the parser. This can be different than + /// reader_current_filename, e.g. if we are evaulating a function defined in a different file + /// than the one curently read. const wchar_t *current_filename() const; - /** - Return a string representing the current stack trace - */ + /// Return a string representing the current stack trace. wcstring stack_trace() const; }; diff --git a/src/parser_keywords.cpp b/src/parser_keywords.cpp index 5f9710ac1..340a886f2 100644 --- a/src/parser_keywords.cpp +++ b/src/parser_keywords.cpp @@ -1,56 +1,22 @@ -/** \file parser_keywords.c - -Functions having to do with parser keywords, like testing if a function is a block command. -*/ -#include "fallback.h" // IWYU pragma: keep -#include "common.h" +// Functions having to do with parser keywords, like testing if a function is a block command. #include "parser_keywords.h" +#include "common.h" +#include "fallback.h" // IWYU pragma: keep -bool parser_keywords_skip_arguments(const wcstring &cmd) -{ - return contains(cmd, - L"else", - L"begin"); +bool parser_keywords_skip_arguments(const wcstring &cmd) { + return contains(cmd, L"else", L"begin"); } - -bool parser_keywords_is_subcommand(const wcstring &cmd) -{ - +bool parser_keywords_is_subcommand(const wcstring &cmd) { return parser_keywords_skip_arguments(cmd) || - contains(cmd, - L"command", - L"builtin", - L"while", - L"exec", - L"if", - L"and", - L"or", - L"not"); - + contains(cmd, L"command", L"builtin", L"while", L"exec", L"if", L"and", L"or", L"not"); } -bool parser_keywords_is_block(const wcstring &word) -{ - return contains(word, - L"for", - L"while", - L"if", - L"function", - L"switch", - L"begin"); +bool parser_keywords_is_block(const wcstring &word) { + return contains(word, L"for", L"while", L"if", L"function", L"switch", L"begin"); } -bool parser_keywords_is_reserved(const wcstring &word) -{ - return parser_keywords_is_block(word) || - parser_keywords_is_subcommand(word) || - contains(word, - L"end", - L"case", - L"else", - L"return", - L"continue", - L"break"); +bool parser_keywords_is_reserved(const wcstring &word) { + return parser_keywords_is_block(word) || parser_keywords_is_subcommand(word) || + contains(word, L"end", L"case", L"else", L"return", L"continue", L"break"); } - diff --git a/src/parser_keywords.h b/src/parser_keywords.h index d9637323a..f922b8262 100644 --- a/src/parser_keywords.h +++ b/src/parser_keywords.h @@ -1,7 +1,4 @@ -/** \file parser_keywords.h - -Functions having to do with parser keywords, like testing if a function is a block command. -*/ +// Functions having to do with parser keywords, like testing if a function is a block command. #ifndef FISH_PARSER_KEYWORD_H #define FISH_PARSER_KEYWORD_H @@ -9,38 +6,27 @@ Functions having to do with parser keywords, like testing if a function is a blo #include "common.h" -/** - Tests if the specified commands parameters should be interpreted as another command, which will be true if the command is either 'command', 'exec', 'if', 'while', or 'builtin'. This does not handle "else if" which is more complicated. - - \param cmd The command name to test - \return 1 of the command parameter is a command, 0 otherwise -*/ - +/// Tests if the specified commands parameters should be interpreted as another command, which will +/// be true if the command is either 'command', 'exec', 'if', 'while', or 'builtin'. This does not +/// handle "else if" which is more complicated. +/// +/// \param cmd The command name to test +/// \return 1 of the command parameter is a command, 0 otherwise bool parser_keywords_is_subcommand(const wcstring &cmd); -/** - Tests if the specified command is a reserved word, i.e. if it is - the name of one of the builtin functions that change the block or - command scope, like 'for', 'end' or 'command' or 'exec'. These - functions may not be overloaded, so their names are reserved. - - \param word The command name to test - \return 1 of the command parameter is a command, 0 otherwise -*/ +/// Tests if the specified command is a reserved word, i.e. if it is the name of one of the builtin +/// functions that change the block or command scope, like 'for', 'end' or 'command' or 'exec'. +/// These functions may not be overloaded, so their names are reserved. +/// +/// \param word The command name to test +/// \return 1 of the command parameter is a command, 0 otherwise bool parser_keywords_is_reserved(const wcstring &word); -/** - Test if the specified string is command that opens a new block -*/ - +/// Test if the specified string is command that opens a new block. bool parser_keywords_is_block(const wcstring &word); -/** - Check if the specified command is one of the builtins that cannot - have arguments, any followin argument is interpreted as a new - command -*/ +/// Check if the specified command is one of the builtins that cannot have arguments, any followin +/// argument is interpreted as a new command. bool parser_keywords_skip_arguments(const wcstring &cmd); - #endif