cauldron 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +7 -0
  3. data/VERSION +1 -1
  4. data/features/cauldron_generates_runtime_method.feature +3 -2
  5. data/features/step_definitions/cauldron_steps.rb +0 -1
  6. data/features/support/method_1.example +3 -0
  7. data/features/support/method_2.example +6 -0
  8. data/lib/Chain.rb +140 -264
  9. data/lib/CodeHandler.rb +0 -4
  10. data/lib/ScopeDependencies.rb +1 -0
  11. data/lib/Theory.rb +12 -15
  12. data/lib/UnifiedChain.rb +265 -8
  13. data/lib/cauldron.rb +1 -1
  14. data/lib/cauldron/demos.rb +280 -0
  15. data/lib/cauldron/pot.rb +56 -30
  16. data/lib/cauldron/sexp2cauldron.rb +109 -126
  17. data/lib/cauldron/terminal.rb +5 -74
  18. data/lib/core/ClassMethodCallContainer.rb +14 -0
  19. data/lib/core/Container.rb +12 -2
  20. data/lib/core/InstanceCallContainer.rb +30 -4
  21. data/lib/core/TheoryGenerator.rb +2 -9
  22. data/lib/core/assignment/Equal.rb +1 -1
  23. data/lib/core/assignment/Equivalent.rb +1 -1
  24. data/lib/core/assignment/NotEqual.rb +1 -1
  25. data/lib/core/call_container/CallContainer.rb +7 -1
  26. data/lib/core/instance_call/Chop.rb +0 -9
  27. data/lib/core/instance_call/instance_calls.rb +8 -0
  28. data/lib/core/instance_call/length_equal.rb +1 -1
  29. data/lib/core/requirement/Requirement.rb +1 -0
  30. data/lib/core/runtime_class/class_names.rb +12 -12
  31. data/lib/core/runtime_method/ActsAsRuntimeMethod.rb +0 -7
  32. data/lib/core/runtime_method/RuntimeMethod.rb +59 -45
  33. data/lib/core/statement/ActsAsStatement.rb +1 -1
  34. data/lib/core/statement/ArrayAccess.rb +28 -2
  35. data/lib/core/statement/OpenStatement.rb +7 -0
  36. data/lib/core/statement/Statement.rb +22 -18
  37. data/lib/core/statement/TheoryStatement.rb +8 -1
  38. data/lib/core/syntax/Addition.rb +3 -2
  39. data/lib/core/syntax/If.rb +8 -0
  40. data/lib/core/syntax/Return.rb +1 -1
  41. data/lib/core/variable/BaseVariable.rb +0 -2
  42. data/lib/core/variable/MethodParameter.rb +4 -31
  43. data/lib/core/variable/Unknown.rb +1 -5
  44. data/lib/implemented_chain.rb +3 -2
  45. data/lib/required.rb +0 -1
  46. data/lib/ruby_code/String.rb +0 -17
  47. data/lib/theories.rb +25 -1
  48. data/lib/theory/TheoryAction.rb +35 -5
  49. data/lib/theory/TheoryChainValidator.rb +10 -8
  50. data/lib/theory/TheoryComponent.rb +17 -0
  51. data/lib/theory/TheoryConnector.rb +76 -9
  52. data/lib/theory/TheoryDependent.rb +2 -2
  53. data/lib/theory/TheoryImplementation.rb +7 -7
  54. data/lib/util/ClassEvaluation.rb +2 -7
  55. data/lib/util/MethodValidation.rb +10 -6
  56. data/lib/util/Parser.rb +26 -20
  57. data/lib/util/StringToTheory.rb +27 -3
  58. data/spec/cauldron/chain_spec.rb +24 -0
  59. data/spec/cauldron/demos_spec.rb +30 -0
  60. data/spec/cauldron/pot_spec.rb +66 -0
  61. data/spec/cauldron/runtime_method_spec.rb +47 -5
  62. data/spec/cauldron/sexp_2_cauldron_spec.rb +92 -0
  63. data/spec/cauldron/terminal_spec.rb +1 -1
  64. data/spec/cauldron/theory_action_spec.rb +20 -0
  65. data/spec/cauldron/theory_connector_spec.rb +52 -0
  66. data/spec/cauldron/theory_spec.rb +59 -0
  67. data/spec/cauldron/unified_chain_spec.rb +102 -0
  68. data/spec/spec_helper.rb +10 -1
  69. data/tasks/theory_tasks.rake +274 -0
  70. data/test/fixtures/implementation_results/0/dump +0 -0
  71. data/test/fixtures/theories/0/dump +0 -0
  72. data/test/fixtures/theories/1/dump +0 -0
  73. data/test/fixtures/theories/10/dump +0 -0
  74. data/test/fixtures/theories/11/dump +0 -0
  75. data/test/fixtures/theories/12/dump +0 -0
  76. data/test/fixtures/theories/13/declaration.txt +1 -1
  77. data/test/fixtures/theories/13/desc +1 -1
  78. data/test/fixtures/theories/13/dump +0 -0
  79. data/test/fixtures/theories/14/dump +0 -0
  80. data/test/fixtures/theories/15/dump +0 -0
  81. data/test/fixtures/theories/16/dump +0 -0
  82. data/test/fixtures/theories/17/dump +0 -0
  83. data/test/fixtures/theories/18/dump +0 -0
  84. data/test/fixtures/theories/19/dump +0 -0
  85. data/test/fixtures/theories/2/dump +0 -0
  86. data/test/fixtures/theories/20/declaration.txt +1 -1
  87. data/test/fixtures/theories/20/desc +1 -1
  88. data/test/fixtures/theories/20/dump +0 -0
  89. data/test/fixtures/theories/3/dump +0 -0
  90. data/test/fixtures/theories/4/dump +0 -0
  91. data/test/fixtures/theories/5/dump +0 -0
  92. data/test/fixtures/theories/6/dump +0 -0
  93. data/test/fixtures/theories/7/dump +0 -0
  94. data/test/fixtures/theories/8/dump +0 -0
  95. data/test/fixtures/theories/9/dump +0 -0
  96. data/test/fixtures/theory_implementations/0/declaration.txt +1 -1
  97. data/test/fixtures/theory_implementations/0/dump +0 -0
  98. data/test/fixtures/theory_implementations/1/declaration.txt +11 -0
  99. data/test/fixtures/theory_implementations/1/dump +0 -0
  100. data/test/fixtures/theory_implementations/2/declaration.txt +11 -0
  101. data/test/fixtures/theory_implementations/2/dump +0 -0
  102. data/test/output/simple_method.txt +0 -1
  103. data/test/tc_contextual_variables.rb +2 -41
  104. data/test/tc_describe.rb +1 -2
  105. data/test/tc_method.rb +2 -5
  106. data/test/unit/core/runtime_method/tc_realised_runtime_method.rb +5 -3
  107. data/test/unit/core/runtime_method/tc_runtime_method.rb +34 -56
  108. data/test/unit/core/statement/tc_block_statement.rb +2 -0
  109. data/test/unit/core/statement/tc_open_statement.rb +15 -6
  110. data/test/unit/core/statement/tc_statement.rb +4 -5
  111. data/test/unit/core/statement/tc_statement_dependencies.rb +1 -0
  112. data/test/unit/core/statement/tc_theory_statement.rb +2 -0
  113. data/test/unit/core/syntax/tc_if_container.rb +5 -5
  114. data/test/unit/core/tc_theory_generator_heavy.rb +1 -1
  115. data/test/unit/core/tracking/tc_history.rb +3 -1
  116. data/test/unit/core/variable/tc_method_parameter_variable.rb +2 -2
  117. data/test/unit/tc_chain_with_case_1.rb +1 -1
  118. data/test/unit/tc_method_usage.rb +1 -1
  119. data/test/unit/tc_theory.rb +8 -2
  120. data/test/unit/theory/tc_theory_action.rb +37 -5
  121. data/test/unit/theory/tc_theory_chain_validator.rb +3 -3
  122. data/test/unit/theory/tc_theory_connector.rb +2 -37
  123. data/test/unit/theory/tc_theory_dependent.rb +2 -0
  124. data/test/unit/theory/tc_theory_implementation.rb +5 -1
  125. data/test/unit/theory/tc_theory_result.rb +3 -2
  126. data/test/unit/util/tc_method_validation.rb +4 -1
  127. data/test/unit/util/tc_parser.rb +2 -0
  128. data/test/unit/util/tc_string_to_theory.rb +3 -2
  129. data/tmp/runtime_method_evaluation.rb +7 -4
  130. metadata +59 -13
  131. data/lib/core/syntax/IfContainer.rb +0 -100
