summaryrefslogtreecommitdiff
path: root/parse.y
diff options
context:
space:
mode:
authorYukihiro Matsumoto <matz@ruby-lang.org>1995-02-01 19:48:24 +0900
committerTakashi Kokubun <takashikkbn@gmail.com>2019-08-17 22:09:31 +0900
commit897cf066952978ccbae1d57bbc14a03c7b98a1e1 (patch)
treebc83424954929dc9574e40a0aee874f45965a8ae /parse.y
parent5d828b25d4ae30a000c054a724ac248dadbb97b3 (diff)
version 0.65v0_65
https://cache.ruby-lang.org/pub/ruby/1.0/ruby-0.65.tar.gz Wed Feb 1 19:48:24 1995 Yukihiro Matsumoto (matz@ix-02) * string.c(str_replace): 置き換える文字列の長さが等しい時メモリコ ピーをしない. * string.c(rindex): バグ修正. Mon Jan 30 11:23:05 1995 Yukihiro Matsumoto (matz@ix-02) * parse.y(value_expr): ifのチェックを追加. * gc.c(gc_mark): free cellの扱いにバグ. * parse.y: 文法の変更(よりシンプルに).例外を減らした. Thu Jan 26 00:52:55 1995 Yukihiro Matsumoto (matz@dyna) * parse.y: 引数として連想配列を置くことができるように.この場合, 連想配列リテラルが最終引数となる. * parse.y: 配列参照の`[]'内が空でもよいことにした. Tue Jan 24 14:45:15 1995 Yukihiro Matsumoto (matz@ix-02) * class.c(rb_include_module): `-v'を指定した時にはincludeしたモジュー ルとクラス定数が衝突していないかチェックする. Mon Jan 23 10:42:09 1995 Yukihiro Matsumoto (matz@ix-02) * parse.y(rb_class2name): メタクラスに関するbug fix. * dict.c: Dict[..]で辞書の生成が出来るように. * array.c: Array[..]で配列の生成が出来るように. * parse.y: 辞書の表現として{a,b,..}という形式も許すように. Fri Jan 20 10:28:38 1995 Yukihiro Matsumoto (matz@ix-02) * re.c(Regexp.quote): 正規表現をエスケープするメソッド. * 無駄なrb_intern()を減らした. * parse.y: `!', `!=', `!~'を特殊演算子にする.よってこれらは再定義 できなくなった. Wed Jan 18 13:20:41 1995 Yukihiro Matsumoto (matz@ix-02) * parse.y: 文法の整理(unless,untilをなくした). Tue Jan 17 11:11:27 1995 Yukihiro Matsumoto (matz@ix-02) * eval.c: defでメソッド再定義時にはスーパークラスのメソッドの可視 性を継承する.最初の定義の時は今までと同じデフォルト(トップレベ ルで関数的,クラス定義内で通常メソッド). * object.c(Class::new): オブジェクトの生成時に関数的メ ソッドinit_objectが必ず呼ばれるように変更. * eval.c: 未定義のメソッドに対してunknownメソッドが呼ばれるように なった.エラー表示が今までと同じになるようにenvを調節している. Fri Jan 13 14:40:30 1995 Yukihiro Matsumoto (matz@ix-02) * gc.c: gcを若干書き換えて整理した.が,あまり変化はなかったようだ. * parse.y(yylex): symbolを\symから:symに変更した. Thu Jan 12 01:39:28 1995 Yukihiro Matsumoto (matz@dyna) * eval.c: 新規関数 rb_eval_string(). * gc.c: gc_mark()を一部非再帰化. * variable.c(rb_ivar_{get,set}): インスタンス変数のアクセス周りで チェックが足りなかった. * variable.c: クラス定数とインスタンス変数でハッシュテーブルを共有 するようにした. * ruby.h: iv_tblをRBasicからRObjectとRClassへ移動した.これにより, ObjectとClass,Moduleしかインスタンス変数を持てなくなる.が,メモ リ効率は若干向上する.
Diffstat (limited to 'parse.y')
-rw-r--r--parse.y759
1 files changed, 384 insertions, 375 deletions
diff --git a/parse.y b/parse.y
index c4148d88d3..7c84221c8c 100644
--- a/parse.y
+++ b/parse.y
@@ -3,7 +3,7 @@
parse.y -
$Author: matz $
- $Date: 1995/01/10 10:42:45 $
+ $Date: 1995/01/12 08:54:50 $
created at: Fri May 28 18:02:42 JST 1993
Copyright (C) 1994 Yukihiro Matsumoto
@@ -50,7 +50,7 @@ static enum lex_state {
static ID cur_class = Qnil, cur_mid = Qnil;
static int in_module, in_single;
-static void value_expr();
+static int value_expr();
static NODE *cond();
static NODE *cond2();
@@ -96,8 +96,6 @@ static void setup_top_local();
ELSE
CASE
WHEN
- UNLESS
- UNTIL
WHILE
FOR
IN
@@ -120,9 +118,7 @@ static void setup_top_local();
_FILE_
_LINE_
IF_MOD
- UNLESS_MOD
WHILE_MOD
- UNTIL_MOD
ALIAS
%token <id> IDENTIFIER GVAR IVAR CONSTANT
@@ -131,14 +127,14 @@ static void setup_top_local();
%type <node> singleton inc_list
%type <val> literal numeric
-%type <node> compstmts stmts stmt stmt0 expr expr0 var_ref
+%type <node> compexpr exprs expr arg primary var_ref
%type <node> if_tail opt_else case_body cases resque ensure
-%type <node> call_args call_args0 args args2 array
+%type <node> call_args call_args0 args args2 opt_args
%type <node> f_arglist f_args assoc_list assocs assoc
%type <node> mlhs mlhs_head mlhs_tail lhs iter_var opt_iter_var
%type <id> superclass variable symbol
%type <id> fname op rest_arg
-%type <num> f_arg
+%type <num> f_arg
%token UPLUS /* unary+ */
%token UMINUS /* unary- */
%token POW /* ** */
@@ -156,11 +152,13 @@ static void setup_top_local();
%token <id> OP_ASGN /* +=, -= etc. */
%token ASSOC /* => */
%token LPAREN LBRACK LBRACE
+%token SYMBEG
/*
* precedence table
*/
+%left IF_MOD WHILE_MOD
%left OR
%left AND
%left YIELD RETURN FAIL
@@ -186,91 +184,74 @@ program : {
lex_state = EXPR_BEG;
init_top_local();
}
- compstmts
+ compexpr
{
eval_tree = block_append(eval_tree, $2);
setup_top_local();
}
-compstmts : stmts opt_term
+compexpr : exprs opt_term
-stmts : /* none */
+exprs : /* none */
{
$$ = Qnil;
}
- | stmt
- | stmts term stmt
+ | expr
+ | exprs term expr
{
$$ = block_append($1, $3);
}
- | stmts error
+ | exprs error
{
lex_state = EXPR_BEG;
}
- stmt
+ expr
{
yyerrok;
$$ = block_append($1, $4);
}
-stmt : CLASS IDENTIFIER superclass
+expr : mlhs '=' args2
{
- if (cur_class || cur_mid || in_single)
- Error("nested class definition");
- cur_class = $2;
- push_local();
+ value_expr($3);
+ $1->nd_value = $3;
+ $$ = $1;
}
- compstmts
- END
+ | assocs
{
- $$ = NEW_CLASS($2, $5, $3);
- pop_local();
- cur_class = Qnil;
+ $$ = NEW_HASH($1);
}
- | MODULE IDENTIFIER
+ | RETURN args2
{
- if (cur_class != Qnil)
- Error("nested module definition");
- cur_class = $2;
- in_module = 1;
- push_local();
+ value_expr($2);
+ if (!cur_mid && !in_single)
+ Error("return appeared outside of method");
+ $$ = NEW_RET($2);
}
- compstmts
- END
+ | FAIL args2
{
- $$ = NEW_MODULE($2, $4);
- pop_local();
- cur_class = Qnil;
- in_module = 0;
+ value_expr($2);
+ $$ = NEW_FAIL($2);
}
- | DEF fname
+ | YIELD args2
{
- if (cur_mid || in_single)
- Error("nested method definition");
- cur_mid = $2;
- push_local();
+ value_expr($2);
+ $$ = NEW_YIELD($2);
}
- f_arglist
- compstmts
- END
+ | IDENTIFIER call_args0
{
- $$ = NEW_DEFN($2, NEW_RFUNC($4, $5), cur_class?0:1);
- pop_local();
- cur_mid = Qnil;
+ $$ = NEW_CALL(Qnil, $1, $2);
}
- | DEF singleton '.' fname
+ | primary '.' IDENTIFIER call_args0
{
- value_expr($2);
- in_single++;
- push_local();
+ value_expr($1);
+ $$ = NEW_CALL($1, $3, $4);
}
- f_arglist
- compstmts
- END
+ | SUPER call_args0
{
- $$ = NEW_DEFS($2, $4, NEW_RFUNC($6, $7));
- pop_local();
- in_single--;
+ if (!cur_mid && !in_single)
+ Error("super called outside of method");
+ $$ = NEW_SUPER($2);
}
| UNDEF fname
{
@@ -286,100 +267,31 @@ stmt : CLASS IDENTIFIER superclass
Error("include appeared in method definition");
$$ = $2;
}
- | stmt0 IF_MOD stmt0
+ | expr IF_MOD expr
{
$$ = NEW_IF(cond($3), $1, Qnil);
}
- | stmt0 UNLESS_MOD stmt0
- {
- $$ = NEW_UNLESS(cond($3), $1, Qnil);
- }
- | stmt0 WHILE_MOD stmt0
+ | expr WHILE_MOD expr
{
$$ = NEW_WHILE2(cond($3), $1);
}
- | stmt0 UNTIL_MOD stmt0
- {
- $$ = NEW_UNTIL2(cond($3), $1);
- }
- | stmt AND stmt
+ | expr AND expr
{
$$ = NEW_AND(cond($1), cond($3));
}
- | stmt OR stmt
+ | expr OR expr
{
$$ = NEW_OR(cond($1), cond($3));
}
- | stmt0
-
-stmt0 : mlhs '=' args2
- {
- $1->nd_value = $3;
- $$ = $1;
- }
- | REDO
- {
- $$ = NEW_REDO();
- }
- | BREAK
- {
- $$ = NEW_BREAK();
- }
- | CONTINUE
- {
- $$ = NEW_CONT();
- }
- | RETRY
- {
- $$ = NEW_RETRY();
- }
- | RETURN args2
- {
- value_expr($2);
- if (!cur_mid && !in_single)
- Error("return appeared outside of method");
- $$ = NEW_RET($2);
- }
- | RETURN
- {
- if (!cur_mid && !in_single)
- Error("return appeared outside of method");
- $$ = NEW_RET(Qnil);
- }
- | FAIL args2
- {
- value_expr($2);
- $$ = NEW_FAIL($2);
- }
- | YIELD args2
- {
- value_expr($2);
- $$ = NEW_YIELD($2);
- }
- | IDENTIFIER call_args0
- {
- $$ = NEW_CALL(Qnil, $1, $2);
- }
- | expr0 '.' IDENTIFIER call_args0
- {
- value_expr($1);
- $$ = NEW_CALL($1, $3, $4);
- }
- | SUPER call_args0
- {
- if (!cur_mid && !in_single)
- Error("super called outside of method");
- $$ = NEW_SUPER($2);
- }
- | expr
+ | arg
mlhs : mlhs_head
{
- $$ = NEW_MASGN(NEW_LIST($1),Qnil);
+ $$ = NEW_MASGN(NEW_LIST($1), Qnil);
}
| mlhs_head '*' lhs
{
- $$ = NEW_MASGN(NEW_LIST($1),$3);
+ $$ = NEW_MASGN(NEW_LIST($1), $3);
}
| mlhs_head mlhs_tail
{
@@ -390,18 +302,7 @@ mlhs : mlhs_head
$$ = NEW_MASGN(list_concat(NEW_LIST($1),$2),$5);
}
-mlhs_head : variable comma
- {
- $$ = asignable($1, Qnil);
- }
- | expr0 '[' args rbracket comma
- {
- $$ = aryset($1, $3, Qnil);
- }
- | expr0 '.' IDENTIFIER comma
- {
- $$ = attrset($1, $3, Qnil);
- }
+mlhs_head : lhs comma
mlhs_tail : lhs
{
@@ -416,24 +317,15 @@ lhs : variable
{
$$ = asignable($1, Qnil);
}
- | expr0 '[' args rbracket
+ | primary '[' opt_args rbracket
{
$$ = aryset($1, $3, Qnil);
}
- | expr0 '.' IDENTIFIER
+ | primary '.' IDENTIFIER
{
$$ = attrset($1, $3, Qnil);
}
-superclass : /* none */
- {
- $$ = Qnil;
- }
- | ':' IDENTIFIER
- {
- $$ = $2;
- }
-
inc_list : IDENTIFIER
{
$$ = NEW_INC($1);
@@ -467,9 +359,7 @@ op : COLON2 { $$ = COLON2; }
| '&' { $$ = '&'; }
| CMP { $$ = CMP; }
| EQ { $$ = EQ; }
- | NEQ { $$ = NEQ; }
| MATCH { $$ = MATCH; }
- | NMATCH { $$ = NMATCH; }
| '>' { $$ = '>'; }
| GEQ { $$ = GEQ; }
| '<' { $$ = '<'; }
@@ -482,119 +372,26 @@ op : COLON2 { $$ = COLON2; }
| '/' { $$ = '/'; }
| '%' { $$ = '%'; }
| POW { $$ = POW; }
- | '!' { $$ = '!'; }
| '~' { $$ = '~'; }
| UPLUS { $$ = UMINUS; }
| UMINUS { $$ = UPLUS; }
| AREF { $$ = AREF; }
| ASET { $$ = ASET; }
-f_arglist : '(' f_args rparen
- {
- $$ = $2;
- }
- | term
- {
- $$ = NEW_ARGS(0, -1);
- }
-
-f_args : /* no arg */
- {
- $$ = NEW_ARGS(0, -1);
- }
- | f_arg
- {
- $$ = NEW_ARGS($1, -1);
- }
- | f_arg comma rest_arg
- {
- $$ = NEW_ARGS($1, $3);
- }
- | rest_arg
- {
- $$ = NEW_ARGS(Qnil, $1);
- }
- | f_arg error
- {
- lex_state = EXPR_BEG;
- $$ = NEW_ARGS($1, -1);
- }
- | error
- {
- lex_state = EXPR_BEG;
- $$ = NEW_ARGS(0, -1);
- }
-
-f_arg : IDENTIFIER
- {
- if (!is_local_id($1))
- Error("formal argument must be local variable");
- local_cnt($1);
- $$ = 1;
- }
- | f_arg comma IDENTIFIER
- {
- if (!is_local_id($3))
- Error("formal argument must be local variable");
- local_cnt($3);
- $$ += 1;
- }
-
-rest_arg : '*' IDENTIFIER
- {
- if (!is_local_id($2))
- Error("rest argument must be local variable");
- $$ = local_cnt($2);
- }
-
-singleton : var_ref
- {
- if (nd_type($1) == NODE_SELF) {
- $$ = NEW_SELF();
- }
- else if (nd_type($1) == NODE_NIL) {
- Error("Can't define single method for nil.");
- $$ = Qnil;
- }
- else {
- $$ = $1;
- }
- }
- | LPAREN compstmts rparen
- {
- switch (nd_type($2)) {
- case NODE_STR:
- case NODE_STR2:
- case NODE_XSTR:
- case NODE_XSTR2:
- case NODE_DREGX:
- case NODE_DGLOB:
- case NODE_LIT:
- case NODE_ARRAY:
- case NODE_ZARRAY:
- Error("Can't define single method for literals.");
- default:
- break;
- }
- $$ = $2;
- }
-
-expr : variable '=' expr
+arg : variable '=' arg
{
value_expr($3);
$$ = asignable($1, $3);
}
- | expr0 '[' args rbracket '=' expr
+ | primary '[' opt_args rbracket '=' arg
{
- value_expr($6);
$$ = aryset($1, $3, $6);
}
- | expr0 '.' IDENTIFIER '=' expr
+ | primary '.' IDENTIFIER '=' arg
{
- value_expr($5);
$$ = attrset($1, $3, $5);
}
- | variable OP_ASGN expr
+ | variable OP_ASGN arg
{
NODE *val;
@@ -613,27 +410,31 @@ expr : variable '=' expr
}
$$ = asignable($1, call_op(val, $2, 1, $3));
}
- | expr0 '[' args rbracket OP_ASGN expr
+ | primary '[' opt_args rbracket OP_ASGN arg
{
- $$ = NEW_OP_ASGN1($1,$5,list_concat(NEW_LIST($6),$3));
+ NODE *args = NEW_LIST($6);
+
+ if ($3) list_concat(args, $3);
+ $$ = NEW_OP_ASGN1($1, $5, args);
}
- | expr0 '.' IDENTIFIER OP_ASGN expr
+ | primary '.' IDENTIFIER OP_ASGN arg
{
$$ = NEW_OP_ASGN2($1, $4, $5);
}
- | expr DOT2 expr
+ | arg DOT2 arg
{
$$ = call_op($1, DOT2, 1, $3);
}
- | expr DOT3 expr
+ | arg DOT3 arg
{
$$ = NEW_DOT3(cond2($1), cond2($3));
}
- | expr '+' expr
+ | arg '+' arg
{
$$ = Qnil;
if ($1 && $3
- && (nd_type($3) == NODE_LIT || nd_type($3) == NODE_STR)
+ && (nd_type($3) == NODE_LIT
+ || nd_type($3) == NODE_STR)
&& nd_type($1) == NODE_CALL && $1->nd_mid == '+') {
if ($1->nd_args->nd_head == Qnil)
Bug("bad operand for `+'");
@@ -648,87 +449,87 @@ expr : variable '=' expr
$$ = call_op($1, '+', 1, $3);
}
}
- | expr '-' expr
+ | arg '-' arg
{
$$ = call_op($1, '-', 1, $3);
}
- | expr '*' expr
+ | arg '*' arg
{
$$ = call_op($1, '*', 1, $3);
}
- | expr '/' expr
+ | arg '/' arg
{
$$ = call_op($1, '/', 1, $3);
}
- | expr '%' expr
+ | arg '%' arg
{
$$ = call_op($1, '%', 1, $3);
}
- | expr POW expr
+ | arg POW arg
{
$$ = call_op($1, POW, 1, $3);
}
- | UPLUS expr
+ | UPLUS arg
{
$$ = call_op($2, UPLUS, 0);
}
- | UMINUS expr
+ | UMINUS arg
{
$$ = call_op($2, UMINUS, 0);
}
- | expr '|' expr
+ | arg '|' arg
{
$$ = call_op($1, '|', 1, $3);
}
- | expr '^' expr
+ | arg '^' arg
{
$$ = call_op($1, '^', 1, $3);
}
- | expr '&' expr
+ | arg '&' arg
{
$$ = call_op($1, '&', 1, $3);
}
- | expr CMP expr
+ | arg CMP arg
{
$$ = call_op($1, CMP, 1, $3);
}
- | expr '>' expr
+ | arg '>' arg
{
$$ = call_op($1, '>', 1, $3);
}
- | expr GEQ expr
+ | arg GEQ arg
{
$$ = call_op($1, GEQ, 1, $3);
}
- | expr '<' expr
+ | arg '<' arg
{
$$ = call_op($1, '<', 1, $3);
}
- | expr LEQ expr
+ | arg LEQ arg
{
$$ = call_op($1, LEQ, 1, $3);
}
- | expr EQ expr
+ | arg EQ arg
{
$$ = call_op($1, EQ, 1, $3);
}
- | expr NEQ expr
+ | arg NEQ arg
{
- $$ = call_op($1, NEQ, 1, $3);
+ $$ = NEW_NOT(call_op($1, EQ, 1, $3));
}
- | expr MATCH expr
+ | arg MATCH arg
{
$$ = NEW_CALL($1, MATCH, NEW_LIST($3));
}
- | expr NMATCH expr
+ | arg NMATCH arg
{
- $$ = NEW_CALL($1, NMATCH, NEW_LIST($3));
+ $$ = NEW_NOT(NEW_CALL($1, MATCH, NEW_LIST($3)));
}
- | '!' expr
+ | '!' arg
{
- $$ = call_op($2, '!', 0);
+ $$ = NEW_NOT(cond($2));
}
- | '~' expr
+ | '~' arg
{
if ($2
&& (nd_type($2) == NODE_STR
@@ -741,27 +542,27 @@ expr : variable '=' expr
$$ = call_op($2, '~', 0);
}
}
- | expr LSHFT expr
+ | arg LSHFT arg
{
$$ = call_op($1, LSHFT, 1, $3);
}
- | expr RSHFT expr
+ | arg RSHFT arg
{
$$ = call_op($1, RSHFT, 1, $3);
}
- | expr COLON2 expr
+ | arg COLON2 arg
{
$$ = call_op($1, COLON2, 1, $3);
}
- | expr ANDOP expr
+ | arg ANDOP arg
{
$$ = NEW_AND(cond($1), cond($3));
}
- | expr OROP expr
+ | arg OROP arg
{
$$ = NEW_OR(cond($1), cond($3));
}
- |expr0
+ | primary
{
$$ = $1;
}
@@ -771,23 +572,37 @@ call_args : /* none */
$$ = Qnil;
}
| call_args0
- | '*' expr
+ | '*' arg
{
$$ = $2;
}
call_args0 : args
- | args comma '*' expr
+ | assocs
+ {
+ $$ = NEW_LIST(NEW_HASH($1));
+ }
+ | args comma assocs
+ {
+ $$ = list_append($1, NEW_HASH($3));
+ }
+ | args comma '*' arg
{
$$ = call_op($1, '+', 1, $4);
}
-args : expr
+opt_args : /* none */
+ {
+ $$ = Qnil;
+ }
+ | args
+
+args : arg
{
value_expr($1);
$$ = NEW_LIST($1);
}
- | args comma expr
+ | args comma arg
{
value_expr($3);
$$ = list_append($1, $3);
@@ -803,7 +618,7 @@ args2 : args
}
}
-expr0 : literal
+primary : literal
{
$$ = NEW_LIT($1);
}
@@ -820,10 +635,6 @@ expr0 : literal
| DREGEXP
| DGLOB
| var_ref
- | IDENTIFIER '(' call_args rparen
- {
- $$ = NEW_CALL(Qnil, $1, $3);
- }
| SUPER '(' call_args rparen
{
if (!cur_mid && !in_single)
@@ -836,13 +647,12 @@ expr0 : literal
Error("super called outside of method");
$$ = NEW_ZSUPER();
}
-
- | expr0 '[' args rbracket
+ | primary '[' opt_args rbracket
{
value_expr($1);
$$ = NEW_CALL($1, AREF, $3);
}
- | LBRACK array rbracket
+ | LBRACK opt_args rbracket
{
if ($2 == Qnil)
$$ = NEW_ZARRAY(); /* zero length array*/
@@ -854,8 +664,33 @@ expr0 : literal
{
$$ = NEW_HASH($2);
}
+ | REDO
+ {
+ $$ = NEW_REDO();
+ }
+ | BREAK
+ {
+ $$ = NEW_BREAK();
+ }
+ | CONTINUE
+ {
+ $$ = NEW_CONT();
+ }
+ | RETRY
+ {
+ $$ = NEW_RETRY();
+ }
+ | RETURN
+ {
+ if (!cur_mid && !in_single)
+ Error("return appeared outside of method");
+ $$ = NEW_RET(Qnil);
+ }
| FAIL '(' args2 ')'
{
+ if (nd_type($3) == NODE_ARRAY) {
+ Error("wrong number of argument to fail(0 or 1)");
+ }
value_expr($3);
$$ = NEW_FAIL($3);
}
@@ -880,7 +715,7 @@ expr0 : literal
{
$$ = NEW_YIELD(Qnil);
}
- | expr0 '{' opt_iter_var '|' compstmts rbrace
+ | primary '{' opt_iter_var '|' compexpr rbrace
{
if (nd_type($1) == NODE_LVAR
|| nd_type($1) == NODE_MVAR) {
@@ -888,52 +723,47 @@ expr0 : literal
}
$$ = NEW_ITER($3, $1, $5);
}
- | expr0 '.' IDENTIFIER '(' call_args rparen
+ | IDENTIFIER '(' call_args rparen
+ {
+ $$ = NEW_CALL(Qnil, $1, $3);
+ }
+ | primary '.' IDENTIFIER '(' call_args rparen
{
value_expr($1);
$$ = NEW_CALL($1, $3, $5);
}
- | expr0 '.' IDENTIFIER
+ | primary '.' IDENTIFIER
{
value_expr($1);
$$ = NEW_CALL($1, $3, Qnil);
}
- | IF stmt0 then
- compstmts
+ | IF expr then
+ compexpr
if_tail
END
{
$$ = NEW_IF(cond($2), $4, $5);
}
- | UNLESS stmt0 then
- compstmts opt_else END
- {
- $$ = NEW_UNLESS(cond($2), $4, $5);
- }
- | WHILE stmt0 term compstmts END
+ | WHILE expr term compexpr END
{
$$ = NEW_WHILE(cond($2), $4);
}
- | UNTIL stmt0 term compstmts END
- {
- $$ = NEW_UNTIL(cond($2), $4);
- }
- | CASE compstmts
+ | CASE compexpr
case_body
END
{
value_expr($2);
$$ = NEW_CASE($2, $3);
}
- | FOR iter_var IN stmt0 term
- compstmts
+ | FOR iter_var IN expr term
+ compexpr
END
{
value_expr($4);
$$ = NEW_FOR($2, $4, $6);
}
| PROTECT
- compstmts
+ compexpr
resque
ensure
END
@@ -946,18 +776,77 @@ expr0 : literal
$$ = NEW_PROT($2, $3, $4);
}
}
- | LPAREN compstmts rparen
+ | LPAREN compexpr rparen
{
$$ = $2;
}
+ | CLASS IDENTIFIER superclass
+ {
+ if (cur_class || cur_mid || in_single)
+ Error("nested class definition");
+ cur_class = $2;
+ push_local();
+ }
+ compexpr
+ END
+ {
+ $$ = NEW_CLASS($2, $5, $3);
+ pop_local();
+ cur_class = Qnil;
+ }
+ | MODULE IDENTIFIER
+ {
+ if (cur_class != Qnil)
+ Error("nested module definition");
+ cur_class = $2;
+ in_module = 1;
+ push_local();
+ }
+ compexpr
+ END
+ {
+ $$ = NEW_MODULE($2, $4);
+ pop_local();
+ cur_class = Qnil;
+ in_module = 0;
+ }
+ | DEF fname
+ {
+ if (cur_mid || in_single)
+ Error("nested method definition");
+ cur_mid = $2;
+ push_local();
+ }
+ f_arglist
+ compexpr
+ END
+ {
+ $$ = NEW_DEFN($2, NEW_RFUNC($4, $5), cur_class?0:1);
+ pop_local();
+ cur_mid = Qnil;
+ }
+ | DEF singleton '.' fname
+ {
+ value_expr($2);
+ in_single++;
+ push_local();
+ }
+ f_arglist
+ compexpr
+ END
+ {
+ $$ = NEW_DEFS($2, $4, NEW_RFUNC($6, $7));
+ pop_local();
+ in_single--;
+ }
then : term
| THEN
| term THEN
if_tail : opt_else
- | ELSIF stmt0 then
- compstmts
+ | ELSIF expr then
+ compexpr
if_tail
{
$$ = NEW_IF(cond($2), $4, $5);
@@ -967,7 +856,7 @@ opt_else : /* none */
{
$$ = Qnil;
}
- | ELSE compstmts
+ | ELSE compexpr
{
$$ = $2;
}
@@ -982,7 +871,7 @@ opt_iter_var : /* none */
| iter_var
case_body : WHEN args then
- compstmts
+ compexpr
cases
{
$$ = NEW_WHEN($2, $4, $5);
@@ -990,7 +879,7 @@ case_body : WHEN args then
cases : opt_else
| WHEN args then
- compstmts
+ compexpr
cases
{
$$ = NEW_WHEN($2, $4, $5);
@@ -1000,7 +889,7 @@ resque : /* none */
{
$$ = Qnil;
}
- | RESQUE compstmts
+ | RESQUE compexpr
{
if ($2 == Qnil)
$$ = (NODE*)1;
@@ -1012,26 +901,19 @@ ensure : /* none */
{
$$ = Qnil;
}
- | ENSURE compstmts
+ | ENSURE compexpr
{
$$ = $2;
}
-array : /* none */
- {
- $$ = Qnil;
- }
- | args
-
literal : numeric
- | '\\' symbol
+ | SYMBEG symbol
{
$$ = INT2FIX($2);
}
| REGEXP
| GLOB
-
symbol : fname
| IVAR
| GVAR
@@ -1058,11 +940,121 @@ var_ref : variable
$$ = gettable($1);
}
+superclass : term
+ {
+ $$ = Qnil;
+ }
+ | colon
+ {
+ lex_state = EXPR_BEG;
+ }
+ IDENTIFIER
+ {
+ $$ = $3;
+ }
+
+f_arglist : '(' f_args rparen
+ {
+ $$ = $2;
+ }
+ | term
+ {
+ $$ = NEW_ARGS(0, -1);
+ }
+
+f_args : /* no arg */
+ {
+ $$ = NEW_ARGS(0, -1);
+ }
+ | f_arg
+ {
+ $$ = NEW_ARGS($1, -1);
+ }
+ | f_arg comma rest_arg
+ {
+ $$ = NEW_ARGS($1, $3);
+ }
+ | rest_arg
+ {
+ $$ = NEW_ARGS(Qnil, $1);
+ }
+ | f_arg error
+ {
+ lex_state = EXPR_BEG;
+ $$ = NEW_ARGS($1, -1);
+ }
+ | error
+ {
+ lex_state = EXPR_BEG;
+ $$ = NEW_ARGS(0, -1);
+ }
+
+f_arg : IDENTIFIER
+ {
+ if (!is_local_id($1))
+ Error("formal argument must be local variable");
+ local_cnt($1);
+ $$ = 1;
+ }
+ | f_arg comma IDENTIFIER
+ {
+ if (!is_local_id($3))
+ Error("formal argument must be local variable");
+ local_cnt($3);
+ $$ += 1;
+ }
+
+rest_arg : '*' IDENTIFIER
+ {
+ if (!is_local_id($2))
+ Error("rest argument must be local variable");
+ $$ = local_cnt($2);
+ }
+
+singleton : var_ref
+ {
+ if (nd_type($1) == NODE_SELF) {
+ $$ = NEW_SELF();
+ }
+ else if (nd_type($1) == NODE_NIL) {
+ Error("Can't define single method for nil.");
+ $$ = Qnil;
+ }
+ else {
+ $$ = $1;
+ }
+ }
+ | LPAREN compexpr rparen
+ {
+ switch (nd_type($2)) {
+ case NODE_STR:
+ case NODE_STR2:
+ case NODE_XSTR:
+ case NODE_XSTR2:
+ case NODE_DREGX:
+ case NODE_DGLOB:
+ case NODE_LIT:
+ case NODE_ARRAY:
+ case NODE_ZARRAY:
+ Error("Can't define single method for literals.");
+ default:
+ break;
+ }
+ $$ = $2;
+ }
+
assoc_list : /* none */
{
$$ = Qnil;
}
| assocs
+ | args
+ {
+ if ($1->nd_alen%2 != 0) {
+ Error("odd number list for Dict");
+ }
+ $$ = $1;
+ }
assocs : assoc
| assocs comma assoc
@@ -1070,12 +1062,11 @@ assocs : assoc
$$ = list_concat($1, $3);
}
-assoc : expr ASSOC expr
+assoc : arg ASSOC arg
{
$$ = list_append(NEW_LIST($1), $3);
}
-
opt_term : /* none */
| term
@@ -1085,6 +1076,9 @@ term : sc
sc : ';' { yyerrok; }
nl : '\n' { yyerrok; }
+colon : ':'
+ | SYMBEG
+
rparen : ')' { yyerrok; }
rbracket : ']' { yyerrok; }
rbrace : '}' { yyerrok; }
@@ -1196,10 +1190,6 @@ parse_regx()
else if (in_brack && c == 'b') {
tokadd('\b');
}
- else if (isdigit(c)) {
- tokadd('\\');
- tokadd(c);
- }
else {
pushback();
read_escape(LEAVE_BS);
@@ -1348,8 +1338,6 @@ static struct kwtable {
"super", SUPER, EXPR_END,
"then", THEN, EXPR_BEG,
"undef", UNDEF, EXPR_FNAME,
- "unless", UNLESS, EXPR_BEG,
- "until", UNTIL, EXPR_BEG,
"when", WHEN, EXPR_BEG,
"while", WHILE, EXPR_BEG,
"yield", YIELD, EXPR_END,
@@ -1406,13 +1394,6 @@ retry:
return '*';
case '!':
- if (lex_state == EXPR_FNAME) {
- if ((c = nextc()) == '@') {
- lex_state = EXPR_BEG;
- return '!';
- }
- pushback();
- }
lex_state = EXPR_BEG;
if ((c = nextc()) == '=') {
return NEQ;
@@ -1737,12 +1718,15 @@ retry:
return c;
case ':':
- lex_state = EXPR_BEG;
- if (nextc() == ':') {
+ c = nextc();
+ if (c == ':') {
+ lex_state = EXPR_BEG;
return COLON2;
}
pushback();
- return ':';
+ if (isspace(c))
+ return ':';
+ return SYMBEG;
case '/':
if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
@@ -1786,7 +1770,6 @@ retry:
return c;
case '[':
-
if (lex_state == EXPR_BEG || lex_state == EXPR_MID)
c = LBRACK;
else if (lex_state == EXPR_FNAME) {
@@ -1811,8 +1794,10 @@ retry:
case '\\':
c = nextc();
- if (c == '\n') goto retry; /* skip \\n */
- lex_state = EXPR_FNAME;
+ if (c == '\n') {
+ sourceline++;
+ goto retry; /* skip \\n */
+ }
pushback();
return '\\';
@@ -1910,9 +1895,7 @@ retry:
lex_state = mid->state;
if (state != EXPR_BEG) {
if (mid->id == IF) return IF_MOD;
- if (mid->id == UNLESS) return UNLESS_MOD;
if (mid->id == WHILE) return WHILE_MOD;
- if (mid->id == UNTIL) return UNTIL_MOD;
}
return mid->id;
}
@@ -2444,6 +2427,7 @@ aryset(recv, idx, val)
NODE *recv, *idx, *val;
{
value_expr(recv);
+ value_expr(val);
return NEW_CALL(recv, ASET, list_append(idx, val));
}
@@ -2453,18 +2437,19 @@ attrset(recv, id, val)
ID id;
{
value_expr(recv);
+ value_expr(val);
id &= ~ID_SCOPE_MASK;
id |= ID_ATTRSET;
- return NEW_CALL(recv, id, NEW_ARRAY(val));
+ return NEW_CALL(recv, id, NEW_LIST(val));
}
-static void
+static int
value_expr(node)
NODE *node;
{
- if (node == Qnil) return;
+ if (node == Qnil) return TRUE;
switch (nd_type(node)) {
case NODE_RETURN:
@@ -2472,25 +2457,29 @@ value_expr(node)
case NODE_BREAK:
case NODE_REDO:
case NODE_RETRY:
+ case NODE_FAIL:
case NODE_WHILE:
case NODE_WHILE2:
case NODE_INC:
case NODE_CLASS:
case NODE_MODULE:
+ case NODE_DEFN:
+ case NODE_DEFS:
Error("void value expression");
+ return FALSE;
break;
case NODE_BLOCK:
while (node->nd_next) {
node = node->nd_next;
}
- if (node) {
- value_expr(node->nd_head);
- }
- break;
+ return value_expr(node->nd_head);
+
+ case NODE_IF:
+ return value_expr(node->nd_body) && value_expr(node->nd_else);
default:
- break;
+ return TRUE;
}
}
@@ -2635,8 +2624,8 @@ init_top_local()
lvtbl->cnt = 0;
}
if (lvtbl->cnt > 0) {
- lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt);
- MEMCPY(lvtbl->tbl, the_scope->local_tbl, VALUE, lvtbl->cnt);
+ lvtbl->tbl = ALLOC_N(ID, lvtbl->cnt+1);
+ MEMCPY(lvtbl->tbl, the_scope->local_tbl, ID, lvtbl->cnt);
}
else {
lvtbl->tbl = Qnil;
@@ -2892,7 +2881,7 @@ rb_class2name(class)
Fail("0x%x is not a class/module", class);
}
- if (FL_TEST(class, FL_SINGLE)) {
+ while (FL_TEST(class, FL_SINGLE)) {
class = (struct RClass*)class->super;
}
@@ -2906,3 +2895,23 @@ rb_class2name(class)
}
Bug("class 0x%x not named", class);
}
+
+static int
+const_check(id, val, class)
+ ID id;
+ VALUE val;
+ struct RClass *class;
+{
+ if (is_const_id(id) && rb_const_bound(class, id)) {
+ Warning("constant redefined for %s", rb_class2name(class));
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+void
+rb_const_check(class, module)
+ struct RClass *class, *module;
+{
+ st_foreach(module->iv_tbl, const_check, class);
+}