1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Add pipeline operator [Feature #15799]

This commit is contained in:
Nobuyoshi Nakada 2019-04-23 13:14:27 +09:00
parent e717d6faa8
commit f169043d81
No known key found for this signature in database
GPG key ID: 4BC7D6DF58D8DF60
6 changed files with 47 additions and 1 deletions

12
NEWS
View file

@ -48,6 +48,18 @@ sufficient information, see the ChangeLog file or Redmine
" # This has been warned since 2.4 " # This has been warned since 2.4
EOS EOS
* Pipeline operator is added.
This code equals to the next code.
foo()
|> bar 1, 2
|> display
foo()
.bar(1, 2)
.display
=== Core classes updates (outstanding ones only) === Core classes updates (outstanding ones only)
Enumerable:: Enumerable::

View file

@ -111,6 +111,7 @@ token_ops = %[\
OROP || OROP ||
ANDDOT &. ANDDOT &.
METHREF .: METHREF .:
PIPE |>
] ]
class KeywordError < RuntimeError class KeywordError < RuntimeError

View file

@ -262,6 +262,7 @@ static const struct token_assoc {
{tDSTAR, O(op)}, {tDSTAR, O(op)},
{tANDDOT, O(op)}, {tANDDOT, O(op)},
{tMETHREF, O(op)}, {tMETHREF, O(op)},
{tPIPE, O(op)},
{tSTRING_BEG, O(tstring_beg)}, {tSTRING_BEG, O(tstring_beg)},
{tSTRING_CONTENT, O(tstring_content)}, {tSTRING_CONTENT, O(tstring_content)},
{tSTRING_DBEG, O(embexpr_beg)}, {tSTRING_DBEG, O(embexpr_beg)},

25
parse.y
View file

@ -1002,7 +1002,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
%type <node> literal numeric simple_numeric ssym dsym symbol cpath %type <node> literal numeric simple_numeric ssym dsym symbol cpath
%type <node> top_compstmt top_stmts top_stmt begin_block %type <node> top_compstmt top_stmts top_stmt begin_block
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call %type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
%type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr %type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr pipeline
%type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure %type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure
%type <node> args call_args opt_call_args %type <node> args call_args opt_call_args
%type <node> paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail %type <node> paren_args opt_paren_args args_tail opt_args_tail block_args_tail opt_block_args_tail
@ -1060,6 +1060,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
%token <id> tANDDOT RUBY_TOKEN(ANDDOT) "&." %token <id> tANDDOT RUBY_TOKEN(ANDDOT) "&."
%token <id> tCOLON2 RUBY_TOKEN(COLON2) "::" %token <id> tCOLON2 RUBY_TOKEN(COLON2) "::"
%token <id> tMETHREF RUBY_TOKEN(METHREF) ".:" %token <id> tMETHREF RUBY_TOKEN(METHREF) ".:"
%token tPIPE RUBY_TOKEN(PIPE) "|>"
%token tCOLON3 ":: at EXPR_BEG" %token tCOLON3 ":: at EXPR_BEG"
%token <id> tOP_ASGN "operator-assignment" /* +=, -= etc. */ %token <id> tOP_ASGN "operator-assignment" /* +=, -= etc. */
%token tASSOC "=>" %token tASSOC "=>"
@ -1095,6 +1096,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in
%nonassoc modifier_if modifier_unless modifier_while modifier_until %nonassoc modifier_if modifier_unless modifier_while modifier_until
%left keyword_or keyword_and %left keyword_or keyword_and
%right keyword_not %right keyword_not
%left tPIPE
%nonassoc keyword_defined %nonassoc keyword_defined
%right '=' tOP_ASGN %right '=' tOP_ASGN
%left modifier_rescue %left modifier_rescue
@ -2269,12 +2271,29 @@ arg : lhs '=' arg_rhs
/*% %*/ /*% %*/
/*% ripper: ifop!($1, $3, $6) %*/ /*% ripper: ifop!($1, $3, $6) %*/
} }
| pipeline
| primary | primary
{ {
$$ = $1; $$ = $1;
} }
; ;
pipeline : arg tPIPE operation2 opt_paren_args
{
/*%%%*/
$$ = new_command_qcall(p, ID2VAL(idPIPE), $1, $3, $4, Qnull, &@3, &@$);
/*% %*/
/*% ripper: command_call!($1, ID2VAL(idPIPE), $3, $4) %*/
}
| arg tPIPE operation2 opt_paren_args brace_block
{
/*%%%*/
$$ = new_command_qcall(p, ID2VAL(idPIPE), $1, $3, $4, $5, &@3, &@$);
/*% %*/
/*% ripper: method_add_block!(command_call!($1, ID2VAL(idPIPE), $3, $4), $5) %*/
}
;
relop : '>' {$$ = '>';} relop : '>' {$$ = '>';}
| '<' {$$ = '<';} | '<' {$$ = '<';}
| tGEQ {$$ = idGE;} | tGEQ {$$ = idGE;}
@ -8924,6 +8943,10 @@ parser_yylex(struct parser_params *p)
SET_LEX_STATE(EXPR_BEG); SET_LEX_STATE(EXPR_BEG);
return tOP_ASGN; return tOP_ASGN;
} }
if (c == '>') {
SET_LEX_STATE(EXPR_DOT);
return tPIPE;
}
SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL); SET_LEX_STATE(IS_AFTER_OPERATOR() ? EXPR_ARG : EXPR_BEG|EXPR_LABEL);
pushback(p, c); pushback(p, c);
return '|'; return '|';

View file

@ -573,6 +573,8 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase
scan('op', 'obj.:foo') scan('op', 'obj.:foo')
assert_equal [], assert_equal [],
scan('op', %q[`make all`]) scan('op', %q[`make all`])
assert_equal %w[|>],
scan('op', %q[x|>y])
end end
def test_symbeg def test_symbeg

View file

@ -1379,6 +1379,13 @@ eom
assert_syntax_error('@1', /outside block/) assert_syntax_error('@1', /outside block/)
end end
def test_pipeline_operator
assert_valid_syntax('x |> y')
x = nil
assert_equal("121", eval('x = 12 |> pow(2) |> to_s(11)'))
assert_equal(12, x)
end
private private
def not_label(x) @result = x; @not_label ||= nil end def not_label(x) @result = x; @not_label ||= nil end