@@ -12,12 +12,13 @@ class TheoryChainValidator
12
12
  def build(runtime_method,test_cases,theory_implementation_chains,potential_values=[])
13
13
  validated_chains = []
14
14
  theory_implementation_chains.each do |chain|
15
- validate_next_chain_link(validated_chains,chain,runtime_method.copy,test_cases,0)
15
+ validate_next_chain_link(validated_chains,chain,runtime_method.copy,test_cases.copy,0)
16
16
  end
17
17
  raise StandardError.new('Failed to generate a valid runtime method') if validated_chains.length == 0
18
18
 
19
19
  # Select the first chain and return the runtime method it generates
20
- return build_method_from_chain(validated_chains.first,runtime_method.copy,test_cases)
20
+ results = build_method_from_chain(validated_chains.first,runtime_method.copy,test_cases.copy)
21
+ return results
21
22
 
22
23
  end
23
24
 
@@ -27,6 +28,7 @@ class TheoryChainValidator
27
28
  # to the validated chain array.
28
29
  #
29
30
  def validate_next_chain_link(validated_chains,chain,runtime_method,test_cases,position)
31
+
30
32
  # Check that current link in the chain meets in dependencies
31
33
  # if its dependents are met it isn't suppose to work
32
34
  unless chain[position].meets_dependencies?(runtime_method.copy,test_cases.copy)
