cauldron 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (398) hide show
  1. data/.document +5 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.txt +20 -0
  4. data/README +1 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/bin/cauldron +10 -0
  9. data/cauldron/.autotest +23 -0
  10. data/cauldron/History.txt +6 -0
  11. data/cauldron/Manifest.txt +8 -0
  12. data/cauldron/README.txt +57 -0
  13. data/cauldron/Rakefile +27 -0
  14. data/cauldron/bin/cauldron +3 -0
  15. data/cauldron/lib/cauldron.rb +3 -0
  16. data/cauldron/test/test_cauldron.rb +8 -0
  17. data/features/cauldron_example_cases.feature +13 -0
  18. data/features/cauldron_generates_runtime_method.feature +12 -0
  19. data/features/cauldron_start_terminal.feature +13 -0
  20. data/features/step_definitions/cauldron_steps.rb +16 -0
  21. data/features/step_definitions/terminal_steps.rb +34 -0
  22. data/features/support/env.rb +19 -0
  23. data/lib/Chain.rb +879 -0
  24. data/lib/ChainMapping.rb +172 -0
  25. data/lib/CodeHandler.rb +517 -0
  26. data/lib/Mapping.rb +26 -0
  27. data/lib/MappingValues.rb +24 -0
  28. data/lib/ScopeDependencies.rb +7 -0
  29. data/lib/Theory.rb +274 -0
  30. data/lib/UnifiedChain.rb +110 -0
  31. data/lib/cauldron.rb +6 -0
  32. data/lib/cauldron/conversion.rb +15 -0
  33. data/lib/cauldron/pot.rb +134 -0
  34. data/lib/cauldron/sexp2cauldron.rb +156 -0
  35. data/lib/cauldron/terminal.rb +120 -0
  36. data/lib/cauldron/theory_factory.rb +10 -0
  37. data/lib/core/ActsAsCode.rb +25 -0
  38. data/lib/core/BlockToken.rb +33 -0
  39. data/lib/core/CCall.rb +7 -0
  40. data/lib/core/CTestCase.rb +27 -0
  41. data/lib/core/ClassMethodCallContainer.rb +45 -0
  42. data/lib/core/Container.rb +85 -0
  43. data/lib/core/InstanceCallContainer.rb +272 -0
  44. data/lib/core/MethodUsage.rb +66 -0
  45. data/lib/core/PrintVariables.rb +25 -0
  46. data/lib/core/TheoryGenerator.rb +764 -0
  47. data/lib/core/Token.rb +7 -0
  48. data/lib/core/assignment/Assignment.rb +18 -0
  49. data/lib/core/assignment/Equal.rb +39 -0
  50. data/lib/core/assignment/Equivalent.rb +20 -0
  51. data/lib/core/assignment/NotEqual.rb +14 -0
  52. data/lib/core/call_container/CallContainer.rb +66 -0
  53. data/lib/core/class_method_call/New.rb +15 -0
  54. data/lib/core/class_method_call/RuntimeClassMethodCall.rb +31 -0
  55. data/lib/core/declaration/Declaration.rb +16 -0
  56. data/lib/core/declaration/LiteralDeclaration.rb +47 -0
  57. data/lib/core/declaration/VariableDeclaration.rb +59 -0
  58. data/lib/core/instance_call/ArrayEach.rb +23 -0
  59. data/lib/core/instance_call/ArrayLength.rb +15 -0
  60. data/lib/core/instance_call/Chop.rb +28 -0
  61. data/lib/core/instance_call/Copy.rb +22 -0
  62. data/lib/core/instance_call/DeclaredVariable.rb +18 -0
  63. data/lib/core/instance_call/InstanceCall.rb +77 -0
  64. data/lib/core/instance_call/Params.rb +15 -0
  65. data/lib/core/instance_call/Push.rb +20 -0
  66. data/lib/core/instance_call/StringLength.rb +32 -0
  67. data/lib/core/instance_call/Times.rb +20 -0
  68. data/lib/core/instance_call/instance_calls.rb +168 -0
  69. data/lib/core/instance_call/length_equal.rb +15 -0
  70. data/lib/core/kernal/EvalCall.rb +15 -0
  71. data/lib/core/kernal/LocalVariablesCall.rb +15 -0
  72. data/lib/core/literal/Literal.rb +111 -0
  73. data/lib/core/literal/Raw.rb +23 -0
  74. data/lib/core/literal/RuntimeMethodLiteral.rb +21 -0
  75. data/lib/core/literal/StatementLiteral.rb +28 -0
  76. data/lib/core/method_call/AvailableVariablesCall.rb +25 -0
  77. data/lib/core/method_call/ClassCall.rb +33 -0
  78. data/lib/core/method_call/DefCall.rb +72 -0
  79. data/lib/core/method_call/EvaluateClassCall.rb +29 -0
  80. data/lib/core/method_call/MethodNameCall.rb +27 -0
  81. data/lib/core/method_call/ToDeclarationCall.rb +15 -0
  82. data/lib/core/requirement/Requirement.rb +291 -0
  83. data/lib/core/runtime_class/ArrayClass.rb +19 -0
  84. data/lib/core/runtime_class/ClassCallClass.rb +23 -0
  85. data/lib/core/runtime_class/ClassEvaluationClass.rb +19 -0
  86. data/lib/core/runtime_class/ClassName.rb +18 -0
  87. data/lib/core/runtime_class/DefCallClass.rb +21 -0
  88. data/lib/core/runtime_class/EqualClass.rb +19 -0
  89. data/lib/core/runtime_class/FixnumClass.rb +15 -0
  90. data/lib/core/runtime_class/IfStatementClass.rb +12 -0
  91. data/lib/core/runtime_class/InstanceCallClass.rb +19 -0
  92. data/lib/core/runtime_class/InstanceCallContainerClass.rb +16 -0
  93. data/lib/core/runtime_class/InstanceClassCallClass.rb +19 -0
  94. data/lib/core/runtime_class/LiteralClass.rb +19 -0
  95. data/lib/core/runtime_class/MethodParameterClass.rb +27 -0
  96. data/lib/core/runtime_class/MethodUsageClass.rb +27 -0
  97. data/lib/core/runtime_class/RequirementClass.rb +19 -0
  98. data/lib/core/runtime_class/ReturnClass.rb +21 -0
  99. data/lib/core/runtime_class/RuntimeClass.rb +30 -0
  100. data/lib/core/runtime_class/RuntimeClassClass.rb +19 -0
  101. data/lib/core/runtime_class/RuntimeMethodClass.rb +34 -0
  102. data/lib/core/runtime_class/StatementClass.rb +53 -0
  103. data/lib/core/runtime_class/StringClass.rb +23 -0
  104. data/lib/core/runtime_class/StringLengthClass.rb +19 -0
  105. data/lib/core/runtime_class/StringVariableClass.rb +19 -0
  106. data/lib/core/runtime_class/ThisClass.rb +15 -0
  107. data/lib/core/runtime_class/UnknownClass.rb +23 -0
  108. data/lib/core/runtime_class/class_names.rb +95 -0
  109. data/lib/core/runtime_class/runtime_class.rb +123 -0
  110. data/lib/core/runtime_method/ActsAsRuntimeMethod.rb +300 -0
  111. data/lib/core/runtime_method/ParametersContainer.rb +29 -0
  112. data/lib/core/runtime_method/RealisedRuntimeMethod.rb +94 -0
  113. data/lib/core/runtime_method/RuntimeMethod.rb +817 -0
  114. data/lib/core/runtime_method/WriteParameters.rb +35 -0
  115. data/lib/core/statement/ActsAsStatement.rb +116 -0
  116. data/lib/core/statement/ArrayAccess.rb +96 -0
  117. data/lib/core/statement/BlockStatement.rb +348 -0
  118. data/lib/core/statement/DeclarationStatement.rb +19 -0
  119. data/lib/core/statement/HackStatement.rb +25 -0
  120. data/lib/core/statement/HashAccess.rb +18 -0
  121. data/lib/core/statement/OpenStatement.rb +171 -0
  122. data/lib/core/statement/RealisedStatement.rb +5 -0
  123. data/lib/core/statement/SingleLineBlockStatement.rb +39 -0
  124. data/lib/core/statement/Statement.rb +1223 -0
  125. data/lib/core/statement/StatementDependencies.rb +271 -0
  126. data/lib/core/statement/StatementGroup.rb +157 -0
  127. data/lib/core/statement/StatementStructure2.rb +224 -0
  128. data/lib/core/statement/TheoryStatement.rb +60 -0
  129. data/lib/core/statement/TopologicalStatements.rb +34 -0
  130. data/lib/core/structure/DeclareNewInstanceStructure.rb +49 -0
  131. data/lib/core/structure/DeclareRuntimeMethodStructure.rb +34 -0
  132. data/lib/core/structure/DeclareVariableAsLiteralStructure.rb +31 -0
  133. data/lib/core/structure/DeclareVariableAsVariableStructure.rb +52 -0
  134. data/lib/core/structure/FixnumAdditionStructure.rb +56 -0
  135. data/lib/core/structure/InstanceCallContainerStructure.rb +50 -0
  136. data/lib/core/structure/InstanceCallStructure.rb +53 -0
  137. data/lib/core/structure/InstanceMethodCallStructure.rb +21 -0
  138. data/lib/core/structure/ReturnStructure.rb +20 -0
  139. data/lib/core/structure/StatementStructure.rb +11 -0
  140. data/lib/core/syntax/Addition.rb +25 -0
  141. data/lib/core/syntax/BlockContainer.rb +130 -0
  142. data/lib/core/syntax/Boolean.rb +15 -0
  143. data/lib/core/syntax/Code.rb +11 -0
  144. data/lib/core/syntax/Do.rb +20 -0
  145. data/lib/core/syntax/False.rb +12 -0
  146. data/lib/core/syntax/If.rb +28 -0
  147. data/lib/core/syntax/IfContainer.rb +100 -0
  148. data/lib/core/syntax/Nil.rb +15 -0
  149. data/lib/core/syntax/Return.rb +33 -0
  150. data/lib/core/syntax/Subtract.rb +19 -0
  151. data/lib/core/syntax/This.rb +40 -0
  152. data/lib/core/syntax/True.rb +20 -0
  153. data/lib/core/syntax/syntax.rb +24 -0
  154. data/lib/core/tracking/ActsAsTrackable.rb +65 -0
  155. data/lib/core/tracking/History.rb +167 -0
  156. data/lib/core/tracking/RuntimeTrackingMethod.rb +32 -0
  157. data/lib/core/tracking/Step.rb +52 -0
  158. data/lib/core/variable/ArrayVariable.rb +76 -0
  159. data/lib/core/variable/BaseVariable.rb +154 -0
  160. data/lib/core/variable/BlockVariable.rb +92 -0
  161. data/lib/core/variable/FixnumVariable.rb +36 -0
  162. data/lib/core/variable/HistoryVariable.rb +8 -0
  163. data/lib/core/variable/MethodParameter.rb +206 -0
  164. data/lib/core/variable/MethodUsageVariable.rb +60 -0
  165. data/lib/core/variable/NilVariable.rb +29 -0
  166. data/lib/core/variable/RuntimeMethodParameter.rb +67 -0
  167. data/lib/core/variable/StatementVariable.rb +72 -0
  168. data/lib/core/variable/StepVariable.rb +7 -0
  169. data/lib/core/variable/StringVariable.rb +46 -0
  170. data/lib/core/variable/TypeVariable.rb +72 -0
  171. data/lib/core/variable/Unknown.rb +116 -0
  172. data/lib/core/variable/UnknownVariable.rb +29 -0
  173. data/lib/core/variable/Variable.rb +70 -0
  174. data/lib/core/variable/VariableContainer.rb +28 -0
  175. data/lib/core/variable/VariableIncluded.rb +27 -0
  176. data/lib/core/variable/VariableReference.rb +85 -0
  177. data/lib/error/FailedToFindStatementContainerError.rb +7 -0
  178. data/lib/error/FailedToFindStatementError.rb +7 -0
  179. data/lib/error/FailedToFindVariableError.rb +7 -0
  180. data/lib/error/FailedToLiteraliseError.rb +7 -0
  181. data/lib/error/FailedVariableMatch.rb +7 -0
  182. data/lib/error/ImproperStatementUsageError.rb +7 -0
  183. data/lib/error/IncompatiableRequirementsError.rb +7 -0
  184. data/lib/error/InvalidStatementError.rb +7 -0
  185. data/lib/error/MethodSizeError.rb +7 -0
  186. data/lib/error/RuntimeSyntaxError.rb +7 -0
  187. data/lib/error/UnexpectedStatementTypeError.rb +7 -0
  188. data/lib/error/UnknownStatementType.rb +7 -0
  189. data/lib/error/UnliteralisableError.rb +7 -0
  190. data/lib/implemented_chain.rb +34 -0
  191. data/lib/intrinsic/IntrinsicLastRuntimeMethod.rb +20 -0
  192. data/lib/intrinsic/IntrinsicLiteral.rb +26 -0
  193. data/lib/intrinsic/IntrinsicObject.rb +22 -0
  194. data/lib/intrinsic/IntrinsicRuntimeMethod.rb +27 -0
  195. data/lib/intrinsic/IntrinsicTestCases.rb +17 -0
  196. data/lib/logger/StandardLogger.rb +62 -0
  197. data/lib/required.rb +236 -0
  198. data/lib/ruby_code/Array.rb +95 -0
  199. data/lib/ruby_code/Fixnum.rb +39 -0
  200. data/lib/ruby_code/Hash.rb +25 -0
  201. data/lib/ruby_code/NilClass.rb +19 -0
  202. data/lib/ruby_code/Object.rb +24 -0
  203. data/lib/ruby_code/String.rb +86 -0
  204. data/lib/ruby_code/Symbol.rb +7 -0
  205. data/lib/standard_library/Tasks.rb +12 -0
  206. data/lib/theories.rb +143 -0
  207. data/lib/theory/ActionImplementation.rb +17 -0
  208. data/lib/theory/TheoryAction.rb +70 -0
  209. data/lib/theory/TheoryChainValidator.rb +101 -0
  210. data/lib/theory/TheoryComponent.rb +42 -0
  211. data/lib/theory/TheoryConnector.rb +755 -0
  212. data/lib/theory/TheoryDependent.rb +135 -0
  213. data/lib/theory/TheoryImplementation.rb +74 -0
  214. data/lib/theory/TheoryResult.rb +131 -0
  215. data/lib/theory/TheoryVariable.rb +63 -0
  216. data/lib/theory/theory_collection.rb +62 -0
  217. data/lib/util/ClassEvaluation.rb +68 -0
  218. data/lib/util/CodeEvaluation.rb +35 -0
  219. data/lib/util/DeclarationStatementEvaluation.rb +31 -0
  220. data/lib/util/MethodEvaluation.rb +49 -0
  221. data/lib/util/MethodTester.rb +71 -0
  222. data/lib/util/MethodValidation.rb +145 -0
  223. data/lib/util/MethodWriter.rb +66 -0
  224. data/lib/util/Parser.rb +299 -0
  225. data/lib/util/StatementCheck.rb +42 -0
  226. data/lib/util/StringToTheory.rb +119 -0
  227. data/lib/util/System.rb +8 -0
  228. data/spec/cauldron/pot_spec.rb +6 -0
  229. data/spec/cauldron/runtime_method_spec.rb +36 -0
  230. data/spec/cauldron/sexp_2_cauldron_spec.rb +26 -0
  231. data/spec/cauldron/terminal_spec.rb +38 -0
  232. data/spec/cauldron/theory_action_spec.rb +5 -0
  233. data/spec/spec_helper.rb +4 -0
  234. data/test/fixtures/chains/1/declaration.txt +26 -0
  235. data/test/fixtures/chains/1/dump +0 -0
  236. data/test/fixtures/chains/2/declaration.txt +26 -0
  237. data/test/fixtures/chains/2/dump +0 -0
  238. data/test/fixtures/chains/3/declaration.txt +26 -0
  239. data/test/fixtures/chains/3/dump +0 -0
  240. data/test/fixtures/implementation_results/0/declaration.txt +3 -0
  241. data/test/fixtures/implementation_results/0/dump +0 -0
  242. data/test/fixtures/theories/0/declaration.txt +9 -0
  243. data/test/fixtures/theories/0/desc +10 -0
  244. data/test/fixtures/theories/0/dump +0 -0
  245. data/test/fixtures/theories/1/declaration.txt +15 -0
  246. data/test/fixtures/theories/1/desc +11 -0
  247. data/test/fixtures/theories/1/dump +0 -0
  248. data/test/fixtures/theories/10/declaration.txt +23 -0
  249. data/test/fixtures/theories/10/desc +17 -0
  250. data/test/fixtures/theories/10/dump +0 -0
  251. data/test/fixtures/theories/11/declaration.txt +20 -0
  252. data/test/fixtures/theories/11/desc +14 -0
  253. data/test/fixtures/theories/11/dump +0 -0
  254. data/test/fixtures/theories/12/declaration.txt +18 -0
  255. data/test/fixtures/theories/12/desc +12 -0
  256. data/test/fixtures/theories/12/dump +0 -0
  257. data/test/fixtures/theories/13/declaration.txt +24 -0
  258. data/test/fixtures/theories/13/desc +20 -0
  259. data/test/fixtures/theories/13/dump +0 -0
  260. data/test/fixtures/theories/14/declaration.txt +26 -0
  261. data/test/fixtures/theories/14/desc +20 -0
  262. data/test/fixtures/theories/14/dump +0 -0
  263. data/test/fixtures/theories/15/declaration.txt +20 -0
  264. data/test/fixtures/theories/15/desc +14 -0
  265. data/test/fixtures/theories/15/dump +0 -0
  266. data/test/fixtures/theories/16/declaration.txt +30 -0
  267. data/test/fixtures/theories/16/desc +14 -0
  268. data/test/fixtures/theories/16/dump +0 -0
  269. data/test/fixtures/theories/17/declaration.txt +25 -0
  270. data/test/fixtures/theories/17/desc +11 -0
  271. data/test/fixtures/theories/17/dump +0 -0
  272. data/test/fixtures/theories/18/declaration.txt +23 -0
  273. data/test/fixtures/theories/18/desc +11 -0
  274. data/test/fixtures/theories/18/dump +0 -0
  275. data/test/fixtures/theories/19/declaration.txt +23 -0
  276. data/test/fixtures/theories/19/desc +11 -0
  277. data/test/fixtures/theories/19/dump +0 -0
  278. data/test/fixtures/theories/2/declaration.txt +12 -0
  279. data/test/fixtures/theories/2/desc +10 -0
  280. data/test/fixtures/theories/2/dump +0 -0
  281. data/test/fixtures/theories/20/declaration.txt +23 -0
  282. data/test/fixtures/theories/20/desc +17 -0
  283. data/test/fixtures/theories/20/dump +0 -0
  284. data/test/fixtures/theories/3/declaration.txt +19 -0
  285. data/test/fixtures/theories/3/desc +11 -0
  286. data/test/fixtures/theories/3/dump +0 -0
  287. data/test/fixtures/theories/4/declaration.txt +11 -0
  288. data/test/fixtures/theories/4/desc +11 -0
  289. data/test/fixtures/theories/4/dump +0 -0
  290. data/test/fixtures/theories/5/declaration.txt +6 -0
  291. data/test/fixtures/theories/5/desc +9 -0
  292. data/test/fixtures/theories/5/dump +0 -0
  293. data/test/fixtures/theories/6/declaration.txt +13 -0
  294. data/test/fixtures/theories/6/desc +11 -0
  295. data/test/fixtures/theories/6/dump +0 -0
  296. data/test/fixtures/theories/7/declaration.txt +19 -0
  297. data/test/fixtures/theories/7/desc +11 -0
  298. data/test/fixtures/theories/7/dump +0 -0
  299. data/test/fixtures/theories/8/declaration.txt +21 -0
  300. data/test/fixtures/theories/8/desc +11 -0
  301. data/test/fixtures/theories/8/dump +0 -0
  302. data/test/fixtures/theories/9/declaration.txt +24 -0
  303. data/test/fixtures/theories/9/desc +20 -0
  304. data/test/fixtures/theories/9/dump +0 -0
  305. data/test/fixtures/theory_implementations/0/declaration.txt +11 -0
  306. data/test/fixtures/theory_implementations/0/desc.txt +9 -0
  307. data/test/fixtures/theory_implementations/0/dump +0 -0
  308. data/test/fixtures/theory_implementations/0/theory_id +1 -0
  309. data/test/fixtures/theory_implementations/1/desc.txt +9 -0
  310. data/test/fixtures/theory_implementations/1/dump +0 -0
  311. data/test/fixtures/theory_implementations/1/theory_id +1 -0
  312. data/test/fixtures/theory_implementations/2/desc.txt +9 -0
  313. data/test/fixtures/theory_implementations/2/dump +0 -0
  314. data/test/fixtures/theory_implementations/2/theory_id +1 -0
  315. data/test/output/simple_method.txt +6 -0
  316. data/test/output/test_method/first_possible_method.txt +6 -0
  317. data/test/output/test_simple_cases/simple_case_01.txt +8 -0
  318. data/test/output/test_simple_cases/simple_case_02.txt +7 -0
  319. data/test/output/test_simple_cases/simple_case_03.txt +8 -0
  320. data/test/output/test_simple_cases/simple_case_04.txt +8 -0
  321. data/test/output/test_simple_cases/simple_case_05.txt +8 -0
  322. data/test/output/test_simple_cases/simple_case_06.txt +9 -0
  323. data/test/output/test_simple_cases/simple_case_07.txt +9 -0
  324. data/test/output/test_simple_cases/simple_case_08.txt +9 -0
  325. data/test/tc_contextual_variables.rb +87 -0
  326. data/test/tc_describe.rb +47 -0
  327. data/test/tc_method.rb +133 -0
  328. data/test/tc_requirement.rb +30 -0
  329. data/test/tc_suite_complete.rb +26 -0
  330. data/test/tc_variable.rb +52 -0
  331. data/test/ts_complete.rb +84 -0
  332. data/test/ts_stable.rb +81 -0
  333. data/test/unit/core/declaration/tc_literal_declaration.rb +34 -0
  334. data/test/unit/core/method_call/tc_class_call.rb +20 -0
  335. data/test/unit/core/runtime_method/tc_realised_runtime_method.rb +129 -0
  336. data/test/unit/core/runtime_method/tc_runtime_method.rb +616 -0
  337. data/test/unit/core/statement/tc_array_access.rb +63 -0
  338. data/test/unit/core/statement/tc_block_statement.rb +51 -0
  339. data/test/unit/core/statement/tc_hack_statement.rb +26 -0
  340. data/test/unit/core/statement/tc_open_statement.rb +70 -0
  341. data/test/unit/core/statement/tc_statement.rb +681 -0
  342. data/test/unit/core/statement/tc_statement_dependencies.rb +146 -0
  343. data/test/unit/core/statement/tc_statement_group.rb +35 -0
  344. data/test/unit/core/statement/tc_statement_replace_variable.rb +61 -0
  345. data/test/unit/core/statement/tc_theory_statement.rb +51 -0
  346. data/test/unit/core/structure/tc_declare_new_instance_structure.rb +41 -0
  347. data/test/unit/core/structure/tc_declare_variable_as_literal_structure.rb +41 -0
  348. data/test/unit/core/structure/tc_declare_variable_as_variable_structure.rb +66 -0
  349. data/test/unit/core/structure/tc_instance_call_container_structure.rb +41 -0
  350. data/test/unit/core/structure/tc_return_structure.rb +32 -0
  351. data/test/unit/core/syntax/tc_block_container.rb +32 -0
  352. data/test/unit/core/syntax/tc_if_container.rb +39 -0
  353. data/test/unit/core/tc_class_method_call.rb +34 -0
  354. data/test/unit/core/tc_container.rb +41 -0
  355. data/test/unit/core/tc_ctest_case.rb +25 -0
  356. data/test/unit/core/tc_instance_call_container.rb +93 -0
  357. data/test/unit/core/tc_literal.rb +30 -0
  358. data/test/unit/core/tc_theory_generator.rb +336 -0
  359. data/test/unit/core/tc_theory_generator_heavy.rb +42 -0
  360. data/test/unit/core/tracking/tc_history.rb +102 -0
  361. data/test/unit/core/tracking/tc_step.rb +65 -0
  362. data/test/unit/core/variable/tc_array_variable.rb +61 -0
  363. data/test/unit/core/variable/tc_block_variable.rb +17 -0
  364. data/test/unit/core/variable/tc_fixnum_variable.rb +54 -0
  365. data/test/unit/core/variable/tc_method_parameter_variable.rb +22 -0
  366. data/test/unit/core/variable/tc_runtime_method_variable.rb +32 -0
  367. data/test/unit/core/variable/tc_string_variable.rb +37 -0
  368. data/test/unit/core/variable/tc_unknown.rb +24 -0
  369. data/test/unit/core/variable/tc_variable_reference.rb +28 -0
  370. data/test/unit/ruby_code/tc_array.rb +64 -0
  371. data/test/unit/ruby_code/tc_fixnum.rb +18 -0
  372. data/test/unit/ruby_code/tc_hash.rb +41 -0
  373. data/test/unit/ruby_code/tc_string.rb +38 -0
  374. data/test/unit/tc_chain.rb +434 -0
  375. data/test/unit/tc_chain_mapping.rb +62 -0
  376. data/test/unit/tc_chain_with_case_1.rb +169 -0
  377. data/test/unit/tc_instance_call.rb +40 -0
  378. data/test/unit/tc_instance_call_structure.rb +35 -0
  379. data/test/unit/tc_method_usage.rb +35 -0
  380. data/test/unit/tc_pot.rb +124 -0
  381. data/test/unit/tc_runtime_tracking_method.rb +40 -0
  382. data/test/unit/tc_statement_structure_2.rb +43 -0
  383. data/test/unit/tc_theory.rb +533 -0
  384. data/test/unit/tc_variable_declaration.rb +32 -0
  385. data/test/unit/theory/tc_theory_action.rb +80 -0
  386. data/test/unit/theory/tc_theory_action_implementation.rb +23 -0
  387. data/test/unit/theory/tc_theory_chain_validator.rb +340 -0
  388. data/test/unit/theory/tc_theory_connector.rb +396 -0
  389. data/test/unit/theory/tc_theory_dependent.rb +151 -0
  390. data/test/unit/theory/tc_theory_implementation.rb +133 -0
  391. data/test/unit/theory/tc_theory_result.rb +111 -0
  392. data/test/unit/theory/tc_theory_variable.rb +45 -0
  393. data/test/unit/util/tc_method_validation.rb +98 -0
  394. data/test/unit/util/tc_parser.rb +108 -0
  395. data/test/unit/util/tc_string_to_theory.rb +299 -0
  396. data/test/unit/variable/tc_method_usage_variable.rb +25 -0
  397. data/tmp/runtime_method_evaluation.rb +10 -0
  398. metadata +522 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "bundler", "~> 1.0.15"
