cauldron 0.1.0

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 (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
@@ -0,0 +1,101 @@
1
+ # Instances of this class receive a chain of order theories and proceed
2
+ # to apply each of them and confirm their expected output. The valid chain
3
+ # can then be used to generate an appropriate runtime method.
4
+ #
5
+ class TheoryChainValidator
6
+
7
+ # TODO Is 'potential_values' used?
8
+ # Returns the first runtime method that could be created with the implemented chains
9
+ # supplied. This actually generates the runtime method to check the links of the chain
10
+ # are accurate - unlike the complete? check in chain instances.
11
+ #
12
+ def build(runtime_method,test_cases,theory_implementation_chains,potential_values=[])
13
+ validated_chains = []
14
+ theory_implementation_chains.each do |chain|
15
+ validate_next_chain_link(validated_chains,chain,runtime_method.copy,test_cases,0)
16
+ end
17
+ raise StandardError.new('Failed to generate a valid runtime method') if validated_chains.length == 0
18
+
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)
21
+
22
+ end
23
+
24
+ # Validates that the next link in the chain is consistent with the
25
+ # theories expected result. If it is then the next link is checked
26
+ # and so on. if all the links are consistent then the chain is add
27
+ # to the validated chain array.
28
+ #
29
+ def validate_next_chain_link(validated_chains,chain,runtime_method,test_cases,position)
30
+ # Check that current link in the chain meets in dependencies
31
+ # if its dependents are met it isn't suppose to work
32
+ unless chain[position].meets_dependencies?(runtime_method.copy,test_cases.copy)
33
+ return nil
34
+ end
35
+
36
+ # Add the theories action to the chains runtime method and realise the runtime method
37
+ # TODO This creates a new runtime method each time (so ignores what the previous theory did - BAD)
38
+ result = runtime_method.copy
39
+ unless chain[position].action.nil?
40
+ begin
41
+ result = add_statement_to_method(test_cases,runtime_method.copy,chain[position].action)
42
+ rescue SyntaxError => e
43
+ StandardLogger.instance.warn e
44
+ return nil
45
+ rescue TypeError => e
46
+ StandardLogger.instance.warn e
47
+ return nil
48
+ end
49
+
50
+ end
51
+
52
+ # Now check that the runtime method with the theories action also responds
53
+ # as the theory said it would in the result.
54
+ if chain[position].results.all? {|x| x.validates?(result,test_cases)}
55
+
56
+ # Has the chain been completed?
57
+ if (position+1) == chain.length
58
+ validated_chains << chain
59
+ return
60
+ else
61
+ # Continue along the chain
62
+ validate_next_chain_link(validated_chains,chain,result,test_cases,(position+1))
63
+ end
64
+ else
65
+ # 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
72
+ return nil
73
+ end
74
+
75
+ end
76
+
77
+ # Builds the method using the chain without checking that the depenedents
78
+ # and results are accurate.
79
+ #
80
+ def build_method_from_chain(chain,runtime_method,test_cases)
81
+ runtime_method = runtime_method.copy
82
+ chain.each do |link|
83
+ next if link.action.nil?
84
+ runtime_method = add_statement_to_method(test_cases,runtime_method,link.action)
85
+ end
86
+ return runtime_method
87
+ end
88
+
89
+ def add_statement_to_method(test_cases,runtime_method,action)
90
+ evaluation_code = ''
91
+ # TODO I don't think this line below is needed
92
+ evaluation_code += "test_cases = #{test_cases.write}"+"\n"
93
+ evaluation_code += "last_runtime_method = runtime_method.copy"+"\n"
94
+ evaluation_code += action.write+"\n"
95
+ evaluation_code += 'return runtime_method'+"\n"
96
+ eval evaluation_code
97
+ rescue NoMethodError => e
98
+ return nil
99
+ end
100
+
101
+ end
@@ -0,0 +1,42 @@
1
+ module TheoryComponent
2
+ include ActsAsCode
3
+
4
+ attr_reader :theory_component_id
5
+
6
+ # TODO Complete hack for issue where component ids aren't unique - using marshal load
7
+ @@theory_component_id = 0
8
+
9
+ def generate_theory_component_id
10
+ if @theory_component_id.nil?
11
+ @theory_component_id = @@theory_component_id
12
+ @@theory_component_id += 1
13
+ end
14
+ end
15
+
16
+ # Returns all the theory vairables in this theory
17
+ # dependent.
18
+ #
19
+ def theory_variables
20
+ return @statement.select_all {|x| x.kind_of?(TheoryVariable)}
21
+ end
22
+
23
+ def tokens
24
+ return @statement.tokens
25
+ end
26
+
27
+ # Returns an array of any of the accessors in the statement. An accessor
28
+ # is the chain to access a property e.g. in the following statement =>
29
+ #
30
+ # var1[:params][var3].something(var6)
31
+ #
32
+ # it would return ["var1[:params][var3]","var6"]
33
+ #
34
+ # The needed when trying to determine intrinsic values. So in this case
35
+ # var1 couln't be a runtime_method instance becuase it doesn't use
36
+ # the has key
37
+ #
38
+ def accessors
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,755 @@
1
+
2
+ # Instances are expected to connect any number of theories so
3
+ # that the chain finishes with a particular outcome.
4
+ #
5
+ # e.g. '<runtime_method>.all_pass?(<test_cases>) = true'
6
+ #
7
+ class TheoryConnector
8
+
9
+ def initialize(potential_values)
10
+ @potential_values = potential_values
11
+ end
12
+
13
+ # Attempts to chain the theories togeather so that the final theory
14
+ # results in the specified "finish".
15
+ #
16
+ # @param runtime_method This is an instance of the core runtime method
17
+ # instance that is populated with any number of statements.
18
+ # @param test_cases An array of test cases that contain the values for
19
+ # runtime method's paramters and the expected return value
20
+ # given those parameters.
21
+ # @param finish A description of the desired final outcome - this will
22
+ # probably be
23
+ # '<runtime_method>.all_pass?(<test_cases>) = true'
24
+ # @param theories A array of theories to be chained togeather to result
25
+ # in the finish outcome.
26
+ #
27
+ # TODO Last runtime method dependencies can't be shared down the the theory chain
28
+ #
29
+ def chain(runtime_method,test_cases,finish,theories)
30
+
31
+ return create_possible_chains(runtime_method,test_cases,finish,theories)
32
+
33
+ end
34
+
35
+ # NOTE: Will probably replace the create_possible_chains and chain call
36
+ # Returns an array of complete chains that conclude with a valid
37
+ # runtime method.
38
+ #
39
+ def generate_chains(runtime_method,test_cases,theories)
40
+
41
+ # Create the inital chain (with the head and tail)
42
+ intial_chain = Chain.new
43
+
44
+ # Find a theory that can act as the head
45
+ possible_head_theories = theories.select {|x| x.dependents.length == 0}
46
+
47
+ # Create the initial chains
48
+ possible_chains = []
49
+ possible_head_theories.each do |x|
50
+ possible_chains += intial_chain.copy.add_link(x)
51
+ end
52
+
53
+ # Check the initial chains incase they're complete
54
+ complete_chains = []
55
+ if possible_chains.any? {|x| x.complete? }
56
+ complete_chains += possible_chains.select {|x| x.complete?}
57
+ possible_chains.delete_if {|x| x.complete?}
58
+ end
59
+
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
+ end
64
+ return complete_chains
65
+
66
+ end
67
+
68
+ # TODO Need to watch out here for infinite chain connections
69
+ def extend_chain(chain,theories)
70
+ complete_chains = []
71
+ theories.each do |x|
72
+ extended_chains = chain.copy.add_link(x)
73
+ next if extended_chains.empty?
74
+ complete_chains += extended_chains.select {|y| y.complete?}
75
+ extended_chains.delete_if {|y| y.complete?}
76
+ extended_chains.each do |y|
77
+ complete_chains += extend_chain(y,theories)
78
+ end
79
+ end
80
+ return complete_chains
81
+ end
82
+
83
+ def create_possible_chains(runtime_method,test_cases,finish,theories)
84
+
85
+ # Generate the head theory - this is the starting point and doesn't have any dependents
86
+ accessors, mapping = TheoryGenerator.new.generate_accessors_and_mapping(test_cases,runtime_method,7,0)
87
+
88
+ # * Generate all the possible results of this runtime method
89
+ theory_results = TheoryGenerator.new.get_theory_results(accessors)
90
+
91
+ # * Create the actual head theory
92
+ head_theory = Theory.new([],nil,theory_results,runtime_method.copy)
93
+
94
+ # Create the initial chain that needs to be connected
95
+ intial_chain = Chain.new
96
+ intial_chain.form_chain(head_theory,finish,mapping)
97
+
98
+ return create_possible_chain_extensions(runtime_method,test_cases,finish,theories,intial_chain)
99
+ end
100
+
101
+ # This method has been created so the initial chain can be passed in to start the method
102
+ # creation. Generating the initial chain can take a couple of minutes.
103
+ #
104
+ def create_possible_chain_extensions(runtime_method,test_cases,finish,theories,intial_chain)
105
+
106
+ # Save any of the complete chains
107
+ possible_chains = []
108
+
109
+ # Search through the available theories and find one that results in the finish
110
+ potential_final_theories = theories.select {|x| x.has_result_structure?(finish)}
111
+
112
+ # Attempt to add the potential link to the end of the chain
113
+ partial_chains = []
114
+ potential_final_theories.each do |theory|
115
+ potential_chain = intial_chain.copy
116
+ # TODO Maybe should be call add_link_to_tail - then check if it completes
117
+ if(potential_chain.add_link(theory))
118
+ # A new link has been added - does this complete the chain (tail -> head)
119
+ res = potential_chain.complete?
120
+ #if potential_chain.complete?
121
+ if res
122
+ possible_chains << potential_chain
123
+ else
124
+ partial_chains << potential_chain
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+
131
+ # If there are any partial chains try to extend them with additional theories
132
+ # - partial chains were connect to the finish but not the head.
133
+ partial_chains.each do |partial_chain|
134
+
135
+ # Select from the chain the dependents that haven't be met.
136
+
137
+ # TODO This looks very messy -
138
+
139
+ # Take the first dependent attempt to add a theory to resolve it
140
+ # - NOTE: This theory may resolve other of the dependents
141
+ #until partial_chain.unmet_dependents.empty?
142
+ limit = 1
143
+ until partial_chain.unmet_dependents.empty? or limit == 0
144
+
145
+ # Select the firs of the unment dependents
146
+ dependent = partial_chain.unmet_dependents.first
147
+
148
+ # Search through the available theories for ones that match the dependent structure
149
+ # TODO This should be empty for "ruby test/unit/theory/tc_theory_connector.rb --name test_chain_with_2_theories"
150
+ potential_theories = theories.select {|x| x.has_result_structure?(dependent) }
151
+ if potential_theories.length > 10
152
+ raise StandardError.new("Have not tested for #{potential_theories.length.to_s} potential theories" )
153
+ end
154
+
155
+ # Attempt to add the theory to the partial chain (prefers the theories that complete)
156
+ potential_theories.each do |t|
157
+ updated_chain = partial_chain.copy
158
+ # TODO Should create a quick way to switch input on and off while the script is running
159
+ if(updated_chain.add_link(t))
160
+ partial_chain = updated_chain
161
+ if updated_chain.complete?
162
+ possible_chains << updated_chain
163
+ break
164
+ else
165
+ end
166
+ else
167
+ end
168
+ end
169
+
170
+ limit -= 1
171
+ end
172
+
173
+ end
174
+
175
+ # Return the complete chains
176
+ return possible_chains
177
+
178
+ end
179
+
180
+ # Returns a new chain so that they all use consistent theory variables ids
181
+ #
182
+ # @param chain An array of theories e.g.
183
+ # [<#Theory>,<#Theory>,<#Theory>,<#Theory>]
184
+ #
185
+ # The last chain contains the finished theory.
186
+ #
187
+ # It is difficult to generate all the arrangements for the chain as soon as
188
+ # there start to be a large number of dependents and results. There is just too
189
+ # many permutations. Once any connection is decided upon e.g. this dependent to
190
+ # that result then the number of permutations is reduced. As such they need to
191
+ # be updated in parallet.
192
+ #
193
+ #
194
+ #
195
+ def unify_chain2(chain)
196
+
197
+ unified_chains = []
198
+
199
+ # Reverse the chain so that the finish is the first theory
200
+ reversed_chain = chain.reverse
201
+
202
+ # This method needs to map the theory variables used in one theory to the
203
+ # rest. This basically means there is a global theory that has a respective
204
+ # id in each of the other theories in the chain. e.g.
205
+ #
206
+ # +----------+--------+--------+--------+--------+
207
+ # |Global #ID| link#1 | link#2 | link#3 | link#4 |
208
+ # +----------+--------+--------+--------+--------+
209
+ # | 0 | 1 | 1 | 2 | 89 |
210
+ # +----------+--------+--------+--------+--------+
211
+ # | 1 | 2 | 4 | 6 | 1 |
212
+ # +----------+--------+--------+--------+--------+
213
+ #
214
+
215
+ # {global#ID=> #{link#1=>1,#link#2=>5}
216
+
217
+ # Take the first theory and set the global theory variables to the first link
218
+ global_theory_variables = {}
219
+
220
+ # * Pop the first link in the chain and set ids of the theory variables
221
+ link = chain.pop
222
+ link.all_theory_variables.each do |theory_variable|
223
+
224
+ # For the first link I'm just going to use the same id as the first link
225
+ global_theory_variables[theory_variable.theory_variable_id] = {link.theory_id=>theory_variable.theory_variable_id}
226
+
227
+ end
228
+
229
+ # 1. Find all the dependent-> result permutations for the last chain
230
+ # 2. Exclude any that are mutually exclusive
231
+
232
+ #possible_global_theory_variables = extend_global_mapping(global_theory_variables,link,chain)
233
+
234
+ # NOTE: Previously I had normalised the theories by working out all the possible permutations
235
+ # of dependent to result. Then work out the variable substitution. This did work but
236
+ # the number of permutations for larger theories meant it was completely impractical. Instead
237
+ # now it needs to form one connection "dependent to result" and then update the consequence of
238
+ # that. Some of the decisions will be mutually exclusive.
239
+
240
+ return unified_chains
241
+
242
+ end
243
+
244
+ def extend_global_mapping(global_theory_variables,link,chain,results=[])
245
+
246
+ next_link = chain.pop
247
+
248
+ # Find all the variables in the next link thats global ids have not been determined
249
+ unidentified_theory_variables = next_link.all_theory_variables.inject([]) do |total,x|
250
+ total << x if global_theory_variables.any? {|key,value| !value[next_link.theory_id].nil? }
251
+ end
252
+
253
+ # Link the previous dependents to the this link
254
+ link.dependents.each do |dependent|
255
+
256
+ # Find the similar
257
+
258
+ end
259
+
260
+ end
261
+
262
+ # Returns a new chain so that they all use consistent theory variables ids
263
+ #
264
+ def unify_chain(chain)
265
+
266
+ #return unify_chain2(chain.reverse)
267
+
268
+ # TODO Break up this method and write tests for the individual parts
269
+
270
+ # Find all the ways the theory and results can connected
271
+ # - the same_structure? approach is quite loose
272
+ arrangements = chain_arrangements(chain.copy.reverse)
273
+ # For each theory in the chain give each each variable a unique id
274
+ starting_id = 1
275
+ uniq_chain = chain.inject([]) do |total,x|
276
+ r = x.uniq_theory_variables(starting_id)
277
+ starting_id = r.highest_theory_variable_id+1
278
+ total << r
279
+ total
280
+ end
281
+
282
+ # Identify the matching variables
283
+ mappings = matching_variables(arrangements,uniq_chain)
284
+ # TODO Why are so many of these identical
285
+ mappings.uniq!
286
+
287
+ # Identify opposed mapping (variables that don't match in the context of the theory aren't equal)
288
+ false_mappings = {}
289
+ uniq_chain.each do |x|
290
+ r = x.all_theory_variables.collect {|x| x.theory_variable_id}
291
+ r.each do |y|
292
+ false_mappings[y] = r.copy.delete_if {|z| z == y}
293
+ end
294
+ end
295
+
296
+ final_mapping = []
297
+ #mappings = [mappings.last]
298
+
299
+ count = 0
300
+ mappings.each do |m|
301
+ count += 1
302
+ # Create an array of all variables that are equalivalent
303
+ master = combine_matches(m.to_a)
304
+
305
+ # Check that the equivalent variables don't occur in the same theory
306
+ # TODO If this never occurs I need to re-think things
307
+ catch :bad_map do
308
+ false_mappings.each do |key,value|
309
+
310
+ master.each do |x|
311
+ if x.include?(key)
312
+ if (x | value).length != x.length+value.length
313
+ throw :bad_map
314
+ end
315
+ end
316
+ end
317
+ end
318
+
319
+ final_mapping << master.collect {|x| x.uniq}
320
+ end
321
+ end
322
+
323
+ # Generate new chains using the final mappings
324
+ return [] if final_mapping.empty?
325
+
326
+ #m = final_mapping.last
327
+ new_chains = []
328
+ final_mapping.each do |x|
329
+
330
+ # Get the id of all the theory variables
331
+ all_theory_variable_ids = uniq_chain.collect {|y| y.all_theory_variables.collect {|z| z.theory_variable_id} }.flatten
332
+
333
+ # Unique theory variables
334
+ uniq_variables = all_theory_variable_ids-x.flatten
335
+ unique_count = (all_theory_variable_ids-x.flatten).length + x.length
336
+
337
+ # Prepare the mapping to match each id to a new variable
338
+ # (at this stage each of the mappings should be unique)
339
+ map = Mapping.new
340
+ unique_count.times do |k|
341
+ unless uniq_variables.empty?
342
+ #map << {uniq_variables.shift=>TheoryVariable.new(k)}
343
+ map[uniq_variables.shift] = TheoryVariable.new(k)
344
+ next
345
+ end
346
+ #t = m.shift
347
+ var = TheoryVariable.new(k)
348
+ #map += x.shift.collect {|u| {u=>var} }
349
+ x.shift.each do |j|
350
+ map[j] = var
351
+ end
352
+ end
353
+
354
+ # Copy the the chain and update the mapping
355
+ new_chains << Chain.new(uniq_chain.collect {|y| y.copy.map_to(map)})
356
+
357
+ end
358
+ return new_chains
359
+
360
+ end
361
+
362
+ # Returns an array of arrays containing matching ids
363
+ #
364
+ # matches e.g. [[5,10],[11,17],[12,18],[1,6],[7,12],[13,5]]
365
+ #
366
+ def combine_matches(matches)
367
+
368
+ results = []
369
+ until matches.empty?
370
+ start = matches.shift
371
+
372
+ catch :no_change do
373
+ loop do
374
+ initial_length = start.length
375
+ #removed = temp2.delete_if {|x| (x | start).length != start.length+x.length }
376
+
377
+ # TODO A delete command to that returns what you were deleting would be nice
378
+ index = matches.index {|x| (x | start).length != start.length+x.length }
379
+ if index.nil?
380
+ results << start
381
+ throw :no_change
382
+ end
383
+ b = matches.slice!(index)
384
+ start += b
385
+ start.uniq!
386
+ end
387
+
388
+ end
389
+ end
390
+ return results
391
+ end
392
+
393
+ # Returns an array that matches one variable to another indicating that
394
+ # they should be considered equal.
395
+ #
396
+ def matching_variables(arrangements,uniq_chain)
397
+ #chains = []
398
+ mappings = []
399
+ arrangements.each do |arrangement|
400
+ map = {}
401
+ arrangement.each do |theory|
402
+
403
+ dependents = uniq_chain.inject([]) {|total,x| total += x.dependents}
404
+ results = uniq_chain.inject([]) {|total,x| total += x.results}
405
+
406
+ theory.each do |dependent_id,result_id|
407
+
408
+ # Find the dependent with the matching id
409
+ dependent = dependents.detect() {|x| x.theory_component_id == dependent_id}
410
+ result = results.detect() {|x| x.theory_component_id == result_id}
411
+
412
+ # Temporary check that everything is tickety boo
413
+ if result.theory_variables.length != dependent.theory_variables.length
414
+ raise StandardError.new('They should always have the same number of theory variables')
415
+ end
416
+
417
+ # Go through each of the variables and match up the values
418
+ result.theory_variables.zip(dependent.theory_variables) do |x,y|
419
+
420
+ if map.has_key?(x.theory_variable_id)
421
+ end
422
+ map[y.theory_variable_id] = x.theory_variable_id
423
+
424
+ end
425
+
426
+ end
427
+
428
+ end
429
+ mappings << map
430
+ end
431
+ return mappings
432
+ end
433
+
434
+ # Returns an array of all the ways the theory chain can be arranged
435
+ # So dependent A -> result B
436
+ #
437
+ # @param chain An array containing all the theories in order
438
+ #
439
+ def chain_arrangements(chain)
440
+ arrangements = []
441
+ next_link_arrangement(arrangements,[],chain)
442
+ return arrangements
443
+ end
444
+
445
+ def next_link_arrangement(arrangements,arrangement,chain)
446
+ # Take out link and find the results that match its dependents
447
+ link = chain.pop
448
+
449
+ # Stop if the all the links in the chain have been met (the last one has nothing left to be dependent on)
450
+ if chain.empty?
451
+ arrangements << arrangement
452
+ return
453
+ end
454
+
455
+ # TODO Down the line I should see if Cauldron can tidy this up
456
+
457
+ # Saves what dependent connects to what result
458
+ # e.g. connection = {16=>[26, 28], 17=>[26, 28]}
459
+ connection = {}
460
+ link.dependents.each do |dependent|
461
+
462
+ # Get all the results from the rest of the chain
463
+ results = chain.inject([]) {|total,x| total + x.results }
464
+
465
+ # Go through the rest of the chain and find the results with the same structure
466
+ connection[dependent.theory_component_id] = results.select do |x|
467
+ x.same_structure?(dependent)
468
+ end.collect {|x| x.theory_component_id}
469
+
470
+ end
471
+
472
+ # TODO I need to re-do allot of the connecton stuff - I was using theories with arround 650 dependents and
473
+ # it was generating an insane size of arrangements. I think it is plausable to handle that size a theory
474
+ # but I should re-do this bit.
475
+ #
476
+ # I may need to reduce the theories to only include the dependent/result arrangements that change after
477
+ # the action is added.
478
+
479
+ # Calculate the total number of arrangements
480
+ total_arrangements = connection.values.collect {|x| x.length}.inject(1) {|total,y| total *= y}
481
+
482
+ # TODO Need to include an escape here if there are too many total_arrangements
483
+
484
+ # TODO The theory_generator is generating too many results and dependents.
485
+
486
+ # Find the various arrangements for the results
487
+ # e.g. [[26,26],[26,28],[28,26],..]
488
+ # NOTE I get a RangeError: too big to product with larger theories
489
+ connection_arrangements = connection.values.first.product(*connection.values[1..connection.values.length])
490
+
491
+ # Alternative
492
+ # NOTE: I've rewritten this because the code above generates an error for larger theories
493
+ # new_connection_arrangements = []
494
+ # extend_arrangement(new_connection_arrangements,connection.values)
495
+
496
+ # Jump back to the clearer dependent -> result arrangement
497
+ # e.g. [{16=>26, 17=>26}, {16=>26, 17=>28}, {16=>28, 17=>26}, {16=>28, 17=>28}]
498
+ nice_connection_arrangements = connection_arrangements.collect do |x|
499
+ a = []
500
+ connection.keys.zip(x) do |dependent_id,result_id|
501
+ a << dependent_id
502
+ a << result_id
503
+ end
504
+ Hash[*a]
505
+ end
506
+
507
+ # For each arrangement continue to the next link
508
+ nice_connection_arrangements.each do |x|
509
+ # TODO Maybe use a hash with the theory id in instead
510
+ a = arrangement.copy + [x]
511
+ next_link_arrangement(arrangements,a,chain.copy)
512
+ end
513
+
514
+ end
515
+
516
+ def extend_arrangement(total,groups,group=[])
517
+ if groups.empty?
518
+ total << group
519
+ return
520
+ end
521
+ groups.shift.each do |x|
522
+ extend_arrangement(total,groups.copy,group.copy.push(x))
523
+ end
524
+ end
525
+
526
+ # Returns all the implementation permutations for the theory.
527
+ def implement_chain(chain,mapping=Mapping.new)
528
+
529
+
530
+ # Implement the theory in all the permutations
531
+ # NOTE: Need to get the mapping during the implementation
532
+ link = chain.shift
533
+
534
+ # TODO Rewriting permutations takes quite long, I think it could be greatly reduced by
535
+ # stricting the posibilities by reviewing the dependents. For example:
536
+ #
537
+ # if(var6.kind_of?(Fixnum))
538
+ # return true
539
+ # end
540
+ #
541
+ # TODO I shouldn't treat the realisable fixnum variables as fair game. They should only
542
+ # TestCaseIndexFixnum and only available to things of that type.
543
+ #
544
+ link_permutations = link.rewrite_permutations(@potential_values,mapping)
545
+ implemented_chains = []
546
+ link_permutations.each do |x|
547
+ implement_next_link(implemented_chains,chain.copy,[link],[x])
548
+ end
549
+
550
+ return implemented_chains
551
+
552
+ end
553
+
554
+ def implement_next_link(implemented_chains,chain,previous_chain,partial_implemented_chain)
555
+ if chain.empty?
556
+ implemented_chains << partial_implemented_chain
557
+ return
558
+ end
559
+ next_link = chain.shift
560
+
561
+ # Create an hash to show how the results-dependents are linked.
562
+ # TODO Because I am loading the theories from Marshal dumps I need to make sure they all have unique ids
563
+ results_to_dependents = {}
564
+
565
+ dependent_mapping = conversion_mapping(partial_implemented_chain,previous_chain,next_link)
566
+
567
+ # # Now implement the next theory using the mapping dependency already established.
568
+ dependent_mapping.each do |mapping|
569
+
570
+ # NOTE: The mapping is only restricted between the dependent and result connection
571
+ implemented_links = next_link.rewrite_permutations(@potential_values,mapping)
572
+
573
+ implemented_links.each do |x|
574
+ extended_implemented_chain = partial_implemented_chain.copy << x
575
+ previous_chain = previous_chain.copy << next_link
576
+ implement_next_link(implemented_chains,chain,previous_chain,extended_implemented_chain)
577
+ end
578
+ end
579
+
580
+ end
581
+
582
+ # Returns a mapping hash that will describe how to implement the next theory
583
+ # so that it is compatiable with current chain.
584
+ #
585
+ def conversion_mapping(implemented_chain,current_chain,next_theory)
586
+
587
+ # Find all the permutations of theory dependents meet by the current chain.
588
+
589
+ # For each dependent find all the current implementations that meet it
590
+ # e.g. {16=>[26, 28, 12], 17=>[26, 28, 12]}
591
+ # TODO Should only include the most recent chain if the result contains a
592
+ # last_runtime_method variable.
593
+ results = current_chain.inject([]) {|total,x| total + x.results }
594
+ arrangements = next_theory.dependents.inject({}) do |total,dependent|
595
+ total[dependent.theory_component_id] = results.select do |x|
596
+ x.same_structure?(dependent)
597
+ end.collect {|x| x.theory_component_id}
598
+ total
599
+ end
600
+
601
+ # # ------------- Development Code -------------
602
+ # arrangements.each do |key,value|
603
+ # value.each do |x|
604
+ # end
605
+ # end
606
+
607
+ # Get the various permutations of the dependent to result
608
+ result_values = arrangements.values
609
+ # http://www.ruby-doc.org/core/classes/Array.html#M000287
610
+ # TODO Need to check when there is only one dependent
611
+ # [1,2].product() #=> [[1],[2]]
612
+ # [1,2].product([]) #=> []
613
+
614
+ variations = result_values.first.product(*result_values[1..result_values.length])
615
+ # e.g. [[26, 26], [26, 28], [26, 12], [28, 26], [28, 28], [28, 12], [12, 26], [12, 28], [12, 12]]
616
+ # TODO Maybe an array with the dependent id in would be more useful
617
+ # e.g. [[16=>26,17=>26],[16=>26,17=>28],...
618
+
619
+ # Need to find all the mappings that will still be consistent
620
+ potential_mappings = []
621
+ variations.each do |x|
622
+
623
+ # Go through each dependent to result pair
624
+ catch :incompatiable do
625
+ index = 0
626
+ mapping = Mapping.new
627
+
628
+ arrangements.each_key do |dependent_id|
629
+
630
+ # ----------- Development ----------------
631
+
632
+ # Find the implementation with this result
633
+ theory_result = results.detect {|y| y.theory_component_id == x[index]}
634
+
635
+ # Find the dependent that will be mapped
636
+ theory_dependent = next_theory.dependents.detect {|y| y.theory_component_id == dependent_id}
637
+
638
+ # Find the implementation that contains the selected result
639
+ # TODO This approach implies that the same theory can be used twice in the chain.
640
+ # TODO I could probably avoid allot of this by having implementation ids and including the
641
+ # mapping with the implementation's results
642
+ theory_implementation = implemented_chain.detect do |y|
643
+ y.results.any? {|z| z.theory_component_id == x[index]}
644
+ end
645
+
646
+ # Map the id of dependent to the real value used by the result
647
+ theory_result.theory_variables.zip(theory_dependent.theory_variables) do |z,y|
648
+
649
+ if mapping.has_key?(y.theory_variable_id)
650
+ throw :incompatiable if mapping[y.theory_variable_id] != theory_implementation.mapping[z.theory_variable_id]
651
+ end
652
+
653
+ mapping[y.theory_variable_id] = theory_implementation.mapping[z.theory_variable_id]
654
+ end
655
+ index += 1
656
+ end
657
+ potential_mappings << mapping
658
+ end
659
+ end
660
+
661
+ return potential_mappings
662
+
663
+ end
664
+
665
+ def find_theories_with_these_results(theories,results)
666
+ return theories.select do |theory|
667
+ results.all? {|x| theory.has_result_structure?(x)}
668
+ end
669
+ end
670
+
671
+ # Find the theories that match any of the results.
672
+ #
673
+ def find_the_theories_with_these_results(theories,results)
674
+ end
675
+
676
+ #
677
+ def add_link(complete_chains,chain,theories)
678
+
679
+ last_theory = chain.last
680
+
681
+
682
+ # Find the theories that can meet last theories dependency
683
+ # TODO Should this be looking for just one theory? If more than one theory is
684
+ # added they might not be compatible.
685
+ results = find_theories_with_these_results(theories,last_theory.dependents)
686
+ if results.empty?
687
+ complete_chains << chain
688
+ return
689
+ end
690
+
691
+ # Try to find any additional links to the new chain
692
+ results.each do |x|
693
+ extended_chain = chain.copy.push(x)
694
+ add_link(complete_chains,extended_chain,theories)
695
+ end
696
+
697
+ end
698
+
699
+ # Returns a number of updated mappings based on what if possible
700
+ # for the first theory and the current mapping for the end.
701
+ #
702
+ def refine_initial_mapping(theory,mapping,runtime_method,test_cases)
703
+
704
+ # TEMP
705
+ # 1. What theory variables don't have real values?
706
+ # 2. What real values are available?
707
+ # 3. For each real variable identify the theory variables it could be.
708
+ # 4. Given the possibilities work out the permutations
709
+
710
+ # Find the theory variable ids that don't have real values
711
+ var_ids = theory.dependents.inject([]){|total,x| total << x.theory_variables.collect {|z| z.theory_variable_id}}.flatten.uniq
712
+ unasigned_var_ids = var_ids-mapping.keys
713
+
714
+ # Development
715
+
716
+ # Find the available real values
717
+ available_real_values = @potential_values-mapping.values
718
+
719
+ # Determine the mermutations of unassigned var ids to available real values.
720
+ # NOTE: I'm sure how efficient it is working out every permutation especially
721
+ # when a dependent link "varA.kind_of?(Fixnum)" could narrow the
722
+ # combinations considerably.
723
+ value_permutations = available_real_values.permutation(unasigned_var_ids.length).to_a
724
+ var_value_permutations = value_permutations.inject([]) do |total,x|
725
+ r = []
726
+ x.zip(unasigned_var_ids) do |y,z|
727
+ r << z
728
+ r << y
729
+ end
730
+ total << Mapping.new(Hash[*r])
731
+ end
732
+
733
+ # = Remove any mapping permutaions that don't work =
734
+ passible_mappings = []
735
+ var_value_permutations.each_with_index do |possible_mapping,i|
736
+
737
+ # Combine the possible mapping with current actual mapping
738
+ m = mapping.merge(possible_mapping)
739
+
740
+ # Using this mapping go through each dependent and check it works
741
+ # (if it doesn't work then it's a none starter)
742
+ # TODO I don't really need to implement the full theory - just the dependents
743
+ implementation = theory.map_to(m)
744
+
745
+ # Use each implementation and find the ones that work
746
+ next unless implementation.meets_dependencies?(runtime_method,test_cases)
747
+ passible_mappings << m
748
+
749
+
750
+ end
751
+ return passible_mappings
752
+
753
+ end
754
+
755
+ end