[ruby-dev:30741] Re: ObjectC style keyword argument
From:
Nobuyoshi Nakada <nobu@...>
Date:
2007-04-28 15:26:47 UTC
List:
ruby-dev #30741
なかだです。
At Fri, 27 Apr 2007 01:12:18 +0900,
Yukihiro Matsumoto wrote in [ruby-dev:30737]:
> |おととい電車の中で大体できちゃったのでなんとなく(謎)。
>
> あ、先を越された。私はずっとreduce/reduce conflictに悩まされ
> てました。いや、もっとObjective-Cに似せようと思ったのが敗因
> なんですが([x copy: y from: z]と書けるようにしたかった)。
式の先頭に[が来ることのないCならともかく、配列があるのでrubyじゃ
無理っぽい気がします。あと引数間のカンマの省略も、かなりきつい
制限がつくことになりそうです。
> メソッド定義は
>
> def copy:from:(x,y) p [x, y] end
>
> か、あるいは
>
> def copy: x from: y; p [x, y] end
>
> の方が良くないですかね? (前者で十分だけど)。
> キーワードの重複もありえますし。「do:value:value:」とか。
重複を忘れてました。とりあえず通常メソッドだけですが、後者で。
Index: parse.y
===================================================================
--- parse.y (revision 12223)
+++ parse.y (working copy)
@@ -520,4 +520,13 @@ static void ripper_compile_error(struct
#endif
+#ifdef RIPPER
+#define MUST_ASSOC(cons, car, cdr) do { \
+ if ((cons) == (car) || (cons) == (cdr) || \
+ TYPE(cons) != T_ARRAY || RARRAY_LEN(cons) != 2) { \
+ (cons) = rb_assoc_new((car), (cdr)); \
+ } \
+ } while (0)
+#endif
+
/* Older versions of Yacc set YYMAXDEPTH to a very low value by default (150,
for instance). This is too low for Ruby to parse some files, such as
@@ -529,4 +538,9 @@ static void ripper_compile_error(struct
#endif
+ID rb_alist_id(VALUE);
+#ifndef RIPPER
+static void assoc_arg_vars(struct parser_params *, NODE *);
+#endif
+
%}
@@ -613,4 +627,5 @@ static void ripper_compile_error(struct
%type <node> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_head f_margs
%type <node> assoc_list assocs assoc undef_list backref string_dvar for_var
+%type <node> assoc_call assoc_arg assoc_fargs assoc_farg
%type <node> block_param opt_block_param block_param_def f_opt
%type <node> bv_decls opt_bv_decl bvar
@@ -1040,4 +1055,17 @@ stmt : keyword_alias fitem {lex_state =
%*/
}
+ | primary_value '.' assoc_call
+ {
+ /*%%%*/
+ ID associd = rb_alist_id($3->nd_lit);
+ $3->nd_next->nd_alen = $3->nd_alen - 1;
+ $$ = NEW_CALL($1, associd, $3->nd_next);
+ fixpos($$, $1);
+ /*%
+ $$ = dispatch3(call, $1, ripper_id2sym('.'),
+ ID2SYM(rb_alist_id(rb_ary_shift($3))));
+ $$ = method_arg($$, $3);
+ %*/
+ }
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call
{
@@ -2830,4 +2858,35 @@ primary : literal
%*/
}
+ | keyword_def assoc_fargs
+ {
+ /*%%%*/
+ $<id>$ = cur_mid;
+ cur_mid = rb_alist_id($2->nd_tval);
+ in_def++;
+ local_push(0);
+ assoc_arg_vars(parser, $2->nd_var);
+ $2->nd_var = 0;
+ /*%
+ %*/
+ }
+ bodystmt
+ keyword_end
+ {
+ /*%%%*/
+ NODE *body = remove_begin($4);
+ reduce_nodes(&body);
+ $$ = NEW_DEFN(cur_mid, NEW_ARGS(RARRAY_LEN($2->nd_tval), 0),
+ body, NOEX_PRIVATE);
+ fixpos($$, $2);
+ local_pop();
+ in_def--;
+ cur_mid = $<id>3;
+ /*%
+ $$ = dispatch3(def, rb_alist_id(RARRAY_PTR($2)[0]),
+ RARRAY_PTR($2)[1], $5);
+ in_def--;
+ cur_mid = $<id>3;
+ %*/
+ }
| keyword_break
{
@@ -4315,5 +4374,5 @@ assoc : arg_value tASSOC arg_value
/*%
$$ = dispatch2(assoc_new, $1, $3);
- if ($$ == $1) $$ = rb_assoc_new($1, $3);
+ MUST_ASSOC($$, $1, $3);
%*/
}
@@ -4324,5 +4383,69 @@ assoc : arg_value tASSOC arg_value
/*%
$$ = dispatch2(assoc_new, $1, $2);
- if ($$ == $1) $$ = rb_assoc_new($1, $2);
+ MUST_ASSOC($$, $1, $2);
+ %*/
+ }
+ ;
+
+assoc_call : assoc_arg
+ | assoc_call ',' assoc_arg
+ {
+ /*%%%*/
+ rb_ary_concat($1->nd_lit, $3->nd_lit);
+ $$ = list_concat($1, $3->nd_next);
+ /*%
+ rb_ary_push(rb_ary_entry($1, 0), rb_ary_entry($3, 0));
+ rb_ary_push($1, rb_ary_entry($3, 1));
+ %*/
+ }
+
+assoc_arg : tLABEL arg_value
+ {
+ /*%%%*/
+ $$ = list_append(NEW_LIST(rb_ary_new3(1, ID2SYM($1))), $2);
+ /*%
+ $$ = rb_assoc_new(rb_ary_new3(1, $1), $2);
+ %*/
+ }
+ ;
+
+assoc_fargs : assoc_farg
+ {
+ /*%%%*/
+ ID pid = $1->nd_pid, mid = $1->nd_mid;
+ rb_gc_force_recycle((VALUE)$1);
+ $$ = NEW_ARGS(rb_ary_new3(1, ID2SYM(pid)),
+ NEW_LIST((NODE *)mid));
+ /* nd_tval, nd_var */
+ /*%
+ $$ = $1;
+ RARRAY_PTR($$)[0] = rb_ary_new3(1, RARRAY_PTR($1)[0]);
+ RARRAY_PTR($$)[1] = rb_ary_new3(1, RARRAY_PTR($1)[1]);
+ %*/
+ }
+ | assoc_fargs assoc_farg
+ {
+ /*%%%*/
+ ID pid = $2->nd_pid, mid = $2->nd_mid;
+ rb_gc_force_recycle((VALUE)$2);
+ $$ = $1;
+ rb_ary_push($$->nd_tval, ID2SYM(pid));
+ $$->nd_var = list_append($$->nd_var, (NODE *)mid);
+ /*%
+ $$ = $1;
+ rb_ary_push(RARRAY_PTR($$)[0], RARRAY_PTR($2)[0]);
+ rb_ary_push(RARRAY_PTR($$)[1], RARRAY_PTR($2)[1]);
+ %*/
+ }
+ ;
+assoc_farg : tLABEL f_norm_arg
+ {
+ /*%%%*/
+ if (!is_local_id($2))
+ yyerror("formal argument must be local variable");
+ $$ = NEW_ARGS_AUX($1, $2);
+ /*%
+ $$ = dispatch2(assoc_farg, $1, $2);
+ MUST_ASSOC($$, $1, $2);
%*/
}
@@ -6795,4 +6918,6 @@ parser_yylex(struct parser_params *parse
if ((lex_state == EXPR_BEG && !cmd_state) ||
lex_state == EXPR_ARG ||
+ lex_state == EXPR_DOT ||
+ lex_state == EXPR_FNAME ||
lex_state == EXPR_CMDARG) {
if (peek(':') && !(lex_p + 1 < lex_pend && lex_p[1] == ':')) {
@@ -8501,4 +8626,28 @@ rb_id2name(ID id)
}
+ID
+rb_alist_id(VALUE names)
+{
+ VALUE name = rb_str_cat(rb_ary_join(names, rb_str_new2(":")), ":", 1);
+ return rb_intern2(RSTRING_PTR(name), RSTRING_LEN(name));
+}
+
+#ifndef RIPPER
+static void
+assoc_arg_vars(struct parser_params *parser, NODE *var)
+{
+ NODE *next;
+
+ while (var) {
+ ID id = var->nd_pid;
+ shadowing_lvar(id);
+ arg_var(id);
+ next = var->nd_next;
+ rb_gc_force_recycle((VALUE)var);
+ var = next;
+ }
+}
+#endif
+
static int
symbols_i(VALUE sym, ID value, VALUE ary)
--
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
中田 伸悦