Chapter 17: Dynamic Appraisal

Blue Chapter -- Machine Translation

summary

That instrument rating system itself is already complete at the previous chapter. It is this chapter Until all the parser to a "broad sense evaluator" verify them as a whole. Are eligible to eval Module # module_eval Object # instance_eval Oh, three Be.

eval

eval already talked about, this is a story from a fine to me.

eval to use and run-time string on the spot to compile and evaluate it. The return value is the value of the program at the end of the ceremony.

 
p eval ( "1 + 1") # 2 

eval string of variables from the scope of reference.

 
lvar = 5 
@ ivar = 6 
p eval ( "lvar + @ ivar") # 11 

So far readers have read "The scope of the phrase" too easy to read tantivy No longer do. For example, the constant "scope" What's going on with you, and I do not have to worry about? I do worry about it. Conclusions from it and basically To eval outside of the environment take over as his word.

The method can define a class definition.

 
def a 
   eval ( 'class C; def test () puts ( "ok") end end') 
end 

a () # class C and C # test to define 
C.new.test # ok and displayed 

In addition, some mentioned in the previous chapter, the second argument Proc to pass in the current system and its environment,

 
def new_env 
   n = 5 
   This method Proc.new (nil) # environment and returned to the object 
end 

p eval ( 'n * 3', new_env ()) # 15 

module_eval and instance_eval

Proc and eval and the second argument to pass the environmental evaluation. module_eval and instance_eval is the Limited Edition (or shortcuts). module_eval modules, and classes sentence statement as if the internal environment Evaluated.

 
lvar = "toplevel lvar" # determine the scope for local variables 

module M 
end 
M.module_eval (<< 'EOS') # this is when heredoc 
     p lvar # reference 
     p self # M and displayed 
     def ok # M # ok to define 
       puts' ok ' 
     end 
EOS 

instance_eval statement of the specific class self object to the environment Evaluated.

 
lvar = "toplevel lvar" # determine the scope for local variables 

obj = Object.new 
obj.instance_eval (<< 'EOS') 
     p lvar # reference 
     p self # #  and displayed 
     to define def ok # obj.ok 
       puts' ok ' 
     end 
EOS 

The module_eval and instance_eval is also used as iterators Worked in this case each block is evaluated by the environment. For example

 
obj = Object.new 
p obj # #  
obj.instance_eval ( 
     p self # #  
) 

And so on.

But if you use a string and is used to block Local variables are different from the behavior around. For example, the method a to block the creation Methods b , instance_eval , the block is a of local variables About. Methods a method to create a string b , instance_eval , During the string of b about local variables. Local variables The scope is just a "compilation" determined, so every time compiling String and when loading files compiled by block, the result is out A different reason.

eval

eval ()

Ruby's eval None of the arguments in many cases separated, the format calls

 
eval (prog_string, some_block) 

And limited. The actual interface functions rb_f_eval () is virtually meaningless Lose because the other functions under the eval () to look at it now. eval () prototype is a function of

 
static VALUE 
eval (VALUE self, VALUE src, VALUE scope, char * file, int line); 

And, scope is the second argument Proc . file and line is eval strings Assume that put the name of the file number of lines. Offers a look at the contents.