@@ -63,12 +65,12 @@ class TheoryChainValidator
63
65
  end
64
66
  else
65
67
  # Theory was wrong
66
- chain[position].results.each do |x|
67
- unless x.validates?(result,test_cases)
68
- StandardLogger.instance.info('The following result failed to be met')
69
- StandardLogger.instance.info(x.write)
70
- end
71
- end
68
+ # chain[position].results.each do |x|
69
+ # unless x.validates?(result,test_cases)
70
+ # StandardLogger.instance.info('The following result failed to be met')
71
+ # StandardLogger.instance.info(x.write)
72
+ # end
73
+ # end
72
74
  return nil
73
75
  end
74
76
 
@@ -24,6 +24,23 @@ module TheoryComponent
24
24
  return @statement.tokens
25
25
  end
26
26
 
27
+ def statements_with_variable(variable_id)
28
+
29
+ # Duplicate the current statement before it is rewritten
30
+ rewritten_statement = @statement.copy
31
+
32
+ # Find all containers of VariableDeclarations that declare a TheoryVariable
33
+ containers = [rewritten_statement].select_all {|x| x.respond_to?(:has?)}
34
+ theory_variable_containers = containers.select {|x| x.has? {|y| y.kind_of?(TheoryVariable)}}
35
+
36
+ results = theory_variable_containers.select do |x|
37
+ reg = eval '/var'+variable_id.to_s+'/'
38
+ x.write.match(reg)
39
+ end
40
+ return results
41
+
42
+ end
43
+
27
44
  # Returns an array of any of the accessors in the statement. An accessor
28
45
  # is the chain to access a property e.g. in the following statement =>
29
46
  #
@@ -38,6 +38,8 @@ class TheoryConnector
38
38
  #
39
39
  def generate_chains(runtime_method,test_cases,theories)
