Class: RuntimeMethod
- Inherits:
-
StatementGroup
- Object
- Array
- StatementGroup
- RuntimeMethod
- Includes:
- ActsAsRuntimeMethod, ActsAsTrackable
- Defined in:
- lib/core/runtime_method/RuntimeMethod.rb
Overview
since you can’t write methods within methods.
Direct Known Subclasses
Constant Summary collapse
- @@METHOD_ID =
0
Instance Attribute Summary collapse
-
#method_id ⇒ Object
Returns the value of attribute method_id.
-
#method_return ⇒ Object
readonly
Returns the value of attribute method_return.
-
#usage ⇒ Object
readonly
Returns the value of attribute usage.
Attributes inherited from StatementGroup
#scope, #scope_id, #statement_level
Class Method Summary collapse
Instance Method Summary collapse
-
#add_return_variable_statement!(id) ⇒ Object
Adds a new statement to the method that returns a variable with the specified id.
-
#add_statement_at(statement, position) ⇒ Object
Inserts a statement at a particular position within the runtime method.
-
#all_pass?(test_cases) ⇒ Boolean
Returns true if all the test cases when run through this runtime method return the correct value.
-
#available_variable_at(params, line = 0) ⇒ Object
Returns an array of variables that are available at a particular line in the method.
- #build_solution(found_variables, statement, rule) ⇒ Object
-
#callable_combinations(available = []) ⇒ Object
Returns an array of def calls given the code elements made available.
- #cauldron_method_calls ⇒ Object
-
#copy ⇒ Object
Creates a copy of the method with the same usage and statements but a different id.
-
#copy_base ⇒ Object
Returns a duplicate method but without any statements in it.
-
#declaration_statement ⇒ Object
Returns a statement that declares the runtime method instance.
-
#describe ⇒ Object
Returns a describtion of the method and the variables within it.
-
#find_next_unknown(complete_statements, concept) ⇒ Object
NOTE: This doesn’t handle the case when there are two unknowns - dependent on each other.
-
#find_variable_in_parameters(id) ⇒ Object
Searches the paramaters for a variable with the specified id.
-
#history(params, additional_methods = []) ⇒ Object
Returns a history object reflecting how the runtime method is processed.
-
#history2(params, additional_methods = []) ⇒ Object
Proxy for the history method except it expects to receive an array of literals.
-
#identify_overriding_statements(params) ⇒ Object
Searches through each statement and identifies whether they override an existing variable or not.
-
#initialize(usage, method_id = nil, *statements) ⇒ RuntimeMethod
constructor
TODO I’m still not sure how to handle the method usage - a runtime method by default doesn’t have literal values since it depends what it is like in each case.
-
#literal_value_of_var(id, params) ⇒ Object
Evaluates the method but includes a return statement for the variable thats id is specified.
-
#params ⇒ Object
TODO This is temporary.
-
#partial_method(line) ⇒ Object
Returns a dupicate method but only with the statements up to the line given.
- #pass?(test_case) ⇒ Boolean
- #push(statement) ⇒ Object
-
#realise2(params, additional_methods = []) ⇒ Object
Rebuilds the method with TypeVariables that all have literal values.
-
#replace_statement_element_with_method_calls(statements, variable, available = []) ⇒ Object
Returns an array of statements with a number of method calls added to it that are equivalent to the variable specified.
- #reset_ids! ⇒ Object
-
#statement_count ⇒ Object
Returns the total number of statements within the method.
-
#to_declaration ⇒ Object
Returns a declaration instance for this particular runtime method.
- #to_intrinsic ⇒ Object
-
#to_var(id = nil, uniq_id = nil) ⇒ Object
Returns the runtime methods as a RuntimeMethodParameter.
-
#trackify(params, tracking_method) ⇒ Object
Returns an updated method that includes a method call after each statement to monitor the usage of a runtime method.
-
#usage_statements(available = []) ⇒ Object
Returns an array of possible statements that contain a call to this runtime method.
- #variables ⇒ Object
Methods included from ActsAsRuntimeMethod
#available_variables, #basic_write, #find_statement_that_created_variable, #find_statement_that_declares_variable, #find_variable, #method_name, #write, #write_with_uniq_id
Methods included from WriteParameters
#describe_params, #write_params
Methods included from ActsAsTrackable
#abstract_variables_for_tracking, #tracking_statement
Methods inherited from StatementGroup
#array_push, #find_all_required_runtime_methods, #find_container_at_level, #find_overriding_statements, #find_statement, #remove_simple, #statement_id, #write
Methods inherited from Array
#contains?, #select_all, #to_literal, #write
Constructor Details
#initialize(usage, method_id = nil, *statements) ⇒ RuntimeMethod
TODO I’m still not sure how to handle the method usage - a runtime method by default
doesn't have literal values since it depends what it is like in each case.
def initialize(usage,method_return=nil,*statements)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 29 def initialize(usage,method_id=nil,*statements) super(*statements) # Set the method id for the generated method if method_id.nil? @@METHOD_ID += 1 method_id = @@METHOD_ID end @method_id = method_id # Save how the method should be used @usage = usage @scope_variables = [] if method_return.nil? then method_return = NilVariable.new end @method_return = method_return # Set the statement level for runtime method (always - because it is the lowest depth) @statement_level = 0 end |
Instance Attribute Details
#method_id ⇒ Object
Returns the value of attribute method_id.
12 13 14 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 12 def method_id @method_id end |
#method_return ⇒ Object (readonly)
Returns the value of attribute method_return.
12 13 14 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 12 def method_return @method_return end |
#usage ⇒ Object
Returns the value of attribute usage.
12 13 14 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 12 def usage @usage end |
Class Method Details
.reset_global_id ⇒ Object
52 53 54 55 56 57 58 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 52 def self.reset_global_id #http://www.zenspider.com/Languages/Ruby/QuickRef.html unless $".include?('test/unit.rb') StandardLogger.log 'WARNING: Resetting variable id, this should only be done for tests' end @@METHOD_ID = 0 end |
Instance Method Details
#add_return_variable_statement!(id) ⇒ Object
Adds a new statement to the method that returns a variable with the specified id.
381 382 383 384 385 386 387 388 389 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 381 def add_return_variable_statement!(id) # Find the requested variable var = contextual_variable(id) # Create the return statement and add it self.push(Statement.new(Return.new,var)) end |
#add_statement_at(statement, position) ⇒ Object
Inserts a statement at a particular position within the runtime method. This could be at the root of the runtime method or within one of its statement groups.
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 175 def add_statement_at(statement,position) if position == self.statement_id push(statement) return end statement_groups = self.select_all {|x| x.kind_of?(StatementGroup) && x.statement_id == position} unless statement_groups.empty? statement_groups.first.push(statement) return end raise StandardError.new('The is no statement group with the id '+position.to_s) end |
#all_pass?(test_cases) ⇒ Boolean
Returns true if all the test cases when run through this runtime method return the correct value.
191 192 193 194 195 196 197 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 191 def all_pass?(test_cases) test_cases.each do |x| result = MethodEvaluation.new.evaluate_method(self.copy,x[:params].collect {|y| y.to_literal}) return false unless result == x[:output] end return true end |
#available_variable_at(params, line = 0) ⇒ Object
Returns an array of variables that are available at a particular line in the method.
TODO This needs tests written for it especially for nested statements
127 128 129 130 131 132 133 134 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 127 def available_variable_at(params,line=0) reduced_copy = copy.clear self.each_with_index do |x,i| break if i > line reduced_copy.push x.copy end return reduced_copy.available_variables(params) end |
#build_solution(found_variables, statement, rule) ⇒ Object
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 241 def build_solution(found_variables,statement,rule) # Create the return statement return_statement = Statement.new return_statement.push Return.new #new_statement = statement.copy # Check the statement follows a "x = y" structure unless statement.assignment? then raise StandardError.new('Statement needs to inlcude an "="') end # Check whether any of the variables are unknown statement.each_unknown do |unknown| # Check if any of the unknown variables have been found #unless found_variables[unknown.variable_id.to_s].nil? if found_variables.has_key?(unknown.variable_id.to_s) # Select the first possible variable id match_variable_id = found_variables[unknown.variable_id.to_s].first # Get the right hand side of the statement rhs = statement.right_hand_side unless rhs.length == 1 then raise StandardError.new('Only expecting one right hand side element') end case rhs.first.class.to_s when 'InstanceCallContainer' # Does the subject of the call match? if found_variables.has_key? rhs.first.subject.variable_id.to_s # Replace unknown variable with the known one variables(rule) do |v| if v.variable_id == found_variables[rhs.first.subject.variable_id.to_s].first return_statement.push InstanceCallContainer.new(v.copy,rhs.first.method_call) return return_statement end end end when 'Unknown' # Look through the variables if found_variables.has_key? rhs.first.variable_id.to_s variables(rule) do |v| if v.variable_id == found_variables[rhs.first.variable_id.to_s].first return_statement.push v.copy return return_statement end end end else raise StandardError.new('Unexpected class '+rhs.first.class.to_s) end end end raise StandardError.new('Unable to find variable with matching id') end |
#callable_combinations(available = []) ⇒ Object
Returns an array of def calls given the code elements made available.
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 498 def callable_combinations(available=[]) # Handle the case where the method doesn't require any parameters if @usage.empty? return [DefCall.new(@method_return.copy,self.copy)] end # NOTE This assumes that all the paramaters must be populated # Go thorugh each usage method variable and construct arranges for each paramater # So if the method expects two parameters - say a string and a number you might # have variables. # A, B # C, B arrangements = [[]] @usage.each do |method_variable| extended_arrangements = [] arrangements.each do |existing_arrangement| available.each do |x| if method_variable.meets_requirements?(x) arrangement = existing_arrangement.copy arrangement.push(x) extended_arrangements.push(arrangement) end end end arrangements = extended_arrangements.copy end # Convert the arrangements to DefCalls def_calls = [] arrangements.each do |x| def_calls.push(DefCall.new(@method_return.copy,self.copy,*x)) end return def_calls end |
#cauldron_method_calls ⇒ Object
817 818 819 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 817 def cauldron_method_calls return ['.all_pass?','.pass?','.history2','.last','.statement_id','.params','.realise2'] end |
#copy ⇒ Object
Creates a copy of the method with the same usage and statements but a different id. I’m not sure if should be using the same id or not.
314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 314 def copy return Marshal.load(Marshal.dump(self)) # # Create the copied method # empty_copy = copy_base # empty_copy.method_id = @method_id # empty_copy.scope_id = scope_id # empty_copy.scope = scope # empty_copy.statement_level = statement_level # self.each do |statement| # empty_copy.push(statement.copy) # end # # return empty_copy end |
#copy_base ⇒ Object
Returns a duplicate method but without any statements in it
370 371 372 373 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 370 def copy_base copied_method = RuntimeMethod.new(@usage.copy,method_id) return copied_method end |
#declaration_statement ⇒ Object
Returns a statement that declares the runtime method instance. e.g. RuntimeMethod.new(MethodUsage.new,ResponseVariable.new)
417 418 419 420 421 422 423 424 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 417 def declaration_statement new_runtime_method = ClassMethodCallContainer.new( RuntimeMethodClass.new, New.new, @usage.declaration_statement ) return Statement.new(new_runtime_method) end |
#describe ⇒ Object
Returns a describtion of the method and the variables within it.
TODO Write test for this method
396 397 398 399 400 401 402 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 396 def describe line = write+"\n" available_variables.each do |var| line += var.describe(self) end return line end |
#find_next_unknown(complete_statements, concept) ⇒ Object
NOTE: This doesn’t handle the case when there are two unknowns -
dependent on each other. e.g. 5 = var1+var2
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 138 def find_next_unknown(complete_statements,concept) # If there are no unknown variables then the concept if fine to use if concept.unknown_count == 0 complete_statements.push(concept) return end concept.each_unknown do |unknown| # Go through each of the varialbes and see if they could be the unknown available_variables.each do |var| # Attempt to substitute one variable for another updated_concept = concept.subst(unknown.variable_id,var) next if updated_concept.nil? # Find any further unknown variables in the statement find_next_unknown(complete_statements,updated_concept) end # Actually only look for the first unknown return end end |
#find_variable_in_parameters(id) ⇒ Object
Searches the paramaters for a variable with the specified id
463 464 465 466 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 463 def find_variable_in_parameters(id) no_var_error = Proc.new { raise FailedToFindVariableError.new('Unable to find variable with the id '+id.to_s) } return @usage.find(no_var_error){|i| i.variable_id == id}.copy end |
#history(params, additional_methods = []) ⇒ Object
Returns a history object reflecting how the runtime method is processed.
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 566 def history(params,additional_methods=[]) # Check the number of parameters to method usage raise StandardError.new('Incorrect number of parameters') unless params.length == @usage.length # Create the method that changes are logged to instance_tracking_variable = ArrayVariable.new instance_tracking_variable.instance_variable = true tracking_method = RuntimeTrackingMethod.new(instance_tracking_variable) # Duplicate the current method and add tracking calls copied = self.copy.trackify(params,tracking_method) # Create a method to call the method and return the results process_method = RuntimeMethod.new(MethodUsage.new) track_statement = Statement.new( DefCall.new(NilVariable.new,copied,*params.collect {|x| x.value} ) ) process_method << track_statement return_statement = Statement.new( Return.new,instance_tracking_variable ) process_method << return_statement # Evaluate the method # TODO This might need to have a number pre-fixed (I'm not certain it's overwritten) # runtime_class = RuntimeClass.new('Temporary'+rand(1000).to_s,tracking_method,copied,process_method,*additional_methods) runtime_class = RuntimeClass.new('Temporary',tracking_method,copied,process_method,*additional_methods) result = ClassEvaluation.new.evaluate_class(runtime_class,process_method.method_name) return result end |
#history2(params, additional_methods = []) ⇒ Object
Proxy for the history method except it expects to receive an array of literals.
TODO Probably best to change the real history method to use literals
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 598 def history2(params,additional_methods=[]) if(params.any? {|x| x.kind_of?(Variable)}) raise StandardError.new('Currently only literal values can be realised') end # TODO Is KnownVariable a better name than LiteralVariable # Convert the passed paramters into literal variables with the appropriate ids unless usage.length == params.length raise StandardError.new('This method expects '+usage.length.to_s+' param(s) but '+params.length.to_s+' were passed') end realised_params = [] usage.zip(params).each do |x,y| realised_params.push y.to_var(x.variable_id,x.uniq_id) end return history(realised_params,methods) end |
#identify_overriding_statements(params) ⇒ Object
Searches through each statement and identifies whether they override an existing variable or not.
407 408 409 410 411 412 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 407 def identify_overriding_statements(params) previously_declared_variables = params.collect {|x| {:variable_id=>x.variable_id} } self.each do |x| x.identify_overriding_statements(previously_declared_variables) end end |
#literal_value_of_var(id, params) ⇒ Object
Evaluates the method but includes a return statement for the variable thats id is specified.
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 429 def literal_value_of_var(id,params) # Create a copy of the runtime method copied = self.copy # Find a reference to the variable in the method's statements and parameters var = nil # TODO Remove all the @parameters params.each do |param| var = param if(param.variable_id == id) end if var.nil? copy.each do |statement| begin var = statement.find_variable(id) rescue FailedToFindVariableError next end break end end if(var.nil?) then raise FailedToFindVariableError.new('Couldn\'t find variable with the id:'+id.to_s) end # Create a return statement for the requested variable copied.push(Statement.new(Return.new,var)) # Now use the method to determine its value at runtime result = MethodEvaluation.new.evaluate_method(copied,params) return result end |
#params ⇒ Object
TODO This is temporary
167 168 169 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 167 def params return usage end |
#partial_method(line) ⇒ Object
Returns a dupicate method but only with the statements up to the line given.
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 339 def partial_method(line) # Create a copy of the base runtime method x = copy_base # Check the length of method if(line>statement_count) then raise MethodSizeError.new('Attmpting to create partial method larger than actual method - crazy bastard!') end # Now add statements up until the line limit has been met index = 0 limit = Array.new(line) while(limit.length>0) if self[index].kind_of?(Statement) x.push(self[index].copy) limit.pop index += 1 elsif self[index].kind_of?(BlockStatement) x.push(self[index].partial(limit)) index += 1 else raise StandardError.new('Unexpected class type '+self[index].class.to_s) end end return x end |
#pass?(test_case) ⇒ Boolean
199 200 201 202 203 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 199 def pass?(test_case) result = MethodEvaluation.new.evaluate_method(self.copy,test_case[:params].collect {|y| y.to_literal}) return false unless result == test_case[:output] return true end |
#push(statement) ⇒ Object
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 205 def push(statement) # Confirms that supplied statement is a statement unless statement.kind_of? Statement or statement.kind_of?(StatementGroup) raise StandardError.new('Only statements can be included in a runtime method not '+statement.class.to_s) end # Check if the statement creates a new variable - and add it the available variables if statement.kind_of? DeclarationStatement @scope_variables.push(statement.declared) # The variable in the statement needs to have its requirements updated end #if statement.kind_of?(StatementGroup) if statement.class.to_s == 'StatementGroup' statement.each do |x| statement_group_push(x) end else # Adding statement to array statement_group_push(statement) end end |
#realise2(params, additional_methods = []) ⇒ Object
Rebuilds the method with TypeVariables that all have literal values.
TODO I expect “params” could probably be changed from a paramaters container to an
array of literal values.
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 740 def realise2(params,additional_methods=[]) # TEMP if(params.any? {|x| x.kind_of?(Variable)}) raise StandardError.new('Currently only literal values can be realised') end # TODO Is KnownVariable a better name than LiteralVariable # Convert the passed paramters into literal variables with the appropriate ids unless usage.length == params.length raise StandardError.new('This method expects '+usage.length.to_s+' param(s) but '+params.length.to_s+' were passed') end realised_params = [] usage.zip(params).each do |x,y| realised_params.push y.to_var(x.variable_id,x.uniq_id) end # Check that any required runtime methods were supplied # TODO Given that I can retrieve all the runtime methods from the statements I probably shouldn't # bother passing them in as parameters to the method. find_all_required_runtime_methods.each do |x| missing_method = lambda{raise StandardError.new('Missing method with id '+x.method_id.to_s)} additional_methods.detect(missing_method) {|y| y.method_id == x.method_id} end # Retrieve a history object reflecting the use of the runtime method past = history(realised_params,additional_methods) # Create a realised method instance to return realised_runtime_method = RealisedRuntimeMethod.new(realised_params) realised_runtime_method.method_id = @method_id # Go through each statement and substitue any of the variables # for those in the history object self.each do |x| if x.realised? realised_runtime_method.push(x) next end # Handle nested and single statements differently if(x.kind_of?(Statement)) realised_statement = x.realise2(past) realised_runtime_method.push(realised_statement) elsif(x.kind_of?(BlockStatement)) # TODO - TEMP DEBUG instance_tracking_variable = ArrayVariable.new instance_tracking_variable.instance_variable = true tracking_method = RuntimeTrackingMethod.new(instance_tracking_variable) #resulting_method.push(x.realise2(past)) realised_runtime_method.push(x.realise2(past)) # TODO I have just added this ---------------------08/02/2011 - I really need to go through the whole # tracking thing. elsif(x.kind_of?(OpenStatement)) # TODO - TEMP DEBUG instance_tracking_variable = ArrayVariable.new instance_tracking_variable.instance_variable = true tracking_method = RuntimeTrackingMethod.new(instance_tracking_variable) #resulting_method.push(x.realise2(past)) realised_runtime_method.push(x.realise2(past)) else raise StandardError.new('Unexpected data type '+x.class.to_s) end end realised_runtime_method.close return realised_runtime_method end |
#replace_statement_element_with_method_calls(statements, variable, available = []) ⇒ Object
Returns an array of statements with a number of method calls added to it that are equivalent to the variable specified.
So a number of statements is provided and a say a string variable. A number method call is added to each statement where the method call will also return a string variable.
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 475 def replace_statement_element_with_method_calls(statements,variable,available=[]) updated_statements = [] if @method_return.meets_requirements?(variable) # Find potential method calls and include them as partial statements callable_combinations(available).each do |x| statements.each do |y| copied_statement = y.copy copied_statement.push(x) updated_statements.push(copied_statement) end end end return updated_statements end |
#reset_ids! ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 86 def reset_ids! copied_method = copy copied_method.method_id = '0' unique_variable_ids = variables.collect {|x| x.variable_id}.uniq reset_variable_ids = (0...unique_variable_ids.length) mapping = {} unique_variable_ids.zip(reset_variable_ids.to_a) do |var_id,reset_id| mapping[var_id] = reset_id end method_parameters = [] @usage.each do |x| method_parameters.push(MethodParameter.new(mapping[x.variable_id])) end usage = MethodUsage.new(*method_parameters) copied_method.usage = usage replacement_mapping = {} mapping.each do |var_id,reset_id| replacement_mapping[var_id] = Unknown.new(reset_id) end copied_method.each do |statement| replacement_mapping.each do |var_id,value| statement.subst_variable!(var_id,value) end end copied_method end |
#statement_count ⇒ Object
Returns the total number of statements within the method. Note
This includes the statements within nested statements.
332 333 334 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 332 def statement_count return self.inject(0) {|count, x| count += x.statement_count} end |
#to_declaration ⇒ Object
Returns a declaration instance for this particular runtime method. The declaration doesn’t contain any of the internally generated statements.
TODO Write tests on this with more variables and statements
77 78 79 80 81 82 83 84 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 77 def to_declaration return VariableDeclaration.new( self.class.to_s, @usage.to_declaration, @method_return.to_declaration, *self.collect {|x| x.to_declaration} ) end |
#to_intrinsic ⇒ Object
821 822 823 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 821 def to_intrinsic return IntrinsicRuntimeMethod.new() end |
#to_var(id = nil, uniq_id = nil) ⇒ Object
Returns the runtime methods as a RuntimeMethodParameter.
553 554 555 556 557 558 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 553 def to_var(id=nil,uniq_id=nil) var = RuntimeMethodParameter.new(self.copy) {{:variable_id => id,:uniq_id=>uniq_id}} # TODO This means that global variable_id is increamented when it doesn't need to be var.variable_id = id unless id.nil? return var end |
#trackify(params, tracking_method) ⇒ Object
Returns an updated method that includes a method call after each statement to monitor the usage of a runtime method.
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 623 def trackify(params,tracking_method) # TODO Really need to give the tracking method parameter proper names - and get them in # correct order. # Identify what statements are overridden to inform what variables need tracked identify_overriding_statements(params) line = [] copied = copy_base modified_params = params # Start by adding the initial tracking call - to catch the parameters # CONTINUE: tracking the statement_id initial_tracking_statement = tracking_statement( tracking_method, line, self.statement_id.to_literal, abstract_variables_for_tracking(modified_params) ) copied.push(initial_tracking_statement) # TODO Currently I am collect all the variables in the variable container -be that # a nested statement or a single statment. I don't know what variables I # actually need to retain. # Create an array to update the variable ids to suite the method usage # TODO I'm not sure this is needed any more id_conversion = Hash.new @usage.zip(params) do |x,y| new_var = y.copy new_var.variable_id = x.variable_id new_var.uniq_id = x.uniq_id id_conversion[x.uniq_id.to_s.to_sym] = new_var end # Copy the runtime method and update each statement copy.each_with_index do |x,i| if x.kind_of?(Statement) # Update the ids of the variables used in the statement to use the ids of the method usage duplicated_statement = x.exchange_variables(id_conversion) variable_values = abstract_variables_for_tracking(duplicated_statement) copied.push(duplicated_statement) copied.push( tracking_statement( tracking_method, line, duplicated_statement.statement_id, variable_values, duplicated_statement ) ) # TODO I think this has to be a OpenStatement elsif(x.kind_of?(StatementGroup)) # Retrieve tha variables available at the point before the nested statement opens results = [] available_variable_at(params,line.length).each do |y| # TODO I should change these to symbols results.push(Hash['id'=>y.variable_id,'value'=>InstanceCallContainer.new(y,Copy.new)]) end # Retrieve the nested statement and trackify it trackifyied_nested_statement = x.trackify( tracking_method,line ) copied.push(trackifyied_nested_statement) # Add the tracking call for after the statement (this has the id for the whole nested statement) # Retrieve the variables used in the nested statement - excluding those no longer in scope # TODO I should maybe only be concerned with the variables that change in the nested # statement. # containers = [x.opening_statement]+x.each # Search through the nested statement for all the statements that override a variable # TODO It really should be all the variables that are overridden and available # outside the nested statement. variable_values = abstract_variables_for_tracking(*x.find_overriding_statements) # TODO The only variables recorded here are ones that overriden inside the nested statement copied.push( tracking_statement( tracking_method, line, self.statement_id, variable_values, x ) ) # TODO I think I'm going to give nested statements two ids - one outside # one inside. I might use the internal statment id as one and the # actual nested statement as the other. else raise StandardError.new('Unexpected class '+x.class.to_s) end end return copied end |
#usage_statements(available = []) ⇒ Object
Returns an array of possible statements that contain a call to this runtime method.
539 540 541 542 543 544 545 546 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 539 def usage_statements(available=[]) results = [] def_calls = callable_combinations(available) def_calls.each do |x| # TODO Unknown variables should be replaced results.push Statement.new(Var) end end |
#variables ⇒ Object
118 119 120 |
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 118 def variables return @usage end |