eval () (condensed version)

 
4984 static VALUE 
4985 eval (self, src, scope, file, line) 
4986 VALUE self, src, scope; 
4987 char * file; 
4988 int line; 
(4989 
4990 struct BLOCK * data = NULL; 
4991 volatile VALUE result = Qnil; 
4992 struct SCOPE * volatile old_scope; 
4993 struct BLOCK * volatile old_block; 
4994 struct RVarmap * volatile old_dyna_vars; 
4995 VALUE volatile old_cref; 
4996 int volatile old_vmode; 
4997 volatile VALUE old_wrapper; 
4998 struct FRAME frame; 
4999 NODE * nodesave = ruby_current_node; 
5000 volatile int iter = ruby_frame-> iter; 
5001 int state; 
5002 
5003 if (! NIL_P (scope)) (/ * * I will always be true / 
5009 Data_Get_Struct (scope, struct BLOCK, data); 
5010 / * data from a ship BLOCK * / 
5011 frame = data-> frame; 
5012 frame.tmp = ruby_frame; / * GC awnings * / 
5013 ruby_frame = & (frame); 
5014 old_scope = ruby_scope; 
5015 ruby_scope = data-> scope; 
5016 old_block = ruby_block; 
5017 ruby_block = data-> prev; 
5018 old_dyna_vars = ruby_dyna_vars; 
5019 ruby_dyna_vars = data-> dyna_vars; 
5020 old_vmode = scope_vmode; 
5021 scope_vmode = data-> vmode; 
5022 old_cref = (VALUE) ruby_cref; 
5023 ruby_cref = (NODE *) ruby_frame-> cbase; 
5024 old_wrapper = ruby_wrapper; 
5025 ruby_wrapper = data-> wrapper; 
5032 self = data-> self; 
5033 ruby_frame-> iter = data-> iter; 
5034) 
5045 PUSH_CLASS (); 
5046 ruby_class = ruby_cbase; / * == ruby_frame-> cbase * / 
5047 
5048 ruby_in_eval + +; 
5049 if (TYPE (ruby_class) == T_ICLASS) ( 
5050 ruby_class = RBASIC (ruby_class) -> klass; 
5051) 
5052 PUSH_TAG (PROT_NONE); 
5053 if ((state = EXEC_TAG ()) == 0) ( 
5054 NODE * node; 
5055 
5056 result = ruby_errinfo; 
5057 ruby_errinfo = Qnil; 
5058 node = compile (src, file, line); 
5059 if (ruby_nerrs> 0) ( 
5060 compile_error (0); 
5061) 
5062 if (! NIL_P (result)) ruby_errinfo = result; 
5063 result = eval_node (self, node); 
5064) 
5065 POP_TAG (); 
5066 POP_CLASS (); 
5067 ruby_in_eval -; 
5068 if (! NIL_P (scope)) (/ * * I will always be true / 
5069 int dont_recycle = ruby_scope-> flags & SCOPE_DONT_RECYCLE; 
5070 
5071 ruby_wrapper = old_wrapper; 
5072 ruby_cref = (NODE *) old_cref; 
5073 ruby_frame = frame.tmp; 
5074 ruby_scope = old_scope; 
5075 ruby_block = old_block; 
5076 ruby_dyna_vars = old_dyna_vars; 
5077 data-> vmode = scope_vmode; / * Save changes to the scope of visibility * / 
5078 scope_vmode = old_vmode; 
5079 if (dont_recycle) ( 
                   / *…… SCOPE BLOCK VARS to copy…… * / 
5097) 
5098) 
5104 if (state) ( 
5105 if (state == TAG_RAISE) ( 
                   / *…… Exception object to prepare…… * / 
5121 rb_exc_raise (ruby_errinfo); 
5122) 
5123 JUMP_TAG (state); 
5124) 
5125 
5126 return result; 
5127) 

(eval.c) 

Preliminaries no wish to see this function to suddenly "ぐぁっ" It's going to be, So far eval.c function has been to defeat our enemy is not anymore. This function will do nothing but return to the stack of saving it. I should note The following is only three points.

And the main part of the middle compile () and eval_node () . eval_node () I have not been forgotten, but the argument node to start evaluating the relationship Numbers. ruby_run () But to have been used.

compile () are these.

compile ()

 
4968 static NODE * 
4969 compile (src, file, line) 
4970 VALUE src; 
4971 char * file; 
4972 int line; 
(4973 
4974 NODE * node; 
4975 
4976 ruby_nerrs = 0; 
4977 Check_Type (src, T_STRING); 
4978 node = rb_compile_string (file, src, line); 
4979 
4980 if (ruby_nerrs == 0) return node; 
4981 return 0; 
4982) 

(eval.c) 

ruby_nerrs is yyerror () increment in the variable. In other words, this variable is non-zero error that happens in Perth. Also rb_compile_string () is already in the second part of the deal. Ruby string syntax tree The function was compiled.