40
40
 
41
+ theories = remove_irrelevant_theories(theories)
42
+
41
43
  # Create the inital chain (with the head and tail)
42
44
  intial_chain = Chain.new
43
45
 
@@ -47,39 +49,104 @@ class TheoryConnector
47
49
  # Create the initial chains
48
50
  possible_chains = []
49
51
  possible_head_theories.each do |x|
50
- possible_chains += intial_chain.copy.add_link(x)
52
+ possible_chains += intial_chain.copy.extension_permutaions(x)
51
53
  end
52
-
54
+
53
55
  # Check the initial chains incase they're complete
54
56
  complete_chains = []
55
57
  if possible_chains.any? {|x| x.complete? }
56
58
  complete_chains += possible_chains.select {|x| x.complete?}
57
59
  possible_chains.delete_if {|x| x.complete?}
58
- end
60
+ end
61
+ return complete_chains unless complete_chains.empty?
59
62
 
60
- # Continue to add theories to the chains until they are complete or the theories are exhausted
61
- possible_chains.each do |x|
62
- complete_chains += extend_chain(x,theories)
63
+ possible_chains.each do |chain|
64
+
65
+ # Remove the head theory to avoid it being re-used
66
+ head_free_theories = theories.copy
67
+ head_free_theories.delete_if {|theory| theory.theory_id == chain.first.theory_id}
68
+
69
+ complete_chains += complete_chain(chain,head_free_theories)
63
70
  end
64
71
  return complete_chains
65
72
 
66
73
  end
67
74
 
68
- # TODO Need to watch out here for infinite chain connections
75
+ def complete_chain(chain,theories)
76
+ chains = converge_chain(chain,theories)
77
+ return chains
78
+
79
+ end
80
+
81
+ def converge_chain(chain,theories,step=0)
82
+
83
+ complete_chains = []
84
+ extended_chains = []
85
+ theories.each do |theory|
86
+ last_position = 1
87
+ chains = chain.add_link_to(theory,last_position,[])
88
+ next if chains.empty?
89
+ extended_chains += chains
90
+ end
91
+
92
+ # Are any of the chains complete
93
+ if extended_chains.any? {|x| x.complete? }
94
+ return extended_chains.select {|x| x.complete?}
95
+ end
96
+
97
+ closer_chains = []
98
+ extended_chains.each do |x|
99
+ if ((chain.unmet_dependents_ids-x.unmet_dependents_ids).length == chain.unmet_dependents_ids.length)
100
+ closer_chains << x
101
+ end
102
+ end
103
+
104
+ unless closer_chains.empty?
105
+ closer_chains.each do |x|
106
+ complete_chains += converge_chain(x,theories,step+1)
107
+ end
108
+ else
109
+ extended_chains.each do |x|
110
+ theories.each do |theory|
111
+ copied_chain = x.copy
112
+ last_position = 1
113
+ chains = copied_chain.add_link_to(theory,last_position,[])
114
+ chains.each do |z|
115
+ if ((chain.unmet_dependents_ids-z.unmet_dependents_ids).length == chain.unmet_dependents_ids.length)
116
+ complete_chains += converge_chain(z.copy,theories,step+1)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ return complete_chains
124
+ end
125
+
69
126
  def extend_chain(chain,theories)
127
+
70
128
  complete_chains = []
71
129
  theories.each do |x|
72
- extended_chains = chain.copy.add_link(x)
130
+ extended_chains = chain.copy.extension_permutaions(x)
73
131
  next if extended_chains.empty?
132
+
133
+ # Don't allow the same theory to be added twice - for now
134
+ updated_theories = theories.copy
135
+ updated_theories.delete_if {|theory| theory.theory_id == x.theory_id}
136
+
74
137
  complete_chains += extended_chains.select {|y| y.complete?}
75
138
  extended_chains.delete_if {|y| y.complete?}
76
139
  extended_chains.each do |y|
