cauldron 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +2 -1
- data/VERSION +1 -1
- data/features/cauldron_generates_runtime_method.feature +2 -2
- data/lib/Chain.rb +22 -6
- data/lib/UnifiedChain.rb +17 -2
- data/lib/cauldron.rb +3 -0
- data/lib/cauldron/pot.rb +50 -40
- data/lib/cauldron/terminal.rb +2 -2
- data/lib/core/ClassMethodCallContainer.rb +0 -1
- data/lib/core/MethodUsage.rb +0 -1
- data/lib/core/TheoryGenerator.rb +0 -4
- data/lib/core/runtime_method/RuntimeMethod.rb +1 -1
- data/lib/core/statement/ActsAsStatement.rb +1 -1
- data/lib/core/statement/Statement.rb +65 -146
- data/lib/core/statement/TheoryStatement.rb +1 -0
- data/lib/core/variable/FixnumVariable.rb +4 -5
- data/lib/core/variable/Unknown.rb +1 -11
- data/lib/core/variable/Variable.rb +1 -1
- data/lib/required.rb +0 -1
- data/lib/ruby_code/String.rb +0 -6
- data/lib/theory/TheoryConnector.rb +54 -117
- data/lib/util/ClassEvaluation.rb +9 -28
- data/lib/util/CodeEvaluation.rb +22 -18
- data/lib/util/DeclarationStatementEvaluation.rb +4 -3
- data/lib/util/MethodEvaluation.rb +6 -6
- data/lib/util/StatementCheck.rb +5 -3
- data/lib/util/StringToTheory.rb +0 -1
- data/spec/cauldron/pot_spec.rb +40 -0
- data/test/fixtures/theories/0/dump +0 -0
- data/test/fixtures/theories/1/dump +0 -0
- data/test/fixtures/theories/10/dump +0 -0
- data/test/fixtures/theories/11/dump +0 -0
- data/test/fixtures/theories/12/dump +0 -0
- data/test/fixtures/theories/13/dump +0 -0
- data/test/fixtures/theories/14/dump +0 -0
- data/test/fixtures/theories/15/dump +0 -0
- data/test/fixtures/theories/16/dump +0 -0
- data/test/fixtures/theories/17/dump +0 -0
- data/test/fixtures/theories/18/dump +0 -0
- data/test/fixtures/theories/19/dump +0 -0
- data/test/fixtures/theories/2/dump +0 -0
- data/test/fixtures/theories/20/dump +0 -0
- data/test/fixtures/theories/3/dump +0 -0
- data/test/fixtures/theories/4/dump +0 -0
- data/test/fixtures/theories/5/dump +0 -0
- data/test/fixtures/theories/6/dump +0 -0
- data/test/fixtures/theories/7/dump +0 -0
- data/test/fixtures/theories/8/dump +0 -0
- data/test/fixtures/theories/9/declaration.txt +1 -1
- data/test/fixtures/theories/9/desc +1 -1
- data/test/fixtures/theories/9/dump +0 -0
- data/test/ts_complete.rb +0 -1
- data/test/unit/core/runtime_method/tc_runtime_method.rb +0 -25
- data/test/unit/core/statement/tc_statement.rb +0 -52
- data/test/unit/core/tc_theory_generator.rb +2 -2
- data/test/unit/tc_theory.rb +2 -10
- data/test/unit/theory/tc_theory_action.rb +2 -6
- data/test/unit/util/tc_string_to_theory.rb +2 -2
- data/tmp/runtime_method_evaluation.rb +10 -7
- metadata +28 -30
- data/lib/core/runtime_class/IfStatementClass.rb +0 -12
- data/test/tc_contextual_variables.rb +0 -48
data/Gemfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
@@ -9,5 +9,5 @@ Feature: Cauldron generates a runtime method
|
|
9
9
|
|
10
10
|
Scenarios: example with only one parameter
|
11
11
|
| cases | runtime_method | demo_num |
|
12
|
-
| "'sparky','sparky'*'kel','kel'" | "def
|
13
|
-
| "'fish','animal'*'carrot','
|
12
|
+
| "'sparky','sparky'*'kel','kel'" | "def method_0(var_0)\n\treturn var_0\nend\n" | 1 |
|
13
|
+
| "'fish','animal'*'carrot','vegetable'" | "def method_0(var_0)\n\tif(var_0 == 'fish')\n\t\treturn 'animal'\n\tend\n\treturn 'vegetable'\nend\n" | 2 |
|
data/lib/Chain.rb
CHANGED
@@ -3,6 +3,7 @@ class Chain
|
|
3
3
|
# TODO This access is proably temporary
|
4
4
|
attr_reader :chain_mapping
|
5
5
|
|
6
|
+
@@default_tail_theory = nil
|
6
7
|
#
|
7
8
|
# @param nodes An array of theories in order
|
8
9
|
#
|
@@ -13,13 +14,10 @@ class Chain
|
|
13
14
|
@uniq_theory_instance_ids = ('A'...'Z').to_a
|
14
15
|
|
15
16
|
# Create a result version of 'finish'
|
16
|
-
|
17
|
-
tail_theory = finish.write
|
18
|
-
tail_theory.gsub!('runtime_method','var1')
|
19
|
-
tail_theory.gsub!('test_cases','var2')
|
20
|
-
tail_dependent = TheoryDependent.new(StringToTheory.run(tail_theory))
|
17
|
+
|
21
18
|
# TODO Drop @tail_theory as a instance variable
|
22
|
-
|
19
|
+
#@tail_theory = Theory.new([tail_dependent],nil,[])
|
20
|
+
@tail_theory = Chain.default_tail_theory
|
23
21
|
|
24
22
|
# NOTE: Now the head and tail are using the same ids for their variables
|
25
23
|
@chain_mapping = ChainMapping.new()
|
@@ -34,6 +32,20 @@ class Chain
|
|
34
32
|
|
35
33
|
end
|
36
34
|
|
35
|
+
def self.default_tail_theory
|
36
|
+
if @@default_tail_theory.nil?
|
37
|
+
finish = Parser.run("if(runtime_method.all_pass?(test_cases))\nreturn true\nend")
|
38
|
+
tail_theory = finish.write
|
39
|
+
tail_theory.gsub!('runtime_method','var1')
|
40
|
+
tail_theory.gsub!('test_cases','var2')
|
41
|
+
tail_dependent = TheoryDependent.new(StringToTheory.run(tail_theory))
|
42
|
+
@@default_tail_theory = Theory.new([tail_dependent],nil,[])
|
43
|
+
@@default_tail_theory.copy
|
44
|
+
else
|
45
|
+
@@default_tail_theory.copy
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
37
49
|
# TODO I want to drop allot of these quick methods
|
38
50
|
def <<(node)
|
39
51
|
@nodes << node
|
@@ -111,6 +123,10 @@ class Chain
|
|
111
123
|
end
|
112
124
|
end
|
113
125
|
|
126
|
+
def theories_sequence
|
127
|
+
@nodes.collect {|x| x.theory_id}
|
128
|
+
end
|
129
|
+
|
114
130
|
# Returns a new chain where they are all using the same respective theory
|
115
131
|
# variables.
|
116
132
|
#
|
data/lib/UnifiedChain.rb
CHANGED
@@ -58,7 +58,7 @@ class UnifiedChain < Chain
|
|
58
58
|
valid_mappings = [Mapping.new]
|
59
59
|
|
60
60
|
#itteration_limit = 6
|
61
|
-
itteration_limit =
|
61
|
+
itteration_limit = 9
|
62
62
|
|
63
63
|
@nodes.each_with_index do |node,index|
|
64
64
|
|
@@ -87,7 +87,8 @@ class UnifiedChain < Chain
|
|
87
87
|
limit += 1
|
88
88
|
end
|
89
89
|
if limit > itteration_limit
|
90
|
-
|
90
|
+
pp missing_variables(node.action,valid_mappings)
|
91
|
+
raise StandardError.new('Unable to resolve action: '+"\n"+node.action.write)
|
91
92
|
end
|
92
93
|
end
|
93
94
|
|
@@ -116,12 +117,26 @@ class UnifiedChain < Chain
|
|
116
117
|
return true
|
117
118
|
end
|
118
119
|
|
120
|
+
def missing_variables(component,mappings)
|
121
|
+
results = []
|
122
|
+
component.theory_variables.each do |var|
|
123
|
+
mappings.each do |mapping|
|
124
|
+
#return false unless mapping.has_key? var.theory_variable_id
|
125
|
+
results << var unless mapping.has_key? var.theory_variable_id
|
126
|
+
end
|
127
|
+
end
|
128
|
+
return results
|
129
|
+
end
|
130
|
+
|
119
131
|
def extend_mapping(valid_mappings,component,runtime_method,test_cases,chain,available_values)
|
120
132
|
|
121
133
|
new_mappings = []
|
122
134
|
component.theory_variables.each do |var|
|
123
135
|
next if valid_mappings.first.has_key?(var.theory_variable_id)
|
136
|
+
#next if valid_mappings.any? {|x| x.has_key?(var.theory_variable_id)}
|
124
137
|
valid_mappings.each do |mapping|
|
138
|
+
|
139
|
+
#next if mapping.has_key?(var.theory_variable_id)
|
125
140
|
|
126
141
|
#next if mapping.has_key?(var.theory_variable_id)
|
127
142
|
implemented_chain = chain.implement(Mapping.new(mapping))
|
data/lib/cauldron.rb
CHANGED
data/lib/cauldron/pot.rb
CHANGED
@@ -3,70 +3,76 @@ module Cauldron
|
|
3
3
|
class Pot
|
4
4
|
include ContainsTheories
|
5
5
|
|
6
|
-
VERSION = '0-
|
6
|
+
VERSION = '0-1-1'
|
7
7
|
|
8
8
|
def initialize()
|
9
|
-
|
9
|
+
StandardLogger.instance.level = Logger::FATAL
|
10
10
|
end
|
11
11
|
|
12
12
|
def brew(test_cases)
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
exclude = []
|
15
|
+
chain = next_chain(test_cases,exclude)
|
16
|
+
if chain.nil?
|
16
17
|
raise StandardError.new('Failed to generate a chain for this problem')
|
17
18
|
end
|
18
19
|
|
19
|
-
# => TODO This probably shouldn't be needed
|
20
|
-
written_chains = chains.collect {|x| x.write}
|
21
|
-
unique_written_chains = written_chains.uniq
|
22
|
-
unique_chains = []
|
23
|
-
chains.each do |x|
|
24
|
-
unless unique_chains.any? {|y| y.write == x.write}
|
25
|
-
unique_chains << x
|
26
|
-
end
|
27
|
-
end
|
28
|
-
chains = unique_chains
|
29
|
-
|
30
20
|
runtime_method = RuntimeMethod.new(MethodUsage.new(MethodParameter.new))
|
31
|
-
|
32
|
-
|
21
|
+
if chain_valid?(chain,test_cases.copy)
|
22
|
+
validator = TheoryChainValidator.new
|
33
23
|
unified_chain = chain.unify_chain
|
34
24
|
implementation_permutations = unified_chain.implementation_permuatations(runtime_method.copy,test_cases.copy,Mapping.new)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
25
|
+
return validator.build(runtime_method.copy,test_cases.copy,implementation_permutations)
|
26
|
+
else
|
27
|
+
exclude << chain.theories_sequence
|
28
|
+
chain = next_chain(test_cases,exclude)
|
29
|
+
if chain_valid?(chain,test_cases.copy)
|
30
|
+
validator = TheoryChainValidator.new
|
31
|
+
unified_chain = chain.unify_chain
|
32
|
+
implementation_permutations = unified_chain.implementation_permuatations(runtime_method.copy,test_cases.copy,Mapping.new)
|
33
|
+
return validator.build(runtime_method.copy,test_cases.copy,implementation_permutations)
|
34
|
+
end
|
45
35
|
end
|
46
36
|
return nil
|
47
37
|
|
48
38
|
end
|
49
39
|
|
40
|
+
def chain_valid?(chain,test_cases)
|
41
|
+
runtime_method = RuntimeMethod.new(MethodUsage.new(MethodParameter.new))
|
42
|
+
unified_chain = chain.unify_chain
|
43
|
+
implementation_permutations = unified_chain.implementation_permuatations(runtime_method.copy,test_cases.copy,Mapping.new)
|
44
|
+
|
45
|
+
# Go through each of the permutations and create the runtime method for the chain
|
46
|
+
validator = TheoryChainValidator.new
|
47
|
+
begin
|
48
|
+
result = validator.build(runtime_method.copy,test_cases.copy,implementation_permutations)
|
49
|
+
rescue StandardError => e
|
50
|
+
StandardLogger.instance.warning e
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
50
56
|
def complete_chains(test_cases)
|
57
|
+
return [next_chain(test_cases)]
|
58
|
+
end
|
59
|
+
|
60
|
+
def next_chain(test_cases,exclude=[])
|
51
61
|
|
52
62
|
theories = saved_theories
|
53
63
|
|
64
|
+
res = theories.collect {|x| x.theory_id }
|
65
|
+
|
54
66
|
runtime_method = RuntimeMethod.new(MethodUsage.new(MethodParameter.new))
|
55
|
-
|
56
|
-
|
57
|
-
tc_index_1 = IntrinsicLiteral.new(1)
|
58
|
-
param_0 = IntrinsicLiteral.new(0)
|
59
|
-
real_method = Parser.run('runtime_method')
|
60
|
-
|
61
|
-
# Create the thoery connector and the values available
|
62
|
-
# TODO These values should actually be retreived progressively
|
63
|
-
potential_values = MappingValues.new([tc,tc_index_0,tc_index_1,param_0,real_method])
|
67
|
+
|
68
|
+
potential_values = MappingValues.new([])
|
64
69
|
connector = TheoryConnector.new(potential_values)
|
65
70
|
|
66
71
|
# Attempt to generate a complete chain for the solution
|
67
|
-
chains = connector.generate_chains(runtime_method,test_cases,theories)
|
68
|
-
return chains
|
69
|
-
|
72
|
+
chains = connector.generate_chains(runtime_method,test_cases,theories,exclude)
|
73
|
+
return chains.first
|
74
|
+
|
75
|
+
end
|
70
76
|
|
71
77
|
def saved_theories
|
72
78
|
saved_theory_file_paths = Dir.glob(File.join(theory_repository_path,'*','dump'))
|
@@ -133,7 +139,11 @@ module Cauldron
|
|
133
139
|
|
134
140
|
# Define the theory's directory
|
135
141
|
theory_path = File.join(repository,theory.theory_id.to_s)
|
136
|
-
|
142
|
+
if File.exists?(theory_path)
|
143
|
+
puts theory_path+' already exists'
|
144
|
+
#raise StandardError.new('Directory already exists - how as this happened?') if File.exists?(theory_path)
|
145
|
+
return
|
146
|
+
end
|
137
147
|
|
138
148
|
# Save a file containing the theory
|
139
149
|
FileUtils.mkdir_p(theory_path)
|
data/lib/cauldron/terminal.rb
CHANGED
@@ -16,7 +16,7 @@ module Cauldron
|
|
16
16
|
@pot = Cauldron::Pot.new
|
17
17
|
@pot.clear
|
18
18
|
@output.puts '* Adding example case'
|
19
|
-
|
19
|
+
@pot.simmer(demo_one)
|
20
20
|
@pot.simmer(demo_two)
|
21
21
|
|
22
22
|
@output.puts "Thanks for trying Cauldron - it's at really early stage right now"
|
@@ -40,7 +40,7 @@ module Cauldron
|
|
40
40
|
|
41
41
|
def submit(input)
|
42
42
|
if input =~ /^RUN$/
|
43
|
-
@output.puts @pot.brew(@cases).basic_write
|
43
|
+
@output.puts @pot.brew(@cases).reset_ids!.basic_write
|
44
44
|
else
|
45
45
|
@cases << convert_to_example(separate_values(input))
|
46
46
|
end
|
data/lib/core/MethodUsage.rb
CHANGED
data/lib/core/TheoryGenerator.rb
CHANGED
@@ -232,10 +232,6 @@ class TheoryGenerator
|
|
232
232
|
)
|
233
233
|
end
|
234
234
|
end
|
235
|
-
# Add the 'if(var1 == var2)' statement
|
236
|
-
# TODO Might only allow values in the action at this point
|
237
|
-
# 'IfStatement.new(var2[var3][:params][var6],Equivalent.new,var2[var3][:output])'
|
238
|
-
# TODO Should the values be equal at this point??
|
239
235
|
|
240
236
|
# Exclude the runtime method from being included as a value (.write method becomes messy)
|
241
237
|
# also excludes the orginal test_cases.
|
@@ -206,7 +206,7 @@ class RuntimeMethod < StatementGroup
|
|
206
206
|
|
207
207
|
# Confirms that supplied statement is a statement
|
208
208
|
unless statement.kind_of? Statement or statement.kind_of?(StatementGroup)
|
209
|
-
raise StandardError.new('Only statements can be included in a runtime method')
|
209
|
+
raise StandardError.new('Only statements can be included in a runtime method not '+statement.class.to_s)
|
210
210
|
end
|
211
211
|
|
212
212
|
# Check if the statement creates a new variable - and add it the available variables
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Statement
|
1
|
+
class Statement
|
2
2
|
include PrintVariables
|
3
3
|
include ActsAsStatement
|
4
4
|
include ActsAsCode
|
@@ -7,7 +7,9 @@ class Statement < Array
|
|
7
7
|
# TODO scope and statement level are confusing - not sure of the difference (I think it's legacy)
|
8
8
|
attr_writer :scope, :statement_level, :overrides, :statement_id
|
9
9
|
|
10
|
-
alias :array_push :push
|
10
|
+
#alias :array_push :push
|
11
|
+
|
12
|
+
|
11
13
|
|
12
14
|
@@statement_id = 0
|
13
15
|
|
@@ -27,9 +29,12 @@ class Statement < Array
|
|
27
29
|
# Sets the flag that indicates the structure of the statement
|
28
30
|
@structure = nil
|
29
31
|
|
32
|
+
@nodes = []
|
33
|
+
|
30
34
|
# Add the parameters to the array
|
31
35
|
parameters.each do |code|
|
32
|
-
|
36
|
+
# self.push(code.copy)
|
37
|
+
@nodes.push(code.copy)
|
33
38
|
end
|
34
39
|
|
35
40
|
# TODO I might change the statement_id to be determined by the structure
|
@@ -63,7 +68,7 @@ class Statement < Array
|
|
63
68
|
# as not.
|
64
69
|
#
|
65
70
|
def identify_overriding_statements(already_declared=[])
|
66
|
-
[BaseVariable,Equal].zip(
|
71
|
+
[BaseVariable,Equal].zip(@nodes) do |x,y|
|
67
72
|
return unless y.kind_of?(x)
|
68
73
|
end
|
69
74
|
already_declared.each do |x|
|
@@ -268,7 +273,8 @@ class Statement < Array
|
|
268
273
|
def push(code)
|
269
274
|
|
270
275
|
# Add the new piece of code to the statement
|
271
|
-
array_push(code)
|
276
|
+
#array_push(code)
|
277
|
+
@nodes << code
|
272
278
|
|
273
279
|
# Update the requirements to reflect the change
|
274
280
|
update
|
@@ -279,6 +285,48 @@ class Statement < Array
|
|
279
285
|
push(element)
|
280
286
|
end
|
281
287
|
|
288
|
+
def select_all(results=[],&block)
|
289
|
+
return @nodes.select_all(results,&block)
|
290
|
+
end
|
291
|
+
|
292
|
+
def each
|
293
|
+
@nodes.each {|x| yield x}
|
294
|
+
end
|
295
|
+
|
296
|
+
def last
|
297
|
+
return @nodes.last
|
298
|
+
end
|
299
|
+
|
300
|
+
def each_with_index
|
301
|
+
@nodes.each_with_index do |x,i|
|
302
|
+
yield x, i
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def []=(index,value)
|
307
|
+
@nodes[index] = value
|
308
|
+
end
|
309
|
+
|
310
|
+
def [](index)
|
311
|
+
return @nodes[index]
|
312
|
+
end
|
313
|
+
|
314
|
+
def length
|
315
|
+
return @nodes.length
|
316
|
+
end
|
317
|
+
|
318
|
+
def select_all(results=[],&block)
|
319
|
+
return @nodes.select_all(results,&block)
|
320
|
+
end
|
321
|
+
|
322
|
+
def first
|
323
|
+
@nodes.first
|
324
|
+
end
|
325
|
+
|
326
|
+
def clear
|
327
|
+
@nodes.clear
|
328
|
+
end
|
329
|
+
|
282
330
|
# Indicates whether the statement is one that assigns
|
283
331
|
# a value to another. Essential "Does the statement
|
284
332
|
# contain an equals sign?"
|
@@ -432,8 +480,8 @@ class Statement < Array
|
|
432
480
|
# @param var The variable to replace any elements that match the block.
|
433
481
|
#
|
434
482
|
def replace_variable_if(var,&block)
|
435
|
-
container =
|
436
|
-
|
483
|
+
container = []
|
484
|
+
@nodes.each do |x|
|
437
485
|
if x.kind_of?(Variable)
|
438
486
|
if block.call(x)
|
439
487
|
container.push(var)
|
@@ -446,7 +494,10 @@ class Statement < Array
|
|
446
494
|
end
|
447
495
|
container.push(x.copy)
|
448
496
|
end
|
449
|
-
return container
|
497
|
+
#return self.copy(*container)
|
498
|
+
copied = self.copy().clear
|
499
|
+
container.each {|x| copied.push(x) }
|
500
|
+
return copied
|
450
501
|
|
451
502
|
end
|
452
503
|
|
@@ -470,29 +521,12 @@ class Statement < Array
|
|
470
521
|
# TODO Write test to retrieve declarared variable in a statement with two variables
|
471
522
|
# e.g. varA = varB-varC
|
472
523
|
#
|
473
|
-
# TODO Write tests for this
|
474
|
-
#
|
475
524
|
def find_variable(id)
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
next unless code.kind_of? Variable or code.kind_of? InstanceCallContainer
|
480
|
-
|
481
|
-
# Determine if the variable matches the id
|
482
|
-
if code.variable_id == id
|
483
|
-
|
484
|
-
# Does the statement declare a new variable?
|
485
|
-
if decalares_variable?
|
486
|
-
return find_variable_in_declaration_statement(code)
|
487
|
-
else
|
488
|
-
return code.copy
|
489
|
-
end
|
490
|
-
|
491
|
-
end
|
492
|
-
|
525
|
+
results = variables.select() {|x| x.variable_id == id}
|
526
|
+
if results.empty?
|
527
|
+
raise FailedToFindVariableError.new('Couldn\'t find variable with id = '+id.to_s+' in "'+self.write+'"')
|
493
528
|
end
|
494
|
-
|
495
|
-
raise FailedToFindVariableError.new('Couldn\'t find variable with id = '+id.to_s+' in "'+self.write+'"')
|
529
|
+
return results.first
|
496
530
|
end
|
497
531
|
|
498
532
|
# Returns the variable in this statement with uniq_id specified. In
|
@@ -616,7 +650,7 @@ class Statement < Array
|
|
616
650
|
# and come up with a solution then.
|
617
651
|
#
|
618
652
|
def to_literal_string
|
619
|
-
return
|
653
|
+
return @nodes.inject('') do |complete,part|
|
620
654
|
complete += part.to_literal_string
|
621
655
|
end
|
622
656
|
end
|
@@ -736,7 +770,7 @@ class Statement < Array
|
|
736
770
|
# statement. In all likelyhood there will no more than one.
|
737
771
|
#
|
738
772
|
def find_all_required_runtime_methods
|
739
|
-
defcalls =
|
773
|
+
defcalls = @nodes.find_all {|x| x.kind_of?(DefCall)}
|
740
774
|
return defcalls.collect {|x| x.runtime_method}
|
741
775
|
end
|
742
776
|
|
@@ -900,121 +934,6 @@ class Statement < Array
|
|
900
934
|
end
|
901
935
|
|
902
936
|
protected
|
903
|
-
|
904
|
-
# Presumes this is a declaration statement and attempts to return
|
905
|
-
# specified variable in the context of the method.
|
906
|
-
#
|
907
|
-
def find_variable_in_declaration_statement(var)
|
908
|
-
|
909
|
-
# Duplicate the variable
|
910
|
-
# TODo I think I want to get rid of this "copy_contextual_variable"and just use copy
|
911
|
-
copied_variable = var.copy_contextual_variable
|
912
|
-
|
913
|
-
# Is the variable declared in this statement?
|
914
|
-
if(self[0].variable_id == copied_variable.variable_id)
|
915
|
-
|
916
|
-
# Create a requirement reflecting the declaration statement
|
917
|
-
# e.g varA = 'test'.chop becomes self = 'test'.chop
|
918
|
-
# statement_requirement = declared_variable_requirement
|
919
|
-
|
920
|
-
# Add this requirement to the variable and return it
|
921
|
-
# copied_variable.push(statement_requirement)
|
922
|
-
|
923
|
-
# TODO I think determining the value of variables at this point should
|
924
|
-
# be removed or re-thought. I think the typify method is more useful.
|
925
|
-
# The problem is that each statement is dependent on other statements
|
926
|
-
# or method calls.
|
927
|
-
|
928
|
-
# # NOTE I have included the untyped_variables call becuase it was continually throwing
|
929
|
-
# # since so many statements include method calls.
|
930
|
-
# if self.untyped_variables.length == 0 && !contains_method_call?
|
931
|
-
# # Convert the variable to be typed (if possible)
|
932
|
-
# if copied_variable.kind_of?(Unknown)
|
933
|
-
# begin
|
934
|
-
# return copied_variable.classify(CodeEvaluation.new.evaluate_code(literalise))
|
935
|
-
# # TODO I shouldn't use NameError - since I want to catch badly formed syntax - I
|
936
|
-
# # should have a custom error for bad syntax that will occu
|
937
|
-
# rescue NameError => e
|
938
|
-
# StandardLogger.log(' -- Statement: find_variable_in_declaration_statement'+e)
|
939
|
-
# end
|
940
|
-
# end
|
941
|
-
# end
|
942
|
-
|
943
|
-
return copied_variable
|
944
|
-
|
945
|
-
else
|
946
|
-
|
947
|
-
# The variable isn't declared in this statement
|
948
|
-
# So if varB is the declared variriable we might have
|
949
|
-
# varB = varA.chop
|
950
|
-
#
|
951
|
-
# This would create the requirement self.chop = varB
|
952
|
-
#
|
953
|
-
# Declare the statement requirement to be created
|
954
|
-
statement_requirement = nil
|
955
|
-
|
956
|
-
# Does the statement only have three elements
|
957
|
-
if(self.length == 3)
|
958
|
-
|
959
|
-
# Create a requirement for the variable in the statement
|
960
|
-
if(self[2].kind_of?(InstanceCallContainer))
|
961
|
-
|
962
|
-
# Create the matching requirement
|
963
|
-
statement_requirement = Requirement.new(InstanceCallContainer.new(This.new,self[2].method_call.class.new),Equal.new,self[0].copy)
|
964
|
-
|
965
|
-
elsif(self[2].kind_of?(Variable))
|
966
|
-
|
967
|
-
# Create the requirement reflecting the statement
|
968
|
-
statement_requirement = Requirement.new(This.new,Equal.new,self[0].copy)
|
969
|
-
|
970
|
-
else
|
971
|
-
raise StandardError.new('Unexpected class type '+self[2].class.to_s)
|
972
|
-
end
|
973
|
-
|
974
|
-
else
|
975
|
-
|
976
|
-
raise StandardError.new('Unexpected statement length'+self.length.to_s+' for requirement re-write') unless self.length == 5
|
977
|
-
|
978
|
-
# Handle the case were we have varA = varB-varC and we want varB's requirement
|
979
|
-
# e.g. we need varB = varA+varC
|
980
|
-
|
981
|
-
# TODO This can probably be re-written to be more abstract
|
982
|
-
# Case varA = varB-varC
|
983
|
-
if( self[2].kind_of?(Variable) and self[3].kind_of?(Subtract) and self[4].kind_of?(Variable) )
|
984
|
-
|
985
|
-
# where varB is the subject -> this = varA + varC
|
986
|
-
if(self[2].variable_id == var.variable_id)
|
987
|
-
statement_requirement = Requirement.new(This.new,Equal.new,self[0].copy,Addition.new,self[4].copy)
|
988
|
-
end
|
989
|
-
|
990
|
-
# where varC is the subject -> this = varB-varA
|
991
|
-
if(self[4].variable_id == var.variable_id)
|
992
|
-
statement_requirement = Requirement.new(This.new,Equal.new,self[2].copy,Subtract.new,self[0].copy)
|
993
|
-
end
|
994
|
-
|
995
|
-
elsif(self[2].kind_of?(Variable) and self[3].kind_of?(Addition) and self[4].kind_of?(Variable) )
|
996
|
-
|
997
|
-
if(self[2].variable_id == var.variable_id)
|
998
|
-
statement_requirement = Requirement.new(This.new,Equal.new,self[0].copy,Subtract.new,self[4].copy)
|
999
|
-
end
|
1000
|
-
|
1001
|
-
if(self[4].variable_id == var.variable_id)
|
1002
|
-
statement_requirement = Requirement.new(This.new,Equal.new,self[2].copy,Addition.new,self[0].copy)
|
1003
|
-
end
|
1004
|
-
|
1005
|
-
else
|
1006
|
-
raise StandardError.new('Unknown statement structure "'+self.write+'"')
|
1007
|
-
end
|
1008
|
-
|
1009
|
-
end
|
1010
|
-
|
1011
|
-
# Adding the new requirement to the variable
|
1012
|
-
copied_variable.push(statement_requirement)
|
1013
|
-
return copied_variable
|
1014
|
-
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
end
|
1018
937
|
|
1019
938
|
# @param var The subsitute variable
|
1020
939
|
# @param id The id of the substitee
|