One problem here is because the local variable. Chapter 12, for use in the construction, I saw the street, local variables are lvtbl managed by using the. Only This is already the SCOPE (and, perhaps VARS ) is in existence because, And add the override must be in Perth. This is a matter of fact eval () of The core of the worst hard place. Again parse.y to return to this search Complete up to it.

top_local

Variable local management table struct local_vars is used to gain local_push () local_pop () . Function was, in fact parse.y the table to gain administrative function is no longer a pair. top_local_init () and top_local_setup () . It was like this is called .

top_local_init () style known as the

 
program: (top_local_init ();) 
           compstmt 
             (Top_local_setup ();) 

Of course, is actually doing a lot more to it, but now it all does not matter Ministry cuts. And the contents are these.

top_local_init ()

 
5273 static void 
5274 top_local_init () 
(5275 
5276 local_push (1); 
5277 lvtbl-> cnt = ruby_scope-> local_tbl? Ruby_scope-> local_tbl [0]: 0; 
5278 if (lvtbl-> cnt> 0) ( 
5279 lvtbl-> tbl = ALLOC_N (ID, lvtbl-> cnt +3); 
5280 MEMCPY (lvtbl-> tbl, ruby_scope-> local_tbl, ID, lvtbl-> cnt +1); 
5281) 
5282 else ( 
5283 lvtbl-> tbl = 0; 
5284) 
5285 if (ruby_dyna_vars) 
5286 lvtbl-> dlev = 1; 
5287 else 
5288 lvtbl-> dlev = 0; 
5289) 

(parse.y) 

In other words ruby_scope and lvtbl in local_tbl to keep a copy. After block local variables are seen together better, Just concentrate on ordinary local variables. Then top_local_setup () .

top_local_setup ()

 
5291 static void 
5292 top_local_setup () 
(5293 
5294 int len = lvtbl-> cnt; / * Perth after a number of local variables * / 
5295 int i; / * Perth previous local variables * / 
5296 
5297 if (len> 0) ( 
5298 i = ruby_scope-> local_tbl? Ruby_scope-> local_tbl [0]: 0; 
5299 
5300 if (i  flags & SCOPE_MALLOC) == 0) ( 
5302 VALUE * vars = ALLOC_N (VALUE, len +1); 
5303 if (ruby_scope-> local_vars) ( 
5304 * vars + + = ruby_scope-> local_vars [-1]; 
5305 MEMCPY (vars, ruby_scope-> local_vars, VALUE, i); 
5306 rb_mem_clear (vars + i, len-i); 
5307) 
5308 else ( 
5309 * vars + + = 0; 
5310 rb_mem_clear (vars, len); 
5311) 
5312 ruby_scope-> local_vars = vars; 
5313 ruby_scope-> flags | = SCOPE_MALLOC; 
5314) 
5315 else ( 
5316 VALUE * vars = ruby_scope-> local_vars-1; 
5317 REALLOC_N (vars, VALUE, len +1); 
5318 ruby_scope-> local_vars = vars +1; 
5319 rb_mem_clear (ruby_scope-> local_vars + i, len-i); 
5320) 
5321 if (ruby_scope-> local_tbl & & 
                       ruby_scope-> local_vars [-1] == 0) ( 
5322 free (ruby_scope-> local_tbl); 
5323) 
5324 ruby_scope-> local_vars [-1] = 0; / * NODE is I do not want * / 
5325 ruby_scope-> local_tbl = local_tbl (); 
5326) 
5327) 
5328 local_pop (); 
5329) 

(parse.y) 

local_vars , or the stack or the heap, so there is somewhat more complicated That is, ruby_scope - local_tbl and local_vars to update that. Of the guard ( SCOPE_MALLOC was standing in the local_vars is malloc () allocation). Also here alloca () also means using force in the absence of malloc () allocations The only change.

block local variables

By the way, block the local variables, but what happens? It will first consider the entry point parser yycompile () to Must return to.

ruby_dyna_vars saving

 
static NODE * 
yycompile (f, line) 
( 
     struct RVarmap * vars = ruby_dyna_vars; 
          : 
     n = yyparse (); 
          : 
     ruby_dyna_vars = vars; 
) 

Return as a mere diversion, but we can see, ruby_dyna_vars to clear the Yes There is no point. That is made evaluator RVarmap link to a parser Directly adds to it.