77
- complete_chains += extend_chain(y,theories)
140
+ complete_chains += extend_chain(y,updated_theories)
78
141
  end
79
142
  end
80
143
  return complete_chains
81
144
  end
82
145
 
146
+ def remove_irrelevant_theories(theories)
147
+ theories.delete_if {|theory| theory.irrelevant? }
148
+ end
149
+
83
150
  def create_possible_chains(runtime_method,test_cases,finish,theories)
84
151
 
85
152
  # Generate the head theory - this is the starting point and doesn't have any dependents
@@ -56,10 +56,10 @@ class TheoryDependent
56
56
  # the values in the mapping hash.
57
57
  #
58
58
  def map_to(mapping)
59
-
59
+
60
60
  # Duplicate the current statement before it is rewritten
61
61
  rewritten_statement = @statement.copy
62
-
62
+
63
63
  # Find all the containers that contain TheoryVariables
64
64
  # NOTE The statement is put in an array because select all doesn't include the array itself
65
65
  containers = [rewritten_statement].select_all {|x| x.respond_to?(:has?)}
@@ -63,12 +63,12 @@ class TheoryImplementation < Theory
63
63
  return false
64
64
  end
65
65
 
66
- # Returns all the theory vairables in this theory
67
- # dependent.
68
- #
69
- # TODO What is the point in this - why only the actions?
70
- def theory_variables
71
- return @action.select_all {|x| x.kind_of?(TheoryVariable)}
72
- end
66
+ # # Returns all the theory vairables in this theory
67
+ # # dependent.
68
+ # #
69
+ # # TODO What is the point in this - why only the actions?
70
+ # def theory_variables
71
+ # return @action.select_all {|x| x.kind_of?(TheoryVariable)}
72
+ # end
73
73
 
74
74
  end
@@ -4,10 +4,7 @@ class ClassEvaluation
4
4
  #include WriteParameters
5
5
  @@count = 0
6
6
 
7
- # TODO What is original_method about - can I get rid of it. I need to
8
- # pass through parameters.
9
- #
10
- def evaluate_class(runtime_class,runtime_call,original_method=nil)
7
+ def evaluate_class(runtime_class,runtime_call)
11
8
 
12
9
  # Create file to include the test method
13
10
  #filepath = $LOC+File.join(['tmp','runtime_class_evaluation.rb'])
@@ -24,7 +21,6 @@ class ClassEvaluation
24
21
  begin
25
22
  return eval("#{runtime_class.class_name}.new.#{runtime_call}")
26
23
  rescue NameError => e
27
- StandardLogger.instance.error(original_method.write()) unless original_method.nil?
28
24
  StandardLogger.instance.info(runtime_class.write)
29
25
  raise e
30
26
  end
@@ -43,7 +39,7 @@ class ClassEvaluation
43
39
  # Include the sytax for the statement in the file
44
40
  file << runtime_class.write
45
41
  file.close
46
-
42
+
47
43
  # Load the newly created class and check the statement
48
44
  load filepath
49
45
  begin
@@ -57,7 +53,6 @@ class ClassEvaluation
57
53
  raise StandardError.new('Can only handle one parameter right now')
58
54
  end
59
55
  rescue NameError => e
60
- StandardLogger.instance.error(original_method.write()) unless original_method.nil?
61
56
  StandardLogger.instance.info(runtime_class.write)
62
57
  raise e
63
58
  end
@@ -118,20 +118,24 @@ class MethodValidation
118
118
  )
119
119
  )
120
120
  # 5. return true if var_3.evaluate_class(var_2,var_1.method_name)<condition>