11
+ gem "jeweler", "~> 1.6.2"
12
+ gem "rcov", ">= 0"
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 theinbetweens
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1 @@
1
+ # Comming soon
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = cauldron
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to cauldron
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
+ * Fork the project
10
+ * Start a feature/bugfix branch
11
+ * Commit and push until you are happy with your contribution
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 theinbetweens. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "cauldron"
18
+ gem.homepage = "http://github.com/theinbetweens/cauldron"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Generate simple ruby methods from the input(s) and expected output}
21
+ gem.description = %Q{Cauldron generates a methd from a number of examples that describe the input and the expected output. It is still at a very early stage of development right now so you're unlikely to get much practical use out of it.}
22
+ gem.email = "warrensangster@yahoo.com"
23
+ gem.authors = ["Warren Sangster"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "cauldron #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/cauldron ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib',__FILE__)
4
+
5
+ require 'cauldron'
6
+
7
+ StandardLogger.instance.level = Logger::FATAL
8
+
9
+ cauldron = Cauldron::Terminal.new(STDOUT,false)
10
+ cauldron.start
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2011-06-08
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
@@ -0,0 +1,8 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/cauldron
7
+ lib/cauldron.rb
8
+ test/test_cauldron.rb
@@ -0,0 +1,57 @@
1
+ = cauldron
2
+
3
+ * FIX (url)
4
+
5
+ == DESCRIPTION:
6
+
7
+ FIX (describe your package)
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * FIX (list of features or problems)
12
+
13
+ == SYNOPSIS:
14
+
15
+ FIX (code sample of usage)
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * FIX (list of requirements)
20
+
21
+ == INSTALL:
22
+
23
+ * FIX (sudo gem install, anything else)
24
+
25
+ == DEVELOPERS:
26
+
27
+ After checking out the source, run:
28
+
29
+ $ rake newb
30
+
31
+ This task will install any missing dependencies, run the tests/specs,
32
+ and generate the RDoc.
33
+
34
+ == LICENSE:
35
+
36
+ (The MIT License)
37
+
38
+ Copyright (c) 2011 FIX
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining
41
+ a copy of this software and associated documentation files (the
42
+ 'Software'), to deal in the Software without restriction, including
43
+ without limitation the rights to use, copy, modify, merge, publish,
44
+ distribute, sublicense, and/or sell copies of the Software, and to
45
+ permit persons to whom the Software is furnished to do so, subject to
46
+ the following conditions:
47
+
48
+ The above copyright notice and this permission notice shall be
49
+ included in all copies or substantial portions of the Software.
50
+
51
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
52
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
54
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
55
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
56
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
57
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/cauldron/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ # Hoe.plugin :compiler
7
+ # Hoe.plugin :compiler
8
+ # Hoe.plugin :gem_prelude_sucks
9
+ # Hoe.plugin :gem_prelude_sucks
10
+ # Hoe.plugin :inline
11
+ # Hoe.plugin :inline
12
+ # Hoe.plugin :racc
13
+ # Hoe.plugin :racc
14
+ # Hoe.plugin :rubyforge
15
+ # Hoe.plugin :rubyforge
16
+
17
+ Hoe.spec 'cauldron' do
18
+ # HEY! If you fill these out in ~/.hoe_template/Rakefile.erb then
19
+ # you'll never have to touch them again!
20
+ # (delete this comment too, of course)
21
+
22
+ # developer('FIX', 'FIX@example.com')
23
+
24
+ # self.rubyforge_name = 'cauldronx' # if different than 'cauldron'
25
+ end
26
+
27
+ # vim: syntax=ruby
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
@@ -0,0 +1,3 @@
1
+ class Cauldron
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,8 @@
1
+ require "test/unit"
2
+ require "cauldron"
3
+
4
+ class TestCauldron < Test::Unit::TestCase
5
+ def test_sanity
6
+ flunk "write tests or I will kneecap you"
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ Feature: User enters example cases
2
+ The user enters a number of example cases that get saved to be ran later
3
+
4
+ Scenario Outline: add test cases
5
+ Given that the terminal has been started
6
+ When I add the case "<case>"
7
+ Then the case "<case>" should be saved
8
+
9
+ Scenarios: single paramerter cases
10
+ | case |
11
+ | 'sparky', 'spark' |
12
+ | 'kel', 'kel' |
13
+
@@ -0,0 +1,12 @@
1
+ Feature: Cauldron generates a runtime method
2
+ I want a runtime method
3
+ That will solve a set of example cases
4
+
5
+ Scenario Outline: Generate a solution to a previously solved problem
6
+ Given that the terminal has been created
7
+ When I add these <cases>
8
+ Then I should receive a runtime method like this <runtime_method>
9
+
10
+ Scenarios: example with only one parameter
11
+ | cases | runtime_method | demo_num |
12
+ | "'sparky','sparky'*'kel','kel'" | "def method_3(var_6)\n\treturn var_6\nend\n" | 1 |
@@ -0,0 +1,13 @@
1
+ Feature: Cauldron starts on the command line
2
+ I want cauldron to start
3
+ So that I can describe the method I want it generate
4
+ Scenario: start cauldron
5
+ When I start cauldron
6
+ Then I should see "Thanks for trying Cauldron - it's at really early stage right now"
7
+ And then I should see "To start enter your first test like this"
8
+ And then I should see "input,input,output"
9
+ And then I should see "For example "
10
+ And then I should see "'fish','animal'"
11
+ And then I should see "'cat','animal'"
12
+ And then I should see "'carrot','vegtable'"
13
+ And then I should see "and when you're done just type RUN"
@@ -0,0 +1,16 @@
1
+
2
+ When /^I add these "([^"]*)"$/ do |test_cases_statement|
3
+ test_cases = test_cases_statement.split('*')
4
+ test_cases.each do |x|
5
+ @terminal.submit x
6
+ end
7
+ end
8
+
9
+ Then /^I should receive a runtime method like this "([^"]*)"$/ do |runtime_method_statement|
10
+ runtime_method_statement = runtime_method_statement.gsub('\\n',"\n").gsub('\\t',"\t")
11
+ #@terminal.submit('RUN').should == runtime_method_statement
12
+ @terminal.submit('RUN')
13
+ output.messages.should include(runtime_method_statement)
14
+ end
15
+
16
+
@@ -0,0 +1,34 @@
1
+
2
+ include Cauldron::Conversion
3
+
4
+ Given /^that the terminal has been created$/ do
5
+ @terminal = Cauldron::Terminal.new(output)
6
+ @terminal.start
7
+ end
8
+
9
+
10
+ When /^I start cauldron$/ do
11
+ @terminal = Cauldron::Terminal.new(output)
12
+ @terminal.start
13
+ end
14
+
15
+ Then /^I should see "([^"]*)"$/ do |message|
16
+ output.messages.should include(message)
17
+ end
18
+
19
+ Then /^then I should see "([^"]*)"$/ do |message|
20
+ output.messages.should include(message)
21
+ end
22
+
23
+ When /^I add the case "([^"]*)"$/ do |test_case|
24
+ @terminal.submit test_case
25
+ end
26
+
27
+ Given /^that the terminal has been started$/ do
28
+ @terminal = Cauldron::Terminal.new(output)
29
+ @terminal.start
30
+ end
31
+
32
+ Then /^the case "([^"]*)" should be saved$/ do |test_case|
33
+ @terminal.cases.should include(convert_to_example(separate_values(test_case)))
34
+ end
@@ -0,0 +1,19 @@
1
+ $LOAD_PATH << File.expand_path('../../../lib',__FILE__)
2
+
3
+ require 'cauldron'
4
+
5
+ class Output
6
+
7
+ def messages
8
+ @messages ||= []
9
+ end
10
+
11
+ def puts(message)
12
+ messages << message
13
+ end
14
+
15
+ end
16
+
17
+ def output
18
+ @output ||= Output.new
19
+ end
data/lib/Chain.rb ADDED
@@ -0,0 +1,879 @@
1
+ require "logger"
2
+ class Chain
3
+ # TODO This access is proably temporary
4
+ attr_reader :chain_mapping
5
+
6
+ #
7
+ # @param nodes An array of theories in order
8
+ #
9
+ def initialize()
10
+ @values, @nodes = {}, []
11
+
12
+ # Create an array of possible ids for any theories added
13
+ @uniq_theory_instance_ids = ('A'...'Z').to_a
14
+
15
+ # Create a result version of 'finish'
16
+ finish = Parser.run("if(runtime_method.all_pass?(test_cases))\nreturn true\nend")
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))
21
+ # TODO Drop @tail_theory as a instance variable
22
+ @tail_theory = Theory.new([tail_dependent],nil,[])
23
+
24
+ # NOTE: Now the head and tail are using the same ids for their variables
25
+ @chain_mapping = ChainMapping.new()
26
+
27
+ # Get the value mappings for the chain
28
+ tc = Parser.run('test_cases')
29
+ real_method = Parser.run('runtime_method')
30
+
31
+ # Add the tail to the nodes list
32
+ add_link(@tail_theory,{1=>real_method,2=>tc})
33
+
34
+ end
35
+
36
+ # TODO I want to drop allot of these quick methods
37
+ def <<(node)
38
+ @nodes << node
39
+ end
40
+
41
+ def length
42
+ return @nodes.length
43
+ end
44
+
45
+ def each(&block)
46
+ @nodes.each(&block)
47
+ end
48
+
49
+ def [](index)
50
+ return @nodes[index]
51
+ end
52
+
53
+ def first
54
+ return @nodes.first
55
+ end
56
+
57
+ def last
58
+ return @nodes.last
59
+ end
60
+
61
+ def reverse
62
+ return Chain.new(@nodes.reverse)
63
+ end
64
+
65
+ def shift
66
+ return @nodes.shift
67
+ end
68
+
69
+ def copy
70
+ #return Chain.new(@nodes.copy)
71
+ return Marshal.load(Marshal.dump(self))
72
+ end
73
+
74
+ def empty?
75
+ return @nodes.empty?
76
+ end
77
+
78
+ def pop
79
+ return @nodes.pop
80
+ end
81
+
82
+ def collect(&block)
83
+ return @nodes.collect(&block)
84
+ end
85
+
86
+ def write(tab=0)
87
+ return @nodes.inject('') {|total,x| total += x.write}
88
+ end
89
+
90
+ def describe(tab=0)
91
+ return @nodes.inject('') {|total,x| total += x.describe}
92
+ end
93
+
94
+ # Returns an array of all the unique theory variables used within
95
+ # the chain.
96
+ #
97
+ # e.g. [0,6,7]
98
+ #
99
+ def uniq_theory_variable_ids
100
+ return @nodes.inject([]) do |total,theory|
101
+ total = total | theory.all_theory_variables.collect {|x| x.theory_variable_id}
102
+ end
103
+ end
104
+
105
+ # Returns a new chain where they are all using the same respective theory
106
+ # variables.
107
+ #
108
+ # TODO This seems to create implemented theories - I'm not sure this is what I want
109
+ #
110
+ def unify_chain
111
+ unless complete?
112
+ raise StandardError.new('Only complete chains can be unified')
113
+ end
114
+ unified_theories = @nodes.inject([]) do |total,theory|
115
+ mapping = generate_theory_mapping(theory.theory_instance_id)
116
+ total.push theory.map_to(mapping)
117
+ end
118
+ return UnifiedChain.new(unified_theories)
119
+ end
120
+
121
+ # DEVELOPMENT
122
+ # Because I'm using Marshal to restore some of the theories I just need to check that
123
+ # none of the components have duplicate ids.
124
+ #
125
+ def duplicate_component_ids?
126
+ collection = TheoryCollection.new(@nodes)
127
+ component_ids = collection.components.inject([]) {|total,x| total << x.theory_component_id }
128
+ return (component_ids.length != component_ids.uniq.length)
129
+ end
130
+
131
+ # Returns the number of breaks in the chain - this is essential the number of
132
+ # unmet depements.
133
+ #
134
+ def broken_link_count
135
+ collection = TheoryCollection.new(@nodes)
136
+ return collection.dependents.inject(0) do |total,dependent|
137
+ unless @chain_mapping.connected_component_ids.include?(dependent.theory_component_id)
138
+ total += 1
139
+ end
140
+ total
141
+ end
142
+ end
143
+
144
+ # TODO Really need a method to highlight what is connected to what
145
+
146
+ # DEVELOPMENT
147
+ # Writes out the chain but highlights any of links in the chain weren't connected
148
+ # to a dependent.
149
+ #
150
+ def highlight_broken_links
151
+ if duplicate_component_ids?
152
+ StandardLogger.instance.warning('You are using theories that share the same component_id')
153
+ end
154
+ unmet = []
155
+ each_unmet(:dependents,0,@nodes) do |index,theory,dependent|
156
+ unmet << dependent.theory_component_id
157
+ end
158
+ return @nodes.inject('') {|msg,x| msg += x.highlight(unmet)}
159
+ end
160
+
161
+ # Attempts to add a new link to form a complete chain between the head and tail. It starts
162
+ # by linking to the tail and then head.
163
+ #
164
+ # TODO This needs to return an array of chains indicating the various permutation they
165
+ # could be connected.
166
+ #
167
+ # TODO link_permutations mighht be a more appropriate name
168
+ #
169
+ def add_link(theory,value_mapping=nil)
170
+
171
+ # Give the theory an instance id
172
+ theory = theory.copy
173
+ raise StandardError.new('Reached limit to chains length') if @uniq_theory_instance_ids.empty?
174
+ theory.theory_instance_id = @uniq_theory_instance_ids.shift
175
+
176
+ # Save the values for use later during the global mapping
177
+ @values[theory.theory_instance_id] = value_mapping
178
+
179
+ # The first link added should be the tail
180
+ if @nodes.empty?
181
+ add_tail(theory,value_mapping)
182
+ return
183
+ end
184
+
185
+ # The second link should be the head
186
+ # (this doesn't necessarily need to be be case but I'll keep this convention
187
+ if @nodes.length == 1
188
+ return add_link_to(theory,0,value_mapping)
189
+ end
190
+
191
+ # Attempt to add a link to all the possible locations (head and tail are exempt)
192
+ extended_chains = []
193
+ (1...@nodes.length).each do |position|
194
+ res = self.copy.add_link_to(theory,position,value_mapping)
195
+ extended_chains += res
196
+ end
197
+ return extended_chains
198
+
199
+ end
200
+
201
+ # Returns true if the chain can be connected from the head to the tail.
202
+ #
203
+ def complete?
204
+
205
+ # Check that all the variables in all the theories have been globally mapped, as well as the head
206
+ @nodes.each do |theory|
207
+ # Find the global variable for each of the theory variables
208
+ theory.all_theory_variables.each do |theory_variable|
209
+ begin
210
+ to_global_id(@chain_mapping,theory.theory_instance_id,theory_variable.theory_variable_id)
211
+ rescue StandardError => e
212
+ StandardLogger.instance.error(e)
213
+ return false
214
+ end
215
+ end
216
+ end
217
+ return dependents_met?
218
+
219
+ end
220
+
221
+ # This uses the supplied theories and checks whether the dependents
222
+ # of any of theories that might be used are reachable.
223
+ #
224
+ # NOTE: This is only a rough assessment of whether the dependents are available
225
+ # it doesn't mean that it is solvable but does identify that it definitely
226
+ # isn't.
227
+ #
228
+ def solvable?(finish,theories)
229
+
230
+ # Get the finish and check all the dependents can be met by the theories
231
+ all_results = theories.inject([]) {|total,x| total += x.results}
232
+ return false unless all_results.any? {|x| x.same_structure?(finish)}
233
+
234
+ # Find the theories that can solve the problem and check their dependents can be met
235
+ # TODO Should probably include the head theory in here too.
236
+ collection = TheoryCollection.new(theories.copy)
237
+ finishing_theories = []
238
+ collection.each_with_result_structure(finish) do |t,r|
239
+ finishing_theories.push(t)
240
+ end
241
+
242
+ finishing_theories.each do |x|
243
+ end
244
+ res = finishing_theories.any? do |x|
245
+ dependency_tree_met?(x,theories+[self.first.copy])
246
+ end
247
+ return res
248
+ end
249
+
250
+ # Implements a new the chain where all the theories are implemented. It can
251
+ # only be implemented if the chain is complete e.g. all the dependents and results
252
+ # are matched up.
253
+ #
254
+ def implement
255
+ raise StandardError.new('This chain is not complete') unless complete?
256
+
257
+ # Generate a global value mapping - so global id to real value
258
+ unifyied_chain = unify_chain
259
+
260
+ return unifyied_chain.implement(intrinsic_mapping)
261
+
262
+ end
263
+
264
+ # Returns an array of implemented theories that have variable syntax that can
265
+ # be mapped to literal syntax(runtime_method,0,...) and also contain
266
+ # real values for each of the variables. So the runtime method will
267
+ # include all statements added to it.
268
+ #
269
+ def each_theory_progression(initial_runtime_method,test_cases)
270
+ raise StandardError.new('Only complete theories can be watched') unless self.implementable?
271
+
272
+ theories = []
273
+ previous_runtime_method = initial_runtime_method.copy
274
+ chain_validator = TheoryChainValidator.new
275
+ progressive_chain do |chain,theory|
276
+ initial_runtime_method.copy
277
+ runtime_method = chain_validator.build_method_from_chain( chain.implement,
278
+ initial_runtime_method.copy,
279
+ test_cases)
280
+
281
+ # Create the intrinsic mapping for the theory
282
+ unified_chain = chain.unify_chain
283
+
284
+ # * Go through each variable and find the intrinsic value
285
+ theory_intrinsic_mapping = Mapping.new
286
+ values = {:before=>{},:after=>{}}
287
+ unified_chain.theory_variables.each do |var|
288
+ intrinsic_value = global_id_intrinsic_value(var.theory_variable_id)
289
+ theory_intrinsic_mapping[var.theory_variable_id] = intrinsic_value
290
+
291
+ # Add the actual varlue of the intrinsic value
292
+ if intrinsic_value.kind_of?(IntrinsicRuntimeMethod)
293
+ values[:before][var.theory_variable_id] = previous_runtime_method.copy
294
+ values[:after][var.theory_variable_id] = previous_runtime_method.copy
295
+ next
296
+ end
297
+ if intrinsic_value.kind_of?(IntrinsicTestCases)
298
+ values[:before][var.theory_variable_id] = test_cases.copy
299
+ values[:after][var.theory_variable_id] = test_cases.copy
300
+ next
301
+ else
302
+ values[:before][var.theory_variable_id] = intrinsic_value.literal
303
+ values[:after][var.theory_variable_id] = intrinsic_value.literal
304
+ end
305
+ end
306
+
307
+ # Generate a unified version of the theory
308
+ mapping = generate_theory_mapping(theory.theory_instance_id)
309
+ unified_theory = theory.map_to(mapping)
310
+
311
+ yield theory.map_to(theory_intrinsic_mapping,values), unified_theory
312
+
313
+ # Save the previous method for the dependents
314
+ previous_runtime_method = runtime_method
315
+
316
+ end
317
+ return theories
318
+
319
+ end
320
+
321
+ # Return true if the chain can be implemented - so all the theories have literal values
322
+ # associated with them. This could be directly via when the theory was added to the
323
+ # chain or indirectly via connecting two theories.
324
+ #
325
+ def implementable?
326
+ self.implement
327
+ return true
328
+ rescue StandardError => e
329
+ StandardLogger.instance.info e
330
+ return false
331
+ end
332
+
333
+ # Returns an array of all the theory variables used in the chain
334
+ #
335
+ def theory_variables
336
+ return TheoryCollection.new(@nodes).theory_variables
337
+ end
338
+
339
+ # TODO Maybe just move this method to the UnfiedChain class
340
+ # Returns a set containing the intrinsic statements that created the variables. It should look
341
+ # something like the following.
342
+ #
343
+ # [{:global_variable_id=>0,:intrinsic_statement=>runtime_method,:written_statement=>'var1'},
344
+ # {:global_variable_id=>3,:intrinsic_statement=>runtime_method.params[0],:written_statement=>'var1.params[var3]'},
345
+ # ...]
346
+ #
347
+ # Currently the only way variables are created are for array access.
348
+ #
349
+ # There should not be the case where there are duplicate intrinsic_statements but different global_variable_ids -
350
+ # for now at least.
351
+ #
352
+ def variables_creation(runtime_method,test_cases)
353
+ raise StandardError.new('This should only be called on complete chains') unless complete?
354
+ res = []
355
+ unify_chain.theory_variables.each do |var|
356
+ intrinsic_value = global_id_intrinsic_value(var.theory_variable_id)
357
+ if intrinsic_value.kind_of?(IntrinsicRuntimeMethod)
358
+ res << {
359
+ :global_variable_id=>var.theory_variable_id,
360
+ :intrinsic_statement=>Parser.run('runtime_method'),
361
+ :written_statement=>'var'+var.theory_variable_id.to_s,
362
+ :variable_value=>runtime_method.copy
363
+ }
364
+ elsif intrinsic_value.kind_of?(IntrinsicTestCases)
365
+ res << {
366
+ :global_variable_id=>var.theory_variable_id,
367
+ :intrinsic_statement=>Parser.run('test_cases'),
368
+ :written_statement=>'var'+var.theory_variable_id.to_s,
369
+ :variable_value=>test_cases.copy
370
+ }
371
+ else
372
+
373
+ # TODO This whole bit is just really rushed------------------ write tests!
374
+
375
+ # Find all the statements that include that variable
376
+ unified_components = unify_chain.components
377
+
378
+ # TODO This is an extremely clumsy approach
379
+ # Collect all the written components matching the delcaration
380
+ written_components = unified_components.collect {|x| x.write}
381
+ written_components = written_components.select {|x| x.include?('var'+var.theory_variable_id.to_s)}
382
+
383
+ # TODO Should use the Parser to find the statement with the varx in
384
+ usage_statements = written_components.inject([]) do |total,x|
385
+ unless x.write.match(/\s.*\[var[\d]\]/).nil?
386
+ total << TheoryStatement.new(StringToTheory.run(x.write.match(/\s.*\[var[\d]\]/)[0]))
387
+ end
388
+ total
389
+ end
390
+ intrinsic_statements = usage_statements.collect {|x| x.map_to(intrinsic_mapping)}
391
+
392
+ unless intrinsic_statements.collect {|x| x.write}.uniq.length == 1
393
+ raise StandardError.new('Unable to create intrinsic variable create for variable '+var.theory_variable_id.to_s)
394
+ end
395
+
396
+ res << {
397
+ :global_variable_id=>var.theory_variable_id,
398
+ :intrinsic_statement=>intrinsic_statements.first,
399
+ :written_statement=>usage_statements.first.write,
400
+ :variable_value=>intrinsic_mapping[var.theory_variable_id].copy
401
+ }
402
+
403
+ end
404
+ end
405
+ return res
406
+ end
407
+
408
+ protected
409
+
410
+ # Returns the intrinsic mapping for the unified chain
411
+ #
412
+ def intrinsic_mapping
413
+
414
+ # Generate a global value mapping - so global id to real value
415
+ unifyied_chain = unify_chain
416
+
417
+ # Get all the global variable ids -
418
+ m = Mapping.new
419
+ unifyied_chain.theory_variables.each do |x|
420
+ m[x.theory_variable_id] = global_id_intrinsic_value(x.theory_variable_id)
421
+ end
422
+ return m
423
+ end
424
+
425
+ # Returns an array of all the components used in the chain
426
+ # TODO Could be turned into a set.
427
+ def components
428
+ return @nodes.inject([]) {|total,x| total += x.components }
429
+ end
430
+
431
+ # Returns the intrinsic value for specified global id. The intrinsic value is
432
+ # IntrinsicRuntimeMethod.new(7), IntrinsicFixnum.new(8), ...
433
+ #
434
+ # @param global_id The global id saved in chain_mapping
435
+ #
436
+ def global_id_intrinsic_value(global_id)
437
+
438
+ # Possible values for global_id
439
+ potentential_values = []
440
+ @chain_mapping.mapping[global_id].each do |key,value|
441
+ if @values[key]
442
+ potentential_values << @values[key][value]
443
+ end
444
+ end
445
+
446
+ if potentential_values.empty?
447
+ raise StandardError.new('Could not find an implementation value for global variable '+global_id.to_s)
448
+ end
449
+
450
+ if potentential_values.length > 1
451
+ unless potentential_values.collect {|y| y.write}.uniq.length == 1
452
+ raise StandardError.new('There is more than one possible value for this - it is ok if there the same')
453
+ end
454
+ end
455
+ return potentential_values[0]
456
+
457
+ end
458
+
459
+ # Replaces the current chain with the values specified
460
+ #
461
+ def create!(n,m,instance_ids,v=[])
462
+ @nodes, @chain_mapping, @uniq_theory_instance_ids, @values = n,m,instance_ids,v
463
+ # TODO I need to check there won't be a problem with @uniq_theory_instance_ids
464
+ return self
465
+ end
466
+
467
+ def nodes=(obj)
468
+ @nodes = obj
469
+ end
470
+
471
+ # Returns any number of new chains after adding this link to the position
472
+ # specified.
473
+ #
474
+ # TODO SHould I raise an error if it doesn't connect to anything?
475
+ #
476
+ def add_link_to(theory,position,value_mapping)
477
+ # TODO Down and up are quite similar I should consider refactoring
478
+
479
+ # Do through each of the dependents and then find a result with the same structure
480
+ mappings = [@chain_mapping.copy]
481
+ upward_links = @nodes[0...position]
482
+ # theory.copy.dependents.each do |dependent|
483
+ # if StandardLogger.instance.level == 0
484
+ # end
485
+ # each_unmet(:results,position,upward_links) do |index,link,result|
486
+ # if result.same_structure?(dependent)
487
+ # if StandardLogger.instance.level == 0
488
+ # end
489
+ # new_mappings = []
490
+ # mappings.each do |x|
491
+ # new_mappings << x.apply_mapping_update(theory,dependent.theory_component_id,link,result.theory_component_id)
492
+ # end
493
+ # mappings = new_mappings
494
+ # end
495
+ # end
496
+ # end
497
+
498
+ theory.copy.dependents.each do |dependent|
499
+ each_result(position,upward_links) do |index,link,result|
500
+ if result.same_structure?(dependent)
501
+ new_mappings = []
502
+ mappings.each do |x|
503
+ new_mappings << x.apply_mapping_update(theory,dependent.theory_component_id,link,result.theory_component_id)
504
+ end
505
+ mappings = new_mappings
506
+ end
507
+ end
508
+ end
509
+
510
+ # Go down the rest of the chain looking for exisitng links with unmet dependents
511
+ downward_links = @nodes[position...@nodes.length]
512
+ theory.copy.results.each do |result|
513
+ each_unmet(:dependents,position,downward_links) do |index,link,dependent|
514
+ if dependent.same_structure?(result)
515
+ new_mappings = []
516
+ mappings.each do |x|
517
+ new_mappings << x.apply_mapping_update(link,dependent.theory_component_id,theory,result.theory_component_id)
518
+ end
519
+ mappings = new_mappings
520
+ end
521
+ end
522
+ end
523
+
524
+ # Strip out any mappings that are identical to original they are
525
+ # links that haven't been connected with anything
526
+ # (don't include the head since it only has one thing to connect to)
527
+ unless @nodes.length < 2
528
+ mappings = mappings.select {|x| !@chain_mapping.same?(x) }
529
+ end
530
+
531
+ # Identify any orphan variables in the action and give them uniq global ids
532
+ mappings.each do |mapping|
533
+ theory.orphan_action_variables.each do |x|
534
+ mapping.add_mapping(mapping.next_free_global_id,theory.theory_instance_id,x.theory_variable_id)
535
+ end
536
+ end
537
+
538
+ # Create a new nodes array with the new theory in place
539
+ updated_nodes = @nodes.copy
540
+ updated_nodes.insert(position,theory)
541
+
542
+ # Create a new chain for each of the possible mappings
543
+ extended_chains = []
544
+ mappings.each do |x|
545
+ c = self.copy
546
+ new_chain = c.create!(updated_nodes,x,@uniq_theory_instance_ids.copy,@values.copy)
547
+ extended_chains << new_chain
548
+ end
549
+ return extended_chains
550
+ end
551
+
552
+ # TODO This could probably be replaced by the normal add_link_to method
553
+ def add_tail(theory,value_mapping={})
554
+ @nodes.push(theory.copy)
555
+ end
556
+
557
+ # # TODO I don't think this is used
558
+ # def update_unified_theory_variables(unified_theory_variables_mapping,chain_front,dependent,theory)
559
+ #
560
+ # # TODO Once the mapping is in place for all the theory vairables in the
561
+ # # in the dependent then the dependent should be mapped, written out
562
+ # # and compared to the result instead of the same_structure? method.
563
+ #
564
+ # # Find all the results that have the same structure as the dependent
565
+ # # TODO It should probably preference the earliest theories first.
566
+ # matching_theories = chain_front.select do |t|
567
+ # t.results.any? {|x| x.same_structure?(dependent)}
568
+ # end
569
+ #
570
+ # # Check that a matching theory was found in the chain
571
+ # if matching_theories.empty?
572
+ # # Couldn't find a theory that meets this theories depdenents - add the theory will
573
+ # # need to add a another link to the chain to connect this theory with the head.
574
+ # return unified_theory_variables_mapping
575
+ # end
576
+ #
577
+ # # Go through the matching thoeries and find the result that matched the dependent
578
+ # matching_results = matching_theories.inject([]) do |total,t|
579
+ # # TODO Presumes there is only one result
580
+ # res = t.results.select {|x| x.same_structure?(dependent)}.first
581
+ # total << {:theory_id=>t.theory_id,:result=>res,:theory=>t}
582
+ # end
583
+ #
584
+ # # Check how many results meet the dependents
585
+ # raise StandardError.new('Currently only handling one result to dependent match') unless matching_results.length == 1
586
+ # linking_result = matching_results.first
587
+ #
588
+ # # Link two theories so that the share the same global mapping
589
+ # @chain_mapping.connect(
590
+ # theory,
591
+ # dependent.theory_component_id,
592
+ # linking_result[:theory],
593
+ # linking_result[:result].theory_component_id
594
+ # )
595
+ # return unified_theory_variables_mapping
596
+ #
597
+ # end
598
+
599
+ # def map_to_tail(global_mapping,theory)
600
+ #
601
+ # # * Check whether there are any dependents from the back of the chain not met
602
+ #
603
+ # # Attempt to connect the theories results to the unmet dependents.
604
+ # # NOTE: The theories position is always one away from the head so
605
+ # # [:head]
606
+ # # [:x] <-----------this is where the new link will go.
607
+ # # [:linkB]
608
+ # # [:linkA]
609
+ # # [:tail]
610
+ #
611
+ # possible_mappings = [global_mapping.copy]
612
+ # valid_mappings = [global_mapping.copy]
613
+ #
614
+ # # 1. Find all the unmet dependents down the chain e.g. :tail, :linkA and :linkB
615
+ # # TODO Need to generate some nice diagrams for what's happing - very har to visualise
616
+ #
617
+ # # TEMP: This is the dependent for the tail of the chain - the head doesn't have any dependents
618
+ # unless unmet_dependents_and_link.empty?
619
+ # unmet_dependents_and_link.each do |dep_and_link|
620
+ #
621
+ # dependent = dep_and_link[:dependent]
622
+ # # TODO This is very similar to the code above - re-factor
623
+ # # Do any of the results have the same structure as the dependent?
624
+ # if theory.results.any? {|x| x.same_structure?(dep_and_link[:dependent])}
625
+ #
626
+ # valid_mappings = []
627
+ #
628
+ # results = theory.results.select {|x| x.same_structure?(dep_and_link[:dependent])}
629
+ # possible_mappings.each do |mapping|
630
+ # results.each do |res|
631
+ #
632
+ # begin
633
+ # new_mapping = potential_tail_mapping(mapping.copy,theory.copy,res.copy,dep_and_link[:dependent].copy,dep_and_link[:theory].copy)
634
+ # # TODO Create special MappingError
635
+ # rescue StandardError => e
636
+ # StandardLogger.instance.error e
637
+ # next
638
+ # end
639
+ # valid_mappings << new_mapping
640
+ # end
641
+ # end
642
+ #
643
+ # # Make the valid mappings the possible mappings for the next stage
644
+ # possible_mappings = valid_mappings
645
+ #
646
+ # end
647
+ #
648
+ # end
649
+ #
650
+ # end
651
+ #
652
+ # if valid_mappings.empty?
653
+ # raise StandardError.new('Unable to perform valid mapping')
654
+ # else
655
+ # # TODO Should be returning all the potential mapping
656
+ # return valid_mappings[0]
657
+ # end
658
+ #
659
+ # #return global_mapping
660
+ # end
661
+
662
+ # # Returns the updated mapping if a possible match is found otherwise it raises
663
+ # # an error.
664
+ # #
665
+ # def potential_tail_mapping(global_mapping,new_theory,new_result,existing_dependent,existing_theory)
666
+ #
667
+ # # Check that the result and dependent have the same number of theory variables
668
+ # if new_result.theory_variables.length != existing_dependent.theory_variables.length
669
+ # raise StandardError.new('The result and dependent that are being linked do not have the same number of theory_variables')
670
+ # end
671
+ #
672
+ # new_result.theory_variables.zip(existing_dependent.theory_variables) do |result_theory_variable,dependent_theory_variable|
673
+ # # Add the results of the theory to the global variables.
674
+ #
675
+ # # So these two variables need the same global variable
676
+ # # TODO This presumes that the same theory isn't being used in the chain
677
+ # global_mapping.connect(
678
+ # new_theory,
679
+ # new_result.theory_component_id,
680
+ # existing_theory,
681
+ # existing_dependent.theory_component_id
682
+ # )
683
+ # end
684
+ # return global_mapping
685
+ #
686
+ # end
687
+
688
+ # Returns the global id of the variable given the theory id and the variable
689
+ # id.
690
+ #
691
+ def to_global_id(global_mapping,theory_id,theory_variable_id)
692
+ global_id = global_mapping.find_global(theory_id,theory_variable_id)
693
+ if global_id.nil?
694
+ raise StandardError.new('Unable to find global id for theory '+theory_id.to_s+' theory_variable_id: '+theory_variable_id.to_s)
695
+ end
696
+ return global_id
697
+ end
698
+
699
+ # NOTE: The :tail isn't a real link, the last link just matches the :tail settings
700
+ def link_to_tail(theory)
701
+
702
+ # * Find the dependent(s) that connect to the finish
703
+ linking_results = theory.select_result_structure(@tail)
704
+ raise StandardError.new('Only expecting the theory to have one result that matches the finish') unless linking_results.length == 1
705
+ if linking_results.empty?
706
+ StandardLogger.instance.warning "this theory does not link to the tail"
707
+ return
708
+ end
709
+ linking_result = linking_results.first
710
+ end
711
+
712
+ # def front_of_chain
713
+ # return [@nodes.first.copy]
714
+ # end
715
+
716
+ # Returns a new theory mapping that replace the theories local ids with global
717
+ # ids.
718
+ #
719
+ def generate_theory_mapping(theory_id)
720
+ mapping = Mapping.new
721
+ @chain_mapping.mapping.each do |key,value|
722
+ if value[theory_id]
723
+ mapping[value[theory_id]] = TheoryVariable.new(key)
724
+ end
725
+ end
726
+ return mapping
727
+ end
728
+
729
+ # Returns true if the dependents of all the theories have been me. It
730
+ # does this by starting from the last link in the chain(the one cloest to
731
+ # the tail) and goes through each of it's dependents. It searches up the
732
+ # the chain until it finds a result that matches.
733
+ #
734
+ # Check that all the dependents have been connected to a result component
735
+ #
736
+ # NOTE: This should only be ran on unfied chains.
737
+ #
738
+ def dependents_met?
739
+ collection = TheoryCollection.new(@nodes)
740
+ return collection.dependents.all? do |dependent|
741
+ @chain_mapping.connected_component_ids.include?(dependent.theory_component_id)
742
+ end
743
+ end
744
+
745
+ # Start from the back of the chain and work backwards to the head.
746
+ #
747
+ def dependent_met?(dependent,chain)
748
+ chain.reverse.each do |theory|
749
+ theory.results.each do |result|
750
+ return true if result.write == dependent.write
751
+ end
752
+ end
753
+ return false
754
+ end
755
+
756
+ # Returns an array of all the depdendents in the chain that haven't
757
+ # been met by the front of the chain.
758
+ #
759
+ def unmet_dependents
760
+ results = []
761
+ return results if self.empty?
762
+ duplicate_chain = self.copy
763
+ last_link = duplicate_chain.pop
764
+ last_link.dependents.each do |dependent|
765
+ results.push dependent unless dependent_met?(dependent,duplicate_chain.copy)
766
+ end
767
+ return results+duplicate_chain.unmet_dependents
768
+ end
769
+
770
+ # Goes up through each theory in the chain from the position
771
+ # specifies and yeilds any unment depndents or results and the
772
+ # theory it belongs to.
773
+ #
774
+ # @param approach Either :depndents or :results
775
+ #
776
+ def each_unmet(approach,position,nodes)
777
+ # TODO Need to exclude theories that use the immediate runtime method
778
+ index = 0
779
+ comp_ids = @chain_mapping.connected_component_ids
780
+ nodes.each do |theory|
781
+ unmets = theory.send(approach).select do |x|
782
+ !comp_ids.include?(x.theory_component_id)
783
+ end
784
+ unmets.each {|x| yield index, theory, x}
785
+ index += 1
786
+ end
787
+ end
788
+
789
+ def each_result(position,nodes)
790
+ index = 0
791
+ nodes.each do |theory|
792
+ theory.results.each {|x| yield index, theory, x}
793
+ index += 1
794
+ end
795
+ end
796
+
797
+ # Returns a hash of all the unmet dependents down the chain (excluding the head)
798
+ # and the link/theory that it belongs to.
799
+ #
800
+ def unmet_dependents_and_link
801
+ results = []
802
+ return results if self.empty?
803
+ duplicate_chain = self.copy
804
+
805
+ # Remove the head link from the chain
806
+ duplicate_chain.shift
807
+
808
+ duplicate_chain.length.times do
809
+ last_link = duplicate_chain.pop
810
+ last_link.dependents.each do |d|
811
+ next if dependent_met?(d,duplicate_chain.copy)
812
+ results.push({:dependent=>d.copy,:theory=>last_link.copy})
813
+ end
814
+ end
815
+ return results
816
+ end
817
+
818
+ # Removes any results from the head that aren't needed to meet
819
+ # the dependents of the supplied theories.
820
+ #
821
+ # NOTE This method is only really needed while the head is so large
822
+ # as development continue I don't think this call will be needed.(26/04/2011)
823
+ #
824
+ def remove_superfluous_head_results!(theories)
825
+ theory_dependents = theories.inject([]) {|total,x| total += x.dependents}
826
+ new_results = []
827
+ @nodes.first.results.each do |r|
828
+ if theory_dependents.any? {|x| r.same_structure?(x)}
829
+ new_results.push(r)
830
+ end
831
+ end
832
+ @nodes.first.results = new_results
833
+ end
834
+
835
+ # Retruns true if all the dependents,and subsequent dependents of
836
+ # the theory can be met otherwise it returns false.
837
+ #
838
+ def dependency_tree_met?(theory,theories,pending_theories=[])
839
+
840
+ return theory.dependents.all? {|d| dependent_can_be_met?(d,theories,pending_theories+[theory.copy])}
841
+
842
+ # Finish if the theory is already in pending theories or has no dependents.
843
+ end
844
+
845
+ def dependent_can_be_met?(dependent,theories,pending_theories=[])
846
+
847
+ # Try to find theories thats result meets this dependent
848
+ theory_collection = TheoryCollection.new(theories.copy)
849
+ theory_collection.each_with_result_structure(dependent) do |theory,result|
850
+
851
+ # Check whether the matching theory is in pending theories
852
+ # (it is already being checked otherwise)
853
+ if pending_theories.any? {|x| x.theory_id == theory.theory_id}
854
+ return true
855
+ end
856
+
857
+ #return dependency_tree_met?(theory,theories,pending_theories+[theory.copy])
858
+ return dependency_tree_met?(theory,theories,pending_theories+[theory.copy])
859
+
860
+ end
861
+ StandardLogger.instance.warning '* failed to find a theory with a result to dependent: '
862
+ StandardLogger.instance.warning dependent.describe
863
+ return false
864
+ end
865
+
866
+ private
867
+
868
+ # Itterates through a progressive extending chain also returning
869
+ # the theory that has just been added to the chain.
870
+ #
871
+ def progressive_chain
872
+ return @nodes.length.times do |i|
873
+ copied_chain = self.copy
874
+ copied_chain.nodes = @nodes[0..i]
875
+ yield copied_chain, @nodes[i].copy
876
+ end
877
+ end
878
+
879
+ end