Class: RuntimeMethod

Inherits:
StatementGroup show all
Includes:
ActsAsRuntimeMethod, ActsAsTrackable
Defined in:
lib/core/runtime_method/RuntimeMethod.rb

Overview

since you can’t write methods within methods.

Direct Known Subclasses

RuntimeTrackingMethod

Constant Summary collapse

@@METHOD_ID =
0

Instance Attribute Summary collapse

Attributes inherited from StatementGroup

#scope, #scope_id, #statement_level

Class Method Summary collapse

Instance Method Summary collapse

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)

Parameters:

  • usage

    How the method should be used - this usage issue needs re-thought for now the only requirement is for usage.length to equal parameters.length

  • method_return

    The response variable to return or nil if nothing is returned



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_idObject

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_returnObject (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

#usageObject

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_idObject



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.

Parameters:

  • id

    The id of the variable that a return statement is being created for.



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.

Raises:

  • (StandardError)


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.

Returns:



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

Parameters:

  • found_variables
  • statement

    The statement that contains the solution. It should be in the following format: return_var = var or return_var = var.<method_call>

  • rule

Raises:

  • (StandardError)


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.

Parameters:

  • available (defaults to: [])

    An array of possible paramaters for the method call



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_callsObject



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

#copyObject

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_baseObject

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_statementObject

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

#describeObject

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.

Parameters:

  • params

    An array of realised variables

  • additional_methods (defaults to: [])

    An array of add

Raises:

  • (StandardError)


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

#paramsObject

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

Returns:



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.

Parameters:

  • params

    A param container instance that contains the necessary parameters for the runtime method instance.

  • params (UPDATE)

    This is being changed to except only an array of literal values e.g. ‘tests’, 9, <#SomeObject>. This will be converted into a literal variable within the method.

  • additional_methods (defaults to: [])

    An array of any methods that are required by the runtime method instance



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_countObject

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_declarationObject

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_intrinsicObject



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.

Parameters:

  • id (defaults to: nil)

    The id of the variable to give to the returned method variable.



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.

Parameters:

  • tracking_method

    A runtime tracking method instance that the track calls saved to.



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

#variablesObject



118
119
120
# File 'lib/core/runtime_method/RuntimeMethod.rb', line 118

def variables
  return @usage
end