121
- test_method.push(
122
- Statement.new(
123
- Return.new,
124
- True.new,
125
- If.new,
121
+ s = Statement.new(
122
+ If.new,
123
+ Container.new(
126
124
  InstanceCallContainer.new(
127
125
  var_3,
128
126
  EvaluateClassCall.new,
129
127
  var_2,
130
128
  InstanceCallContainer.new(var_1,MethodNameCall.new)
131
129
  ),
132
- Raw.new(condition)
130
+ Raw.new(condition)
133
131
  )
134
132
  )
133
+ os = OpenStatement.new(s)
134
+ os << Statement.new(Return.new,True.new)
135
+ test_method.push(os)
136
+
137
+ #test_method.push(s)
138
+
135
139
  # 6. return false
136
140
  test_method.push(
137
141
  Statement.new(
@@ -119,25 +119,7 @@ class Parser
119
119
  end
120
120
 
121
121
  if sexp[0] == :if
122
- # TODO Look into the change in the nil position
123
- #
124
- # "if(var2 == var3)\nreturn true\nend"
125
- # s(:if, s(:call, s(:call, nil, :var2, s(:arglist)), :==, s(:arglist, s(:call, nil, :var3, s(:arglist)))), s(:return, s(:true)), nil)
126
- #
127
- # "if(var2 != var3)\nreturn true\nend"
128
- # s(:if, s(:call, s(:call, nil, :var2, s(:arglist)), :==, s(:arglist, s(:call, nil, :var3, s(:arglist)))), nil, s(:return, s(:true)))
129
- #
130
- internal_statements = (2...sexp.length).inject([]) do |total,x|
131
- total << sexp[x] unless sexp[x].nil?
132
- total
133
- end
134
- return OpenStatement.new(
135
- IfContainer.new(
136
- parse_token(sexp[1])
137
- ),
138
- *internal_statements.collect {|x| parse_token(x)}
139
- )
140
-
122
+ return self.parse_if(sexp)
141
123
  end
142
124
 
143
125
  if sexp[0] == :attrasgn
@@ -182,6 +164,29 @@ class Parser
182
164
  raise StandardError.new("Could not find sexp '#{sexp[0].to_s}'")
183
165
  end
184
166
 
167
+ def self.parse_if(sexp)
168
+ # TODO Look into the change in the nil position
169
+ #
170
+ # "if(var2 == var3)\nreturn true\nend"
171
+ # s(:if, s(:call, s(:call, nil, :var2, s(:arglist)), :==, s(:arglist, s(:call, nil, :var3, s(:arglist)))), s(:return, s(:true)), nil)
172
+ #
173
+ # "if(var2 != var3)\nreturn true\nend"
174
+ # s(:if, s(:call, s(:call, nil, :var2, s(:arglist)), :==, s(:arglist, s(:call, nil, :var3, s(:arglist)))), nil, s(:return, s(:true)))
175
+ #
176
+ internal_statements = (2...sexp.length).inject([]) do |total,x|
177
+ total << sexp[x] unless sexp[x].nil?
178
+ total
179
+ end
180
+ return OpenStatement.new(
181
+ Statement.new(
182
+ If.new,
183
+ Container.new(parse_token(sexp[1]))
184
+ ),
185
+ *internal_statements.collect {|x| parse_token(x)}
186
+ )
187
+
188
+ end
189
+
185
190
  def self.parse_simple_token(token)
186
191
  if token.to_s.match(/^var(\d+)$/)
187
192
  id = token.to_s.match(/^var(\d+)$/)[1].to_i
@@ -284,7 +289,8 @@ class Parser
284
289
  'statement_id' => 'StatementID',
285
290
  'last' => 'Last',
286
291
  'select' => 'Select',
287
- '-' => 'Subtract'
292
+ '-' => 'Subtract',
293
+ 'first' => 'First'
288
294
  }
289
295
  # TODO Need to re-structure code to better suit the parser and how it handles != statements
290
296
  if not affirmative
@@ -41,7 +41,7 @@ class StringToTheory < Parser
41
41
  def self.run(statement_string)
42
42
  statement_string.gsub!(/<runtime_method>/,'runtime_method')
43
43
  return super(statement_string)
44
-
44
+
45
45
  end
46
46
 
47
47
  # TODO This method is very similar to the Parser
@@ -69,17 +69,18 @@ class StringToTheory < Parser
69
69
  'Unknown'=>'UnknownClass',
70
70
  'Addition'=>'AdditionClass',
71
71
  'Equal'=>'EqualClass',
72
+ 'If'=>'IfClass',
72
73
  'RuntimeMethod'=>'RuntimeMethodClass',
73
74
  'CTestCase'=>'CTestCaseClass',
74
75
  'Fixnum'=>'FixnumClass',
75
76
  'Equivalent'=>'EquivalentClass',
76
77
  'OpenStatement'=>'OpenStatementClass',
77
- 'IfContainer'=>'IfContainerClass',
78
78
  'BlockStatement'=> 'BlockStatementClass',
79
79
  'Container'=> 'ContainerClass',
80
80
  'Subtract'=> 'SubtractClass',
81
81
  'Times'=> 'TimesClass',
82
- 'Chop'=> 'ChopClass'
82
+ 'Chop'=> 'ChopClass',
83
+ 'TheoryStatement'=> 'TheoryStatementClass'
83
84
  }
84
85
  raise StandardError.new('Unkown constant '+token.to_s) unless constants.has_key?(token.to_s)
85
86
  eval(constants[token.to_s]+'.new')
@@ -98,6 +99,29 @@ class StringToTheory < Parser
98
99
  end
99
100
  end
100
101
 
102
+ def self.parse_if(sexp)
103
+ # TODO Look into the change in the nil position
104
+ #
105
+ # "if(var2 == var3)\nreturn true\nend"
106
+ # s(:if, s(:call, s(:call, nil, :var2, s(:arglist)), :==, s(:arglist, s(:call, nil, :var3, s(:arglist)))), s(:return, s(:true)), nil)
107
+ #
108
+ # "if(var2 != var3)\nreturn true\nend"
109
+ # s(:if, s(:call, s(:call, nil, :var2, s(:arglist)), :==, s(:arglist, s(:call, nil, :var3, s(:arglist)))), nil, s(:return, s(:true)))
110
+ #
111
+ internal_statements = (2...sexp.length).inject([]) do |total,x|
112
+ total << sexp[x] unless sexp[x].nil?
113
+ total
114
+ end
115
+ return OpenStatement.new(
116
+ TheoryStatement.new(
117
+ If.new,
118
+ Container.new(parse_token(sexp[1]))
119
+ ),
120
+ *internal_statements.collect {|x| parse_token(x)}
121
+ )
122
+
123
+ end
124
+
101
125
  def self.parse_return(sexp)
102
126
  return TheoryStatement.new(
103
127
  *[sexp[0],sexp[1]].collect {|x| parse_token(x)}
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ module Cauldron
4
+
5
+ describe 'Chain' do
6
+
7
+ describe '#complete?' do
8
+ it 'chain is complete with just "return param1"' do
9
+ temp = Object.new
10
+ temp.extend(Cauldron::Demos)
11
+ demo = temp.demo_one
12
+ demo[:chain].complete?.should == true
13
+ end
14
+ it 'chain is complete with "if param1 == \'carrot\'"' do
15
+ temp = Object.new
16
+ temp.extend(Cauldron::Demos)
17
+ demo = temp.demo_two
18
+ demo[:chain].complete?.should == true
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ module Cauldron
4
+
5
+ describe 'Demos' do
6
+
7
+ describe '#demo_one' do
8
+ it 'can generate a demo that can generate a simple runtime method' do
9
+ temp = Object.new
10
+ temp.extend(Cauldron::Demos)
11
+ demo = temp.demo_one
12
+
13
+ # => TODO Don't like this coupling
14
+ Cauldron::Pot.new.demo_works?(demo).should == true
15
+ end
16
+ end
17
+
18
+ describe '#demo_two' do
19
+ it 'generates a demo that can return two different values' do
20
+ temp = Object.new
21
+ temp.extend(Cauldron::Demos)
22
+ demo = temp.demo_two
23
+
24
+ Cauldron::Pot.new.demo_works?(demo).should == true
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end