diff --git a/plugins/sh/gen/com/intellij/sh/parser/ShParser.java b/plugins/sh/gen/com/intellij/sh/parser/ShParser.java index 0372261b02bc..cc20cc20049a 100644 --- a/plugins/sh/gen/com/intellij/sh/parser/ShParser.java +++ b/plugins/sh/gen/com/intellij/sh/parser/ShParser.java @@ -1176,7 +1176,7 @@ public class ShParser implements PsiParser, LightPsiParser { if (!recursion_guard_(b, l, "function_definition")) return false; if (!nextTokenIs(b, "", FUNCTION, WORD)) return false; boolean r; - Marker m = enter_section_(b, l, _NONE_, FUNCTION_DEFINITION, ""); + Marker m = enter_section_(b, l, _COLLAPSE_, FUNCTION_DEFINITION, ""); r = function_definition_0(b, l + 1); r = r && function_definition_inner(b, l + 1); exit_section_(b, l, m, r, false, null); @@ -1206,7 +1206,7 @@ public class ShParser implements PsiParser, LightPsiParser { /* ********************************************************** */ // word argument_list newlines block - // | function word argument_list? newlines block + // | function (word | <>) argument_list? newlines block static boolean function_definition_inner(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "function_definition_inner")) return false; if (!nextTokenIs(b, "", FUNCTION, WORD)) return false; @@ -1232,20 +1232,32 @@ public class ShParser implements PsiParser, LightPsiParser { return r || p; } - // function word argument_list? newlines block + // function (word | <>) argument_list? newlines block private static boolean function_definition_inner_1(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "function_definition_inner_1")) return false; boolean r, p; Marker m = enter_section_(b, l, _NONE_); - r = consumeTokens(b, 1, FUNCTION, WORD); + r = consumeToken(b, FUNCTION); p = r; // pin = function|argument_list - r = r && report_error_(b, function_definition_inner_1_2(b, l + 1)); + r = r && report_error_(b, function_definition_inner_1_1(b, l + 1)); + r = p && report_error_(b, function_definition_inner_1_2(b, l + 1)) && r; r = p && report_error_(b, newlines(b, l + 1)) && r; r = p && block(b, l + 1) && r; exit_section_(b, l, m, r, p, null); return r || p; } + // word | <> + private static boolean function_definition_inner_1_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "function_definition_inner_1_1")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, WORD); + if (!r) r = keywordsRemapped(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + // argument_list? private static boolean function_definition_inner_1_2(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "function_definition_inner_1_2")) return false; @@ -2511,7 +2523,7 @@ public class ShParser implements PsiParser, LightPsiParser { } /* ********************************************************** */ - // test simple_command_element+ + // test simple_command_element* public static boolean test_command(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "test_command")) return false; if (!nextTokenIs(b, TEST)) return false; @@ -2524,19 +2536,15 @@ public class ShParser implements PsiParser, LightPsiParser { return r || p; } - // simple_command_element+ + // simple_command_element* private static boolean test_command_1(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "test_command_1")) return false; - boolean r; - Marker m = enter_section_(b); - r = simple_command_element(b, l + 1); - while (r) { + while (true) { int c = current_position_(b); if (!simple_command_element(b, l + 1)) break; if (!empty_element_parsed_guard_(b, "test_command_1", c)) break; } - exit_section_(b, m, null, r); - return r; + return true; } /* ********************************************************** */ diff --git a/plugins/sh/grammar/sh.bnf b/plugins/sh/grammar/sh.bnf index 69f16347bc34..4f62dd7f3643 100644 --- a/plugins/sh/grammar/sh.bnf +++ b/plugins/sh/grammar/sh.bnf @@ -143,7 +143,7 @@ pipeline_command ::= '!'? pipeline let_command ::= let expression eval_command ::= eval (EVAL_CONTENT|simple_command_element)+ -test_command ::= test simple_command_element+ +test_command ::= test simple_command_element* private pipeline_recover ::= !(case|if|while|until|select|'{'|function|'$'|'&&'|';'|';;'|'||'|'&'|'!'|'['|'[['|'('|')'|'|'|'|&'|'\n'|'(('| var | word|EXPR_CONDITIONAL_LEFT|ARITH_SQUARE_LEFT | CLOSE_BACKQUOTE | do | done | '}') @@ -219,7 +219,7 @@ private pipeline_command_list_separator ::= ('&&'| '||' | '&' | ';' | '\n') function_definition ::= &(function | word '(') function_definition_inner {extends=command} private function_definition_inner ::= word argument_list newlines block - | function word argument_list? newlines block {pin(".*")="function|argument_list"} + | function (word | <>) argument_list? newlines block {pin(".*")="function|argument_list"} private argument_list ::= '(' ')' {recoverWhile = argument_list_recover} private argument_list_recover ::= !('\n'| '{') diff --git a/plugins/sh/testData/parser/conditional.sh b/plugins/sh/testData/parser/conditional.sh index 1f3c9ad8091c..51f138fb03e2 100644 --- a/plugins/sh/testData/parser/conditional.sh +++ b/plugins/sh/testData/parser/conditional.sh @@ -76,4 +76,9 @@ fi [[ ${osvers} -ge 7 ]] [[ (pwd) ]] -[[ ${sss} -ge 7 ]] \ No newline at end of file +[[ ${sss} -ge 7 ]] + +function test() { + echo my custom test function $3 +} +test \ No newline at end of file diff --git a/plugins/sh/testData/parser/conditional.txt b/plugins/sh/testData/parser/conditional.txt index 0d011aac621c..b14094426fa6 100644 --- a/plugins/sh/testData/parser/conditional.txt +++ b/plugins/sh/testData/parser/conditional.txt @@ -914,4 +914,49 @@ SHELL_SCRIPT NUMBER PsiElement(int)('7') PsiWhiteSpace(' ') - PsiElement(]])(']]') \ No newline at end of file + PsiElement(]])(']]') + PsiElement(\n)('\n') + PsiElement(\n)('\n') + COMMANDS_LIST + PIPELINE_COMMAND + PIPELINE + FUNCTION_DEFINITION + PsiElement(function)('function') + PsiWhiteSpace(' ') + SIMPLE_COMMAND_ELEMENT + PsiElement(word)('test') + PsiElement(()('(') + PsiElement())(')') + PsiWhiteSpace(' ') + BLOCK + PsiElement({)('{') + COMPOUND_LIST + PsiElement(\n)('\n') + PsiWhiteSpace(' ') + PIPELINE_COMMAND + PIPELINE + SIMPLE_COMMAND + GENERIC_COMMAND_DIRECTIVE + LITERAL + PsiElement(word)('echo') + PsiWhiteSpace(' ') + LITERAL + PsiElement(word)('my') + PsiWhiteSpace(' ') + LITERAL + PsiElement(word)('custom') + PsiWhiteSpace(' ') + SIMPLE_COMMAND_ELEMENT + PsiElement(word)('test') + PsiWhiteSpace(' ') + LITERAL + PsiElement(word)('function') + PsiWhiteSpace(' ') + VARIABLE + PsiElement(var)('$3') + PsiElement(\n)('\n') + PsiElement(})('}') + PsiElement(\n)('\n') + COMMANDS_LIST + TEST_COMMAND + PsiElement(test)('test') \ No newline at end of file