Class: Statement
- Includes:
- ActsAsCode, ActsAsStatement, PrintVariables
- Defined in:
- lib/core/statement/Statement.rb
Direct Known Subclasses
Constant Summary collapse
- @@statement_id =
0
Instance Attribute Summary collapse
-
#overrides ⇒ Object
writeonly
TODO scope and statement level are confusing - not sure of the difference (I think it’s legacy).
-
#scope ⇒ Object
Returns the value of attribute scope.
-
#statement_id ⇒ Object
Returns the value of attribute statement_id.
-
#statement_level ⇒ Object
Returns the value of attribute statement_level.
Class Method Summary collapse
-
.reset_global_id ⇒ Object
Resets the globablly used value for statements id.
Instance Method Summary collapse
- #[](index) ⇒ Object
- #[]=(index, value) ⇒ Object
- #add(element) ⇒ Object
-
#assignment? ⇒ Boolean
Indicates whether the statement is one that assigns a value to another.
- #cauldron_method_calls ⇒ Object
- #clear ⇒ Object
-
#confirmed? ⇒ Boolean
Indicates whether the statement has been confirmed.
-
#contains_method_call? ⇒ Boolean
Returns true if the statement contains any calls to a runtime method.
-
#context_variable(id) ⇒ Object
Returns a variable instance with the contextual requirements for the statement.
- #contextual_variable(id) ⇒ Object
-
#copy ⇒ Object
Creates a copy of the statement.
-
#created_variable ⇒ Object
Returns the variable created by this statement or raises an error if the statement doesn’t create a variable.
-
#created_variable_id ⇒ Object
Returns the id of the created variable in this statement or raises an error if no variable is created.
-
#creates_variable? ⇒ Boolean
Returns true if this statement creates a new variable.
-
#decalares_variable? ⇒ Boolean
Returns true if the statement declares a variable.
-
#declared_variable ⇒ Object
Returns the variable declared in the statement.
-
#declared_variable_id ⇒ Object
Returns the id of the variable declared in this statement.
- #describe(tab = 0) ⇒ Object
- #each ⇒ Object
-
#each_unrealised_variable ⇒ Object
Displays each of the unrealised variables within the statement.
-
#each_untyped_variable ⇒ Object
yeilds each variable that is not declared in the statement and isn’t known e.g.
- #each_variable ⇒ Object
- #each_with_index ⇒ Object
-
#equivalent?(statement) ⇒ Boolean
TODO Write tests for this Returns true if this statement is equivalent to the statement supplied.
-
#exchange_variables(conversions) ⇒ Object
Returns the statement with the any variables in the conversions table replaced with the supplied variables.
-
#find_actual_variable(uniq_id) ⇒ Object
Returns the variable in this statement with uniq_id specified.
-
#find_all_required_runtime_methods ⇒ Object
Returns an array of all the RuntimeMethods instances contained in this statement.
-
#find_overriding_statements(overriding_statements = []) ⇒ Object
Adds this statement to array of overriding statements if it overrides an existing variable.
-
#find_statement(id) ⇒ Object
Returns this statement if it has the correct id.
-
#find_variable(id) ⇒ Object
Returns the variable or instance call that contains the variable with the specidied id.
- #first ⇒ Object
- #has?(&block) ⇒ Boolean
-
#identify_overriding_statements(already_declared = []) ⇒ Object
If this statement declares a variable determine whether the the variable has been previously declared.
-
#initialize(*parameters) ⇒ Statement
constructor
&block [OPTIONAL] A block can also be provided to preview the statement from being reviewed and therefore preventing changes to variables uniq_id.
-
#is_simple? ⇒ Boolean
Returns true if the statement is simple.
- #last ⇒ Object
- #left_hand_side ⇒ Object
- #length ⇒ Object
-
#literalise ⇒ Object
Attempt to convert the statement into a string without any references to variables where possible.
- #map_to(mapping) ⇒ Object
-
#not_declared_variables ⇒ Object
Returns an array of all the undeclared variables in the statement.
-
#overrides? ⇒ Boolean
Returns true if the statement overrides an existing variable.
-
#push(code) ⇒ Object
Adds the new piece of code to the statement and update the variables requirements to accomodate any change.
-
#realise2(method_map) ⇒ Object
Returns an updated statement where all the variables within the statement have been realised.
-
#realised? ⇒ Boolean
Returns true if the statement has been fully realsied - in that all the variables contained within it are realised.
- #replace_variable!(id, var) ⇒ Object
-
#replace_variable_if(var, &block) ⇒ Object
TODO I should have a realised statement class Finds each element that satisfy the.
-
#required_variable_ids ⇒ Object
Retuns an array of all the variable ids required for the statement.
- #right_hand_side ⇒ Object
-
#same_not_declared_variables?(statement) ⇒ Boolean
Returns true if the statement contains the same undeclared variables as the statement provided as well as the same number of elements.
- #select_all(results = [], &block) ⇒ Object
-
#statement_count ⇒ Object
Returns the number of statments in the statement.
-
#subst(id, var, context = self) ⇒ Object
TODO It would be nicer to a subst that allows a block passed though e.g.
- #subst!(var, &block) ⇒ Object
-
#subst_variable!(id, var) ⇒ Object
TODO Not sure whether both replace_variable! and subst_variable! are both needed - either ways their names aren’t descriptive enough to distinguish that one uses the uniq_id and one uses the variable.
-
#to_declaration(except = []) ⇒ Object
Returns a declaration for this statement.
-
#to_literal_string ⇒ Object
TODO Write tests This method writes the statement out as a literal string.
-
#to_var(id = nil, uniq_id = nil) ⇒ Object
Returns the statement as a StatementVariable.
-
#tokens ⇒ Object
Returns an array of all the tokens in the statement.
-
#unrealised_variables ⇒ Object
Returns each of the variables that aren’t realised.
-
#untyped_variables ⇒ Object
Returns an array of all the untyped variables in the statement.
-
#valid_syntax? ⇒ Boolean
This writes and evalutes the syntax of a statement to determine whether it can be used by it self.
-
#variables ⇒ Object
Returns an array of variables in this statement.
-
#write(tab = 0) ⇒ Object
TODO Maybe use a opject to handle the output of the statement.
- #write_with_uniq_id(tab = 0) ⇒ Object
-
#write_with_value(tab = 0) ⇒ Object
NOTE This method should only be used on realised statements.
-
#write_with_variable_id(tab = 0, context = self) ⇒ Object
Returns a string containing the written version of the statement but any variables will have there id in brackets after them.
Methods included from ActsAsCode
Methods included from ActsAsStatement
#classes_match?, #statement_type
Methods included from PrintVariables
Constructor Details
#initialize(*parameters) ⇒ Statement
&block [OPTIONAL] A block can also be provided to preview the statement from being
reviewed and therefore preventing changes to variables uniq_id.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/core/statement/Statement.rb', line 22 def initialize(*parameters) super() # @overrides = nil @confirmed = false # Sets the flag that indicates the structure of the statement @structure = nil @nodes = [] # Add the parameters to the array parameters.each do |code| # self.push(code.copy) @nodes.push(code.copy) end # TODO I might change the statement_id to be determined by the structure # of the statement. @statement_id = @@statement_id @@statement_id += 1 # Review completed statement if block_given? values = yield review if (values[:review]) else review end end |
Instance Attribute Details
#overrides=(value) ⇒ Object (writeonly)
TODO scope and statement level are confusing - not sure of the difference (I think it’s legacy)
8 9 10 |
# File 'lib/core/statement/Statement.rb', line 8 def overrides=(value) @overrides = value end |
#scope ⇒ Object
Returns the value of attribute scope.
6 7 8 |
# File 'lib/core/statement/Statement.rb', line 6 def scope @scope end |
#statement_id ⇒ Object
Returns the value of attribute statement_id.
6 7 8 |
# File 'lib/core/statement/Statement.rb', line 6 def statement_id @statement_id end |
#statement_level ⇒ Object
Returns the value of attribute statement_level.
6 7 8 |
# File 'lib/core/statement/Statement.rb', line 6 def statement_level @statement_level end |
Class Method Details
.reset_global_id ⇒ Object
Resets the globablly used value for statements id
57 58 59 60 61 62 63 |
# File 'lib/core/statement/Statement.rb', line 57 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 @@statement_id = 0 end |
Instance Method Details
#[](index) ⇒ Object
310 311 312 |
# File 'lib/core/statement/Statement.rb', line 310 def [](index) return @nodes[index] end |
#[]=(index, value) ⇒ Object
306 307 308 |
# File 'lib/core/statement/Statement.rb', line 306 def []=(index,value) @nodes[index] = value end |
#add(element) ⇒ Object
284 285 286 |
# File 'lib/core/statement/Statement.rb', line 284 def add(element) push(element) end |
#assignment? ⇒ Boolean
Indicates whether the statement is one that assigns a value to another. Essential “Does the statement contain an equals sign?”
334 335 336 337 338 339 |
# File 'lib/core/statement/Statement.rb', line 334 def assignment? if detect_class(Equivalent).nil? return false end return true end |
#cauldron_method_calls ⇒ Object
913 914 915 |
# File 'lib/core/statement/Statement.rb', line 913 def cauldron_method_calls return ['.statement_id'] end |
#clear ⇒ Object
326 327 328 |
# File 'lib/core/statement/Statement.rb', line 326 def clear @nodes.clear end |
#confirmed? ⇒ Boolean
Indicates whether the statement has been confirmed.
354 355 356 |
# File 'lib/core/statement/Statement.rb', line 354 def confirmed? return @confirmed end |
#contains_method_call? ⇒ Boolean
Returns true if the statement contains any calls to a runtime method.
266 267 268 |
# File 'lib/core/statement/Statement.rb', line 266 def contains_method_call? return self.any? {|x| x.kind_of?(DefCall)} end |
#context_variable(id) ⇒ Object
Returns a variable instance with the contextual requirements for the statement. TODO Don’t really need these contextual_variable calls
507 508 509 |
# File 'lib/core/statement/Statement.rb', line 507 def context_variable(id) return find_variable(id) end |
#contextual_variable(id) ⇒ Object
511 512 513 |
# File 'lib/core/statement/Statement.rb', line 511 def contextual_variable(id) return context_variable(id) end |
#copy ⇒ Object
Creates a copy of the statement. The copy’s variables should have the same variable ids but should be different instances. When all the code elements are added the statement is ascessed and the the requirements updated approriately.
255 256 257 258 259 260 261 |
# File 'lib/core/statement/Statement.rb', line 255 def copy # tmp = self.collect{|x| x.copy} # result = self.class.new(*tmp) {{:review=>false}} # result.statement_level = statement_level # return result return Marshal.load(Marshal.dump(self)) end |
#created_variable ⇒ Object
Returns the variable created by this statement or raises an error if the statement doesn’t create a variable.
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 |
# File 'lib/core/statement/Statement.rb', line 828 def created_variable # Check if the statement declares a new variable begin return declared_variable rescue ImproperStatementUsageError => e if first.kind_of?(InstanceCallContainer) if first.subject.kind_of?(Variable) and first.method_call.destructive? return first.subject end end raise ImproperStatementUsageError.new(self.write+' statement does not create a new variable "'+e+"'") end end |
#created_variable_id ⇒ Object
Returns the id of the created variable in this statement or raises an error if no variable is created.
821 822 823 |
# File 'lib/core/statement/Statement.rb', line 821 def created_variable_id return created_variable.variable_id end |
#creates_variable? ⇒ Boolean
Returns true if this statement creates a new variable. A variable is considered created if it is declared in the variable or it modifies a variable. e.g. var_a.chop! or var_a.push(var_b)
811 812 813 814 815 816 |
# File 'lib/core/statement/Statement.rb', line 811 def creates_variable? created_variable return true rescue ImproperStatementUsageError return false end |
#decalares_variable? ⇒ Boolean
Returns true if the statement declares a variable
795 796 797 798 |
# File 'lib/core/statement/Statement.rb', line 795 def decalares_variable? return true if self[0].kind_of?(Variable) and self[1].kind_of?(Equal) return false end |
#declared_variable ⇒ Object
Returns the variable declared in the statement. (if one exists)
802 803 804 805 806 |
# File 'lib/core/statement/Statement.rb', line 802 def declared_variable raise ImproperStatementUsageError.new(self.write+' does not declare a variable') unless decalares_variable? return nil if declared_variable_id.nil? return self[0] end |
#declared_variable_id ⇒ Object
Returns the id of the variable declared in this statement
613 614 615 616 |
# File 'lib/core/statement/Statement.rb', line 613 def declared_variable_id raise UnexpectedStatementTypeError.new('Should be declaration statement type '+self.write) unless decalares_variable? return self[0].variable_id end |
#describe(tab = 0) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/core/statement/Statement.rb', line 168 def describe(tab=0) # Check the file type of tab raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum line = '' tab.times {line += "\t" } self.each do |code| line += code.describe break if code.object_id == self.last.object_id end return line end |
#each ⇒ Object
292 293 294 |
# File 'lib/core/statement/Statement.rb', line 292 def each @nodes.each {|x| yield x} end |
#each_unrealised_variable ⇒ Object
Displays each of the unrealised variables within the statement
409 410 411 412 413 |
# File 'lib/core/statement/Statement.rb', line 409 def each_unrealised_variable unrealised_variables.each do |x| yield x end end |
#each_untyped_variable ⇒ Object
yeilds each variable that is not declared in the statement and isn’t known e.g. cat be literalised in the statement.
373 374 375 376 377 |
# File 'lib/core/statement/Statement.rb', line 373 def each_untyped_variable untyped_variables.each do |x| yield x end end |
#each_variable ⇒ Object
117 118 119 |
# File 'lib/core/statement/Statement.rb', line 117 def each_variable variables.each { |x| yield x } end |
#each_with_index ⇒ Object
300 301 302 303 304 |
# File 'lib/core/statement/Statement.rb', line 300 def each_with_index @nodes.each_with_index do |x,i| yield x, i end end |
#equivalent?(statement) ⇒ Boolean
TODO Write tests for this Returns true if this statement is equivalent to the statement supplied. They are equalvalent if they have the same length, classes and values.
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 |
# File 'lib/core/statement/Statement.rb', line 851 def equivalent?(statement) return false unless statement.length == self.length # TODO It would be nice to come up with a method to itterate through # groups in an array. # e.g. [self,statement].each_pair do |x,y| # end # where x is the first element in self and y is the first element in statement # TODO I think Unknowns should only be accepted if they are the first paramter in # a declaration statement. Current var_a = Unknown.chop is the same as var_b = var_c.chop self.each_with_index do |elem,i| return false unless elem.equivalent?(statement[i]) end return true # # TODO Tidy this up - pass the element to each other # # e.g. # # self.each_with_index do |elem,i| # # return false unless eleme.equivalent?(statement[i]) # # end # # # self.each_with_index do |elem,i| # return false if statement[i].class == elem.class # if(elem.kind_of?(Variable)) # return false if elem.variable_id != statement[i].variable_id # elsif(elem.kind_of?(InstanceCallContainer)) # return false if elem.variable_id != statement[i].variable_id # return false if elem.method_call != statement[i].method_call # end # end # return true end |
#exchange_variables(conversions) ⇒ Object
Returns the statement with the any variables in the conversions table replaced with the supplied variables. This is used when a runtime method with parameters needs evaluated.
900 901 902 903 904 905 906 907 908 909 910 911 |
# File 'lib/core/statement/Statement.rb', line 900 def exchange_variables(conversions) copied_statement = self.copy conversions.each do |x,y| begin #copied_statement = copied_statement.subst(x.to_s.to_i,y.copy) copied_statement = copied_statement.replace_variable_if(y) {|a| a.uniq_id == x.to_s.to_i} rescue FailedToFindVariableError next end end return copied_statement end |
#find_actual_variable(uniq_id) ⇒ Object
Returns the variable in this statement with uniq_id specified. In the event the variable resides in a instance call then that is returned.
536 537 538 539 540 |
# File 'lib/core/statement/Statement.rb', line 536 def find_actual_variable(uniq_id) target = self.variables.select {|x| x.uniq_id == uniq_id} return target[0] unless target.empty? raise FailedToFindVariableError.new('Couldn\'t find a variable with the id '+uniq_id.to_s+' in "'+self.write+'"') end |
#find_all_required_runtime_methods ⇒ Object
Returns an array of all the RuntimeMethods instances contained in this statement. In all likelyhood there will no more than one.
772 773 774 775 |
# File 'lib/core/statement/Statement.rb', line 772 def find_all_required_runtime_methods defcalls = @nodes.find_all {|x| x.kind_of?(DefCall)} return defcalls.collect {|x| x.runtime_method} end |
#find_overriding_statements(overriding_statements = []) ⇒ Object
Adds this statement to array of overriding statements if it overrides an existing variable.
683 684 685 686 |
# File 'lib/core/statement/Statement.rb', line 683 def find_overriding_statements(overriding_statements=[]) overriding_statements.push self if self.overrides? return overriding_statements end |
#find_statement(id) ⇒ Object
Returns this statement if it has the correct id
88 89 90 91 92 93 |
# File 'lib/core/statement/Statement.rb', line 88 def find_statement(id) if self.statement_id == id return self end raise FailedToFindStatementError.new('Couldn\'t find statement with id '+id.to_s) end |
#find_variable(id) ⇒ Object
Returns the variable or instance call that contains the variable with the specidied id. It doesn’t search the requirements.
TODO Write test to retrieve declarared variable in a statement with two variables
e.g. varA = varB-varC
524 525 526 527 528 529 530 |
# File 'lib/core/statement/Statement.rb', line 524 def find_variable(id) results = variables.select() {|x| x.variable_id == id} if results.empty? raise FailedToFindVariableError.new('Couldn\'t find variable with id = '+id.to_s+' in "'+self.write+'"') end return results.first end |
#first ⇒ Object
322 323 324 |
# File 'lib/core/statement/Statement.rb', line 322 def first @nodes.first end |
#has?(&block) ⇒ Boolean
884 885 886 887 888 889 |
# File 'lib/core/statement/Statement.rb', line 884 def has?(&block) self.each do |x| return true if block.call(x) end return false end |
#identify_overriding_statements(already_declared = []) ⇒ Object
If this statement declares a variable determine whether the the variable has been previously declared. If so mark this statement as an “overrides” statement otherwise flag it as not.
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/core/statement/Statement.rb', line 70 def identify_overriding_statements(already_declared=[]) [BaseVariable,Equal].zip(@nodes) do |x,y| return unless y.kind_of?(x) end already_declared.each do |x| if x[:variable_id] == declared_variable_id @overrides = true return end end already_declared.push({:variable_id => declared_variable_id}) @overrides = false end |
#is_simple? ⇒ Boolean
Returns true if the statement is simple. In that it just re-declares an existing variable e.g. var_a = var_b.
629 630 631 632 633 634 635 636 |
# File 'lib/core/statement/Statement.rb', line 629 def is_simple? return false unless decalares_variable? # TODO Look at what you call the right hand side of the equation if right_hand_side.length == 1 && right_hand_side[0].kind_of?(Variable) return true end return false end |
#last ⇒ Object
296 297 298 |
# File 'lib/core/statement/Statement.rb', line 296 def last return @nodes.last end |
#left_hand_side ⇒ Object
347 348 349 350 |
# File 'lib/core/statement/Statement.rb', line 347 def left_hand_side l, r = self.split(Equivalent) return l end |
#length ⇒ Object
314 315 316 |
# File 'lib/core/statement/Statement.rb', line 314 def length return @nodes.length end |
#literalise ⇒ Object
Attempt to convert the statement into a string without any references to variables where possible. So varA = varB.chop might become “varA = ‘test’chop”
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/core/statement/Statement.rb', line 125 def literalise # Go through each element in the statement and attempt to literalise it line = '' self.each do |code| unless code.kind_of? Variable or code.kind_of? InstanceCallContainer line += code.write next end if code.kind_of?(Variable) if code.literalisable? literal = code.literalise line += literal.write next end line += code.write elsif code.kind_of?(InstanceCallContainer) if(code.subject.literalisable?) literal = code.subject.literalise line += literal.write+'.'+code.method_call.write next end line += code.write end end return line end |
#map_to(mapping) ⇒ Object
917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 |
# File 'lib/core/statement/Statement.rb', line 917 def map_to(mapping) # Duplicate the current statement before it is rewritten rewritten_statement = self.copy # Find all the containers that contain TheoryVariables # NOTE The statement is put in an array because select all doesn't include the array itself containers = [rewritten_statement].select_all {|x| x.respond_to?(:has?)} theory_variable_containers = containers.select {|x| x.has? {|y| y.kind_of?(Variable)}} # Rewrite the statement replacing the values theory_variable_containers.each do |z| z.replace_variables!(mapping) end return rewritten_statement #return TheoryDependent.new(rewritten_statement,@theory_component_id) end |
#not_declared_variables ⇒ Object
Returns an array of all the undeclared variables in the statement. An undeclared variable is simply a variable not declared in the statement but used in it. e.g. var_c = var_a+var_b var_a and var_b are the undeclared variable.
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/core/statement/Statement.rb', line 421 def not_declared_variables() # The statement shouldn't be valid if there are undeclared variables return [] if valid_syntax? # Find any excluded variables(ones that are delcared within the statement) # e.g. var = 'test'.chop declared_variables = [] if( (self[0].kind_of? Variable)&&(self[1].class == Equal) ) declared_variables.push(self[0].copy) end # Attempt to find all the undeclared variables undeclared = [] variables.each do |x| next if declared_variables.any? {|y| y.uniq_id == x.uniq_id} undeclared.push(x.copy) end return undeclared end |
#overrides? ⇒ Boolean
Returns true if the statement overrides an existing variable. So if a = 6 but a was already set to 4 then this would be an overriding statement.
99 100 101 |
# File 'lib/core/statement/Statement.rb', line 99 def overrides? return @overrides end |
#push(code) ⇒ Object
Adds the new piece of code to the statement and update the variables requirements to accomodate any change.
273 274 275 276 277 278 279 280 281 282 |
# File 'lib/core/statement/Statement.rb', line 273 def push(code) # Add the new piece of code to the statement #array_push(code) @nodes << code # Update the requirements to reflect the change update end |
#realise2(method_map) ⇒ Object
Returns an updated statement where all the variables within the statement have been realised. If the statement resides inside a nested statement or multiple nested statements the variables will be changed into a Dynamic Variable. These dynamic variables contain multiple variables with different values but the same variable_id.
For example:
3.times do |var_a|
var_b = var_a+1
end
In the above case var_b would be a dynamic variable would contain 3 FixnumVariable with the values 1,2,3. The statement itself doesn’t indicate that it is nested, it is still just a regular statement.
In a more complex example where we have two nested statements we might have something like the following:
2.times do |var_a|
2.times do |var_b|
var_c = var_b+1
end
end
We would end up with another dynamic variable with the values 1,2,1,2.
The final tricky situation is when variables are overwritten. As a rule block variables are never overwritten - I should also include the subject of a loop as well.
For example:
var_a = 0 3.times do |var_b|
var_a += var_b
end
In this situation there will be 3 versions of var_a the first one, the dynamic internal one and a post statement variable. The post statement variable will have a statement dependencey on the above nested statement. The internal variable will have a scope depenencey on the nested statement.
TODO I suspect my approach to this is wrong. I pass in the history instance with
all the information and then try to work out the realised value for this statement
but it would probably be easier if the history instance itself to determine this.
735 736 737 738 739 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 |
# File 'lib/core/statement/Statement.rb', line 735 def realise2(method_map) return copy if realised? raise StandardError.new('Unexpected data type ') unless method_map.kind_of?(History) # Create a duplcate statement to be modified result = self.copy # Find value(s) for each unrealised variable. y = [] each_unrealised_variable do |x| if x.kind_of?(BlockVariable) y.push(method_map.find_realised_variable(x.variable_id,x.uniq_id,'BlockVariable')) else y.push(method_map.find_realised_variable(x.variable_id,x.uniq_id)) end # TODO Change to elsif x.kind_of?(Variable) end # Substitue the realised variables for the unrealised ones self.each_unrealised_variable do |x| catch(:variable_substituted) do y.each do |z| if z.uniq_id == x.uniq_id result = result.replace_variable_if(z) {|a| a.uniq_id == x.uniq_id} throw :variable_substituted end end raise StandardError.new('Couldn\'t find realised value for variable with id '+x.variable_id.to_s+' in "'+self.write+'"') end end return result end |
#realised? ⇒ Boolean
Returns true if the statement has been fully realsied - in that all the variables contained within it are realised. Otherwise it returns false.
780 781 782 |
# File 'lib/core/statement/Statement.rb', line 780 def realised? return self.variables.all? {|x| x.realised?} end |
#replace_variable!(id, var) ⇒ Object
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 |
# File 'lib/core/statement/Statement.rb', line 542 def replace_variable!(id,var) # Find the variable to be replaced target = self.find_actual_variable(id) #raise StandardError.new('Both target and variable should be the same class('+target.class.to_s+' != '+var.class.to_s+')') unless(target.kind_of?(var.class)) # TODO Should check for two variable kinds to two instance call kinds self.each_with_index do |code,i| # TODO Need to test with changing instance calls next unless code.kind_of?(Variable) or code.kind_of?(InstanceCallContainer) if(code.variable_id==target.variable_id) if code.kind_of?(Variable) self[i] = var elsif code.kind_of?(InstanceCallContainer) self[i].subject = var end return self end end end |
#replace_variable_if(var, &block) ⇒ Object
TODO I should have a realised statement class Finds each element that satisfy the
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/core/statement/Statement.rb', line 482 def replace_variable_if(var,&block) container = [] @nodes.each do |x| if x.kind_of?(Variable) if block.call(x) container.push(var) next end end if x.kind_of?(InstanceCallContainer) container.push(x.replace_variable_if(var,&block)) next end container.push(x.copy) end #return self.copy(*container) copied = self.copy().clear container.each {|x| copied.push(x) } return copied end |
#required_variable_ids ⇒ Object
Retuns an array of all the variable ids required for the statement.
621 622 623 624 |
# File 'lib/core/statement/Statement.rb', line 621 def required_variable_ids results = self.variables.collect {|x| x.variable_id} return (results-[declared_variable_id]) end |
#right_hand_side ⇒ Object
342 343 344 345 |
# File 'lib/core/statement/Statement.rb', line 342 def right_hand_side l, r = self.split(Equivalent) return r end |
#same_not_declared_variables?(statement) ⇒ Boolean
Returns true if the statement contains the same undeclared variables as the statement provided as well as the same number of elements.
670 671 672 673 674 675 676 |
# File 'lib/core/statement/Statement.rb', line 670 def same_not_declared_variables?(statement) return false if statement.length != self.length statement.not_declared_variables.each do |x| return false unless self.not_declared_variables.any? {|y| y.variable_id == x.variable_id} end return true end |
#select_all(results = [], &block) ⇒ Object
288 289 290 |
# File 'lib/core/statement/Statement.rb', line 288 def select_all(results=[],&block) return @nodes.select_all(results,&block) end |
#statement_count ⇒ Object
Returns the number of statments in the statement. This will always be one but nested statements may have more.
661 662 663 |
# File 'lib/core/statement/Statement.rb', line 661 def statement_count return 1 end |
#subst(id, var, context = self) ⇒ Object
TODO It would be nicer to a subst that allows a block passed though
e.g. a.subst(sub) {|x| x.variable_id == 9}
Returns a new statement that is a duplicate of this statement but with the specified variable replaced.
TODO Use the name nest for more than one statement TODO Write allot!! of tests for this
454 455 456 |
# File 'lib/core/statement/Statement.rb', line 454 def subst(id,var,context=self) return self.copy.subst!(var){|x| x.uniq_id == id} end |
#subst!(var, &block) ⇒ Object
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
# File 'lib/core/statement/Statement.rb', line 458 def subst!(var,&block) # TODO I should probably check whether anything was substituted or or not self.each_with_index do |x,i| next unless x.kind_of?(Variable) or x.kind_of?(InstanceCallContainer) # Essentially checks whether element is an InstanceCallContainer if x.respond_to?(:subst!) self[i] = x.subst!(var,&block) next end if block.call(x) self[i] = var.copy end end return self end |
#subst_variable!(id, var) ⇒ Object
TODO Not sure whether both replace_variable! and subst_variable! are both needed - either ways
their names aren't descriptive enough to distinguish that one uses the uniq_id and one uses
the variable.
571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/core/statement/Statement.rb', line 571 def subst_variable!(id,var) # => TODO Use replace_variable_if? self.each_with_index do |token,i| if token.kind_of?(Variable) && id == token.variable_id self[i] = var next end if token.kind_of?(Container) self[i] = token.subst_variable!(id,var) end end self end |
#to_declaration(except = []) ⇒ Object
Returns a declaration for this statement. So it will look something like - Statement.new(StringVariable.new(‘test’),Equal.new,‘test’)
596 597 598 599 600 601 602 603 604 605 606 607 608 609 |
# File 'lib/core/statement/Statement.rb', line 596 def to_declaration(except=[]) if except.empty? then return VariableDeclaration.new('Statement',*self.collect {|x| x.to_declaration}) end results = [] self.each do |x| if x.kind_of?(Variable) if except.any? {|y| x.variable_id == y} results.push Declaration.new(x.write) next end end results.push x.to_declaration end return VariableDeclaration.new('Statement',*results) end |
#to_literal_string ⇒ Object
TODO Write tests This method writes the statement out as a literal string. In the sense that any of the variables used in the statement are converted to literals and written. Unknown variables are not written yet though.
This method is called during tracking to give an indication what the statement being tracked is doing.
TODO I am treating unknown variables as a special case that is the same
value e.g. 'var' - but for determining equivalent processes it isn't
ideal becuase you loose track of what variables is used in each
statement. Although I'll wait unitl I can come up with an example
and come up with a solution then.
652 653 654 655 656 |
# File 'lib/core/statement/Statement.rb', line 652 def to_literal_string return @nodes.inject('') do |complete,part| complete += part.to_literal_string end end |
#to_var(id = nil, uniq_id = nil) ⇒ Object
Returns the statement as a StatementVariable
789 790 791 792 |
# File 'lib/core/statement/Statement.rb', line 789 def to_var(id=nil,uniq_id=nil) var = StatementVariable.new(self.copy) {{:variable_id => id,:uniq_id=>uniq_id}} return var end |
#tokens ⇒ Object
Returns an array of all the tokens in the statement. A token is any literal, variable, intrinsic runtime or intrinsic testcase
112 113 114 |
# File 'lib/core/statement/Statement.rb', line 112 def tokens return self.select_all([]){|x| x.kind_of?(Token)} end |
#unrealised_variables ⇒ Object
Returns each of the variables that aren’t realised. In that they aren’t TypeVariables and don’t have a literal value.
393 394 395 396 397 398 399 400 401 402 403 404 405 |
# File 'lib/core/statement/Statement.rb', line 393 def unrealised_variables results = [] variables.each do |x| unless x.kind_of?(TypeVariable) results.push(x) next end if x.value.nil? and !x.kind_of?(NilVariable) results.push(x) end end return results end |
#untyped_variables ⇒ Object
Returns an array of all the untyped variables in the statement. Excluding any declared variables in the statement.
382 383 384 385 386 387 388 |
# File 'lib/core/statement/Statement.rb', line 382 def untyped_variables x = [] not_declared_variables.each do |y| x.push(y) unless y.kind_of?(TypeVariable) end return x end |
#valid_syntax? ⇒ Boolean
This writes and evalutes the syntax of a statement to determine whether it can be used by it self.
So something like var1 = var0.chop would fail since var0 doesn’t exist. It needs to write to a different class to avoid the situation where the statement ‘return false’ would perceived as invalid syntax.
366 367 368 |
# File 'lib/core/statement/Statement.rb', line 366 def valid_syntax? return StatementCheck.new.valid_syntax?(self.write) end |
#variables ⇒ Object
Returns an array of variables in this statement
105 106 107 |
# File 'lib/core/statement/Statement.rb', line 105 def variables return self.select_all([]){|x| x.kind_of?(Variable)} end |
#write(tab = 0) ⇒ Object
TODO Maybe use a opject to handle the output of the statement.
154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/core/statement/Statement.rb', line 154 def write(tab=0) # Check the file type of tab raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum line = '' tab.times {line += "\t" } self.each do |code| line += code.write break if code.object_id == self.last.object_id end return line end |
#write_with_uniq_id(tab = 0) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/core/statement/Statement.rb', line 181 def write_with_uniq_id(tab=0) # Check the file type of tab raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum line = '' tab.times {line += "\t" } self.each do |code| # TODO Doesn't need a space on the last code element #line += code.write_with_uniq_id+' ' if code.respond_to?('write_with_uniq_id') line += code.write_with_uniq_id+' ' next end line += code.write+' ' end return line end |
#write_with_value(tab = 0) ⇒ Object
NOTE This method should only be used on realised statements
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/core/statement/Statement.rb', line 200 def write_with_value(tab=0) # Check the file type of tab raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum line = '' tab.times {line += "\t" } self.each do |code| if code.kind_of?(Variable) line += code.write+'('+code.value.write+')' # unless code == self.last # line += ' ' # end next end line += code.write end return line end |
#write_with_variable_id(tab = 0, context = self) ⇒ Object
Returns a string containing the written version of the statement but any variables will have there id in brackets after them.
TODO This method is duplicated with requirements
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/core/statement/Statement.rb', line 230 def write_with_variable_id(tab=0,context=self) line = '' tab.times {line += "\t" } self.each do |x| if x.kind_of? Variable line += x.write+'('+x.variable_id.to_s+') ' next end if x.kind_of? InstanceCallContainer line += x.write+'('+x.subject.variable_id.to_s+')' next end line += x.write end return line end |