cauldron 0.1.0 → 0.1.1

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.
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