From 1c58b6d83e36f014189461a5d4a23fa590f66b45 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Mon, 17 Mar 2014 08:45:25 -0700 Subject: [PATCH] Rewrite parser_t::eval_args to use new AST parser --- complete.cpp | 2 +- fish_tests.cpp | 9 +++++ parser.cpp | 90 ++++++++++++++++---------------------------------- parser.h | 11 +++--- 4 files changed, 43 insertions(+), 69 deletions(-) diff --git a/complete.cpp b/complete.cpp index 9b8d5c0b1..648824ecf 100644 --- a/complete.cpp +++ b/complete.cpp @@ -1249,7 +1249,7 @@ void completer_t::complete_from_args(const wcstring &str, if (! is_autosuggest) proc_push_interactive(0); - parser.eval_args(args.c_str(), possible_comp); + parser.eval_args(args, possible_comp); if (! is_autosuggest) proc_pop_interactive(); diff --git a/fish_tests.cpp b/fish_tests.cpp index 5b7bcea6d..35b1a7ff3 100644 --- a/fish_tests.cpp +++ b/fish_tests.cpp @@ -620,6 +620,15 @@ static void test_parser() /* This is disabled since it produces a long backtrace. We should find a way to either visually compress the backtrace, or disable error spewing */ parser_t::principal_parser().eval(L"function recursive1 ; recursive2 ; end ; function recursive2 ; recursive1 ; end ; recursive1; ", io_chain_t(), TOP); #endif + + say(L"Testing eval_args"); + completion_list_t comps; + parser_t::principal_parser().eval_args(L"alpha 'beta gamma' delta", comps); + do_test(comps.size() == 3); + do_test(comps.at(0).completion == L"alpha"); + do_test(comps.at(1).completion == L"beta gamma"); + do_test(comps.at(2).completion == L"delta"); + } /* Wait a while and then SIGINT the main thread */ diff --git a/parser.cpp b/parser.cpp index b361fe494..872f99fc4 100644 --- a/parser.cpp +++ b/parser.cpp @@ -546,7 +546,8 @@ void parser_t::print_errors_stderr() } } -void parser_t::eval_args(const wchar_t *line, std::vector &args) + +void parser_t::eval_args(const wcstring &arg_list_src, std::vector &output_arg_list) { expand_flags_t eflags = 0; if (! show_errors) @@ -554,77 +555,44 @@ void parser_t::eval_args(const wchar_t *line, std::vector &args) if (this->parser_type != PARSER_TYPE_GENERAL) eflags |= EXPAND_SKIP_CMDSUBST; - bool do_loop=1; - - if (! line) return; - - // PCA we need to suppress calling proc_push_interactive off of the main thread. + /* Suppress calling proc_push_interactive off of the main thread. */ if (this->parser_type == PARSER_TYPE_GENERAL) - proc_push_interactive(0); - - tokenizer_t tok(line, (show_errors ? 0 : TOK_SQUASH_ERRORS)); - - /* - eval_args may be called while evaulating another command, so we - save the previous tokenizer and restore it on exit - */ - scoped_push tokenizer_push(¤t_tokenizer, &tok); - scoped_push tokenizer_pos_push(¤t_tokenizer_pos, 0); - - error_code=0; - - for (; do_loop && tok_has_next(&tok) ; tok_next(&tok)) { - current_tokenizer_pos = tok_get_pos(&tok); - switch (tok_last_type(&tok)) + proc_push_interactive(0); + } + + /* 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_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()); + const parse_node_t *arg_list = &tree.at(0); + assert(arg_list->type == symbol_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) { - case TOK_STRING: + const wcstring arg_src = arg_node->get_source(arg_list_src); + if (expand_string(arg_src, output_arg_list, eflags) == EXPAND_ERROR) { - const wcstring tmp = tok_last(&tok); - if (expand_string(tmp, args, eflags) == EXPAND_ERROR) - { - err_pos=tok_get_pos(&tok); - do_loop=0; - } - break; - } - - case TOK_END: - { - break; - } - - case TOK_ERROR: - { - if (show_errors) - error(SYNTAX_ERROR, - tok_get_pos(&tok), - TOK_ERR_MSG, - tok_last(&tok)); - - do_loop=0; - break; - } - - default: - { - if (show_errors) - error(SYNTAX_ERROR, - tok_get_pos(&tok), - UNEXPECTED_TOKEN_ERR_MSG, - tok_get_desc(tok_last_type(&tok))); - - do_loop=0; + /* Failed to expand a string */ break; } } } - if (show_errors) - this->print_errors_stderr(); - if (this->parser_type == PARSER_TYPE_GENERAL) + { proc_pop_interactive(); + } } void parser_t::stack_trace(size_t block_idx, wcstring &buff) const diff --git a/parser.h b/parser.h index 675fe6afd..3e4a431f3 100644 --- a/parser.h +++ b/parser.h @@ -340,15 +340,12 @@ public: /** 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 line Line to evaluate - \param output List to insert output to + \param arg_src String to evaluate as an argument list + \param output List to insert output into */ - /** - \param line Line to evaluate - \param output List to insert output to - */ - void eval_args(const wchar_t *line, std::vector &output); + void eval_args(const wcstring &arg_src, std::vector &output); /** Sets the current evaluation error. This function should only be used by libraries that are called by