But ruby_dyna_vars parser and the rating should be a different structure. Always links 問題なsingle-track approach is likely to be in the header ( id = 0 - RVarmap ) with the difference between the way What now?

So it is useful top_local_init () was local_push (1) "1" Oh Be. local_push () and the argument is true ruby_dyna_vars first with a header Guard down. In other words, as shown in Figure 1. The eval string Scoping out the reference to block local variables can be confirmed.

(dynavars)
Figure 1: eval in ruby_dyna_vars

No, I can certainly refer KEDOMO ruby_dyna_vars is parser so they are all freed Then you should have no hoops or evaluator made links to free and when you do now…… It is aware of the following people are relieved to read it for me.

yycompile () - ruby_dyna_vars release

 
2386 vp = ruby_dyna_vars; 
2387 ruby_dyna_vars = vars; 
2388 lex_strterm = 0; 
2389 while (vp & & vp! = Vars) ( 
2390 struct RVarmap * tmp = vp; 
2391 vp = vp-> next; 
2392 rb_gc_force_recycle ((VALUE) tmp); 
2393) 

(parse.y) 

Evaluator made link ( vars ) to come right loop To stop it.

instance_eval

overall picture

Module # module_eval entities are rb_mod_module_eval () , Object # instance_eval entities are rb_obj_instance_eval () .

rb_mod_module_eval () rb_obj_instance_eval ()

 
5316 VALUE 
5317 rb_mod_module_eval (argc, argv, mod) 
5318 int argc; 
5319 VALUE * argv; 
5320 VALUE mod; 
(5321 
5322 return specific_eval (argc, argv, mod, mod); 
5323) 

5298 VALUE 
5299 rb_obj_instance_eval (argc, argv, self) 
5300 int argc; 
5301 VALUE * argv; 
5302 VALUE self; 
(5303 
5304 VALUE klass; 
5305 
5306 if (rb_special_const_p (self)) ( 
5307 klass = Qnil; 
5308) 
5309 else ( 
5310 klass = rb_singleton_class (self); 
5311) 
5312 
5313 return specific_eval (argc, argv, klass, self); 
5314) 

(eval.c) 

These two methods are " self and class to replace the method," as in common Since it is out specific_eval () has been organized. This target also includes Because it illustrated to try (see Figure 2). Bracketed by calling the function pointer.

(speceval)
Figure 2: Call graph

instance_eval to have module_eval to have both a block and a string of them Because a unique process to make eval and yield split up. But the Most part it is also common, it is exec_under () out as a tie Have not.

But read from the standpoint of a 2 \ times 2 = 4 at the same time deal with street Particularly, and it does, it is inadvisable. So here is

  1. instance_eval in,
  2. when you take a string argument

Only consider rb_obj_instance_eval () All these functions inline deployment, Constant folding to read it to him.

annexed after

MATOMETARA all this happened. Compared with the previous annexation has been pretty clear.

specific_eval () - instance_eval , eval , string

 
static VALUE 
instance_eval_string (self, src, file, line) 
     VALUE self, src; 
     const char * file; 
     int line; 
( 
     VALUE sclass; 
     VALUE result; 
     int state; 
     int mode; 

     sclass = rb_singleton_class (self); 

     PUSH_CLASS (); 
     ruby_class = sclass; 
     PUSH_FRAME (); 
     ruby_frame-> self = ruby_frame-> prev-> self; 
     ruby_frame-> last_func = ruby_frame-> prev-> last_func; 
     ruby_frame-> last_class = ruby_frame-> prev-> last_class; 
     ruby_frame-> argc = ruby_frame-> prev-> argc; 
     ruby_frame-> argv = ruby_frame-> prev-> argv; 
     if (ruby_frame-> cbase! = sclass) ( 
         ruby_frame-> cbase = rb_node_newnode (NODE_CREF, sclass, 0, 
                                             ruby_frame-> cbase); 
     ) 
     PUSH_CREF (sclass); 

     mode = scope_vmode; 
     SCOPE_SET (SCOPE_PUBLIC); 
     PUSH_TAG (PROT_NONE); 
     if ((state = EXEC_TAG ()) == 0) ( 
         result = eval (self, src, Qnil, file, line); 
     ) 
     POP_TAG (); 
     SCOPE_SET (mode); 

     POP_CREF (); 
     POP_FRAME (); 
     POP_CLASS (); 
     if (state) JUMP_TAG (state); 

     return result; 
) 

Object-specific classes CLASS and CREF and ruby_frame-> cbase to Push. Story goes. The main processing eval () the first attempt. Usual Different FRAME a copy of the initial structure of them is not uncommon, That's not much difference.

annexation ago

I have become easy to read even though they may say, perhaps before the annexation easyだっ The following might be. Compared to the previous annexation and easily Where is that? To try to verify.

First specific_eval () . This function is part of the interface and Ruby To a common code for one, most of the arguments of Perth. It all, he cut back.

specific_eval () (condensed version)

 
5258 static VALUE 
5259 specific_eval (argc, argv, klass, self) 
5260 int argc; 
5261 VALUE * argv; 
5262 VALUE klass, self; 
(5263 
5264 if (rb_block_given_p ()) ( 

5268 return yield_under (klass, self); 
5269) 
5270 else ( 

5294 return eval_under (klass, self, argv [0], file, line); 
5295) 
5296) 

(eval.c) 

This street block and whether there are two completely separate, Each code is the root of the influence they can not. So Read one at a time when you should read. The first edition annexed to this point has been improved.

Also yield_under () When you read file and line relationship is not yield route to the annexation of the party's argument about Perth I can not think about going to be clear.

Then eval_under () and eval_under_i () to look at.

eval_under ()

 
5222 static VALUE 
5223 eval_under (under, self, src, file, line) 
5224 VALUE under, self, src; 
5225 const char * file; 
5226 int line; 
(5230 
5228 VALUE args [4]; 
5229 
5230 if (ruby_safe_level> = 4) ( 
5231 StringValue (src); 
5232) 
5233 else ( 
5234 SafeStringValue (src); 
5235) 
5236 args [0] = self; 
5237 args [1] = src; 
5238 args [2] = (VALUE) file; 
5239 args [3] = (VALUE) line; 
5240 return exec_under (eval_under_i, under, under, args); 
5241) 

5214 static VALUE 
5215 eval_under_i (args) 
5216 VALUE * args; 
(5217 
5218 return eval (args [0], args [1], Qnil, (char *) args [2], (int) args [3]); 
5219) 

(eval.c) 

This function is one of the arguments for an array args via the pass. This args is eval_under () and eval_under_i () to pass a temporary I wonder containers, Is it possible to predict, but I really do not know. Maybe exec_under () in args and the process might be.

As a way of a common code that it is very correct way, but Read from the side of the pass to get into this kind of indirect and hard-to-understand. In particular file and line sesame seeds morph into a compiler for the cast is wasted in the Really, so what type is hard to imagine. This area is annexed to its all disappeared Because they do not have to choose.

But the annexation or expand and it is always easy to understand is that it is a . For example exec_under () to call when the second and third arguments are arguments under passing However, exec_under () side of the parameters of both the variable under to expand the I want to? Say, exec_under () in the second and third argument is actually a push to be CLASS and CREF shows The. CLASS and CREF "otherness", to use another variable, but it I might. This version of the annexation is only

 
VALUE sclass = .....; 
VALUE cbase = sclass; 

And I thought, but it suddenly left so many variables and there is something wrong with I thought, sclass 've been deployed. That is the top sentence flow only.

As many times arguments to expand and expand and function has been, but every time Doggedly explain the reason for deployment. That is

. "I get a lot of things can easily be deployed." I can not tell, never.

It is always preferred for their ease of understanding, not a step It is not to protect. Expand it, it is easy to understand and deployment. Do not expand, or vice versa summary of the proceedings it is easy to understand if you feel I agree. ruby If the source is not good writing because it was just a deployment , Who wrote a bad source to function if it is clear it away tie Often it.


The original work is Copyright © 2002 - 2004 Minero AOKI.
Translations,  additions,  and graphics by C.E. Thornton
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike2.5 License.