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
@@ -0,0 +1,19 @@
1
+ # This class represents statements that declare new variables.
2
+ # e.g. var = 'test'.chop
3
+ # var1 = var2.pop
4
+ #
5
+ class DeclarationStatement < Statement
6
+
7
+ def initialize(*parameters)
8
+ super(*parameters)
9
+ end
10
+
11
+ # Returns the declared variable. So in he case where
12
+ # there is var = 8 it would return var. This is always
13
+ # the first entry.
14
+ #
15
+ def declared
16
+ return self.first
17
+ end
18
+
19
+ end
@@ -0,0 +1,25 @@
1
+ # This is a temporary statement that simple writes out the string provided to it. It
2
+ # is used by the RuntimeTrackingMethod and is simple used now because I am not
3
+ # able to create hashes just yet. I hope to remove this class in the foreseable
4
+ # future(15/07/09) - lets see.
5
+ #
6
+ class HackStatement < Statement
7
+
8
+ def initialize(statement_text)
9
+ super()
10
+ @statement_text = statement_text
11
+ @confirmed = true
12
+ @statement_type = 'Hack'
13
+ end
14
+
15
+ def write(tab=0)
16
+ l = ''
17
+ tab.times {|x| l += "\t" }
18
+ return l+@statement_text
19
+ end
20
+
21
+ def copy
22
+ return HackStatement.new(@statement_text.dup)
23
+ end
24
+
25
+ end
@@ -0,0 +1,18 @@
1
+ class HashAccess
2
+
3
+ attr_reader :hash, :key
4
+
5
+ def initialize(array,index)
6
+ @hash = array
7
+ @key = index
8
+ end
9
+
10
+ def write
11
+ return @hash.write+'['+@key.write+']'
12
+ end
13
+
14
+ def copy
15
+ return HashAccess.new(@hash.copy,@key.copy)
16
+ end
17
+
18
+ end
@@ -0,0 +1,171 @@
1
+ # This class represents the structure where a statement is declared
2
+ # but doesn't close on the same line. Instead it can contain any
3
+ # number of other statements.
4
+ #
5
+ # for example
6
+ #
7
+ # if var_a == 'test'.select_all {|x| x.kind_of?(TheoryVariable)}
8
+ # # do something
9
+ # end
10
+ #
11
+ class OpenStatement < StatementGroup
12
+ include ActsAsTrackable
13
+ include ActsAsCode
14
+
15
+
16
+ def initialize(open_statement,*statements)
17
+ super(*statements)
18
+ @statement = open_statement
19
+ end
20
+
21
+ def write(tab=0)
22
+ line = @statement.write(tab)+"\n"
23
+ line += super(tab+1)
24
+ tab.times {line += "\t" }
25
+ line += "end"
26
+ return line
27
+ end
28
+
29
+ def describe(tab=0)
30
+ line = @statement.describe(tab)+"\n"
31
+ line += super(tab+1)
32
+ tab.times {line += "\t" }
33
+ line += "end\n"
34
+ return line
35
+ end
36
+
37
+ # Creates a copy of the current nested statement but without any statements
38
+ #
39
+ def copy_base
40
+ result = self.class.new(@statement.copy)
41
+ # TODO This means the scope id is being incremented for statements only exist for the declaration
42
+ result.scope_id = scope_id
43
+ return result
44
+ end
45
+
46
+ # Returns all the variables used in the opening statement as well as any
47
+ # child statements.
48
+ #
49
+ # TODO Write tests for this
50
+ def variables
51
+ return self.select_all([]){|x| x.kind_of?(Variable)}
52
+ end
53
+
54
+ def tokens
55
+ return self.select_all([]){|x| x.kind_of?(Token)}
56
+ end
57
+
58
+ # Overrides the default array select_all method to include
59
+ # the opening statement and contents of the open statement.
60
+ #
61
+ def select_all(results=[],&block)
62
+ @statement.select_all(results,&block)
63
+ return super(results,&block)
64
+ end
65
+
66
+ # Create a duplicate of this OpenStatement instance
67
+ #
68
+ # TODO Write tests for this
69
+ #
70
+ def copy
71
+ result = self.class.new(@statement.copy,*self.collect {|x| x.copy })
72
+ result.scope_id = scope_id
73
+ result.scope = scope
74
+ result.statement_level = statement_level
75
+ return result
76
+ end
77
+
78
+ # Returns a new open statement that has been trackified. A
79
+ # trackified open statement has a statement call after each
80
+ # line.
81
+ #
82
+ # @param tracking_method A runtime tracking method instance
83
+ # @param line An array thats length represents the current line.
84
+ #
85
+ def trackify(tracking_method,line)
86
+
87
+ # First copy the base open statement and repopulate it
88
+ result = copy_base
89
+
90
+ # Start by trackifying the opening statement
91
+ opening_variables = abstract_variables_for_tracking(@statement)
92
+ track_statement = tracking_statement(
93
+ tracking_method,
94
+ line,
95
+ statement_id.to_literal,
96
+ opening_variables,
97
+ @statement
98
+ )
99
+ result.push(track_statement)
100
+
101
+ # For each line in the open statement include a tracking call
102
+ # TODO I don't think this would trackify further open statements
103
+ self.each do |x|
104
+ result.push(x.copy)
105
+
106
+ # Now include a tracking call for after the statement
107
+ line_variables = abstract_variables_for_tracking(x)
108
+ # TODO Check that the line is going up
109
+ result.push tracking_statement(
110
+ tracking_method,
111
+ line,
112
+ x.statement_id,
113
+ line_variables,
114
+ x
115
+ )
116
+ end
117
+
118
+ return result
119
+
120
+ end
121
+
122
+ def replace_theory_variables!(mapping)
123
+ @statement.replace_theory_variables!(mapping)
124
+ self.each_with_index do |x,i|
125
+ if x.kind_of?(TheoryVariable) && mapping.has_key?(x.theory_variable_id)
126
+ self[i] = mapping[x.theory_variable_id].copy
127
+ next
128
+ end
129
+ self[i].respond_to?(:replace_theory_variables!)
130
+ self[i].replace_theory_variables!(mapping) if self[i].respond_to?(:replace_theory_variables!)
131
+ end
132
+ end
133
+
134
+ # Returns the statement_id of the embeded statement.
135
+ #
136
+ # TODO The nested statement should maybe have an idea
137
+ # of its own. It should probably have two ids
138
+ # to indicate at what point additional statements
139
+ # added e.g. inside/outside statement.
140
+ #
141
+ def statement_id
142
+ return @statement.statement_id
143
+ end
144
+
145
+ # TODO This seems wrong there is no opening statement
146
+ def to_literal_string
147
+ a = ''
148
+ self.each do |x|
149
+ a += x.to_literal_string
150
+ end
151
+ return a
152
+ end
153
+
154
+ # Returns true if the opening statement and all internal statements
155
+ # have been realised.
156
+ #
157
+ def realised?
158
+ return false unless @statement.realised?
159
+ return false unless self.all? {|x| x.realised? }
160
+ return true
161
+ end
162
+
163
+ def has?(&block)
164
+ self.each do |x|
165
+ return true if block.call(x)
166
+ end
167
+ return true if block.call(@statement)
168
+ return false
169
+ end
170
+
171
+ end
@@ -0,0 +1,5 @@
1
+ class RealisedStatement < Array
2
+ include PrintVariables
3
+ include ActsAsStatement
4
+
5
+ end
@@ -0,0 +1,39 @@
1
+ # TODO It is probably a bit overkill to create a new class for this.
2
+ #
3
+ # This is the same as the block statement except it uses the curly bracket syntax
4
+ #
5
+ class SingleLineBlockStatement < BlockStatement
6
+
7
+ def initialize(statement,block_container=BlockContainer.new(BlockVariable.new),*internal_statements)
8
+ super(statement,block_container,*internal_statements)
9
+ end
10
+
11
+ def write(tab=0)
12
+ l = @statement.write(tab)+'{ '+@block_container.write+' '
13
+ self.each do |x|
14
+ l += x.write
15
+ end
16
+ l += '} '
17
+ return l
18
+ end
19
+
20
+ def describe(tab=0)
21
+ l = @statement.describe(tab)+'{ '+@block_container.describe+' '
22
+ self.each do |x|
23
+ l += x.describe
24
+ end
25
+ l += '} '
26
+ return l
27
+ end
28
+
29
+ def copy
30
+
31
+ result = SingleLineBlockStatement.new(@statement.copy,@block_container.copy,*self.collect {|x| x.copy})
32
+ # TODO This means the scope id is being incremented for statements only exist for the declaration
33
+ result.scope_id = scope_id
34
+ result.scope = scope.copy
35
+ result.statement_level = statement_level
36
+ return result
37
+ end
38
+
39
+ end
@@ -0,0 +1,1223 @@
1
+ class Statement < Array
2
+ include PrintVariables
3
+ include ActsAsStatement
4
+ include ActsAsCode
5
+
6
+ attr_reader :statement_id, :scope, :statement_level, :statement_id
7
+ # TODO scope and statement level are confusing - not sure of the difference (I think it's legacy)
8
+ attr_writer :scope, :statement_level, :overrides, :statement_id
9
+
10
+ alias :array_push :push
11
+
12
+ @@statement_id = 0
13
+
14
+ #
15
+ # @params parameters Any number of elements to make up the statement possible classes
16
+ # include Equal, Addition, Unknown, StringVariable, Literal e.t.c
17
+ # &block [OPTIONAL] A block can also be provided to preview the statement from being
18
+ # reviewed and therefore preventing changes to variables uniq_id.
19
+ #
20
+ def initialize(*parameters)
21
+ super()
22
+
23
+ #
24
+ @overrides = nil
25
+ @confirmed = false
26
+
27
+ # Sets the flag that indicates the structure of the statement
28
+ @structure = nil
29
+
30
+ # Add the parameters to the array
31
+ parameters.each do |code|
32
+ self.push(code.copy)
33
+ end
34
+
35
+ # TODO I might change the statement_id to be determined by the structure
36
+ # of the statement.
37
+ @statement_id = @@statement_id
38
+ @@statement_id += 1
39
+
40
+ # Review completed statement
41
+ if block_given?
42
+ values = yield
43
+ review if (values[:review])
44
+ else
45
+ review
46
+ end
47
+
48
+ end
49
+
50
+ # Resets the globablly used value for statements id
51
+ #
52
+ def self.reset_global_id
53
+ #http://www.zenspider.com/Languages/Ruby/QuickRef.html
54
+ unless $".include?('test/unit.rb')
55
+ StandardLogger.log 'WARNING: Resetting variable id, this should only be done for tests'
56
+ end
57
+ @@statement_id = 0
58
+ end
59
+
60
+ # If this statement declares a variable determine whether the
61
+ # the variable has been previously declared. If so mark this
62
+ # statement as an "overrides" statement otherwise flag it
63
+ # as not.
64
+ #
65
+ def identify_overriding_statements(already_declared=[])
66
+ [BaseVariable,Equal].zip(self) do |x,y|
67
+ return unless y.kind_of?(x)
68
+ end
69
+ already_declared.each do |x|
70
+ if x[:variable_id] == declared_variable_id
71
+ @overrides = true
72
+ return
73
+ end
74
+ end
75
+ already_declared.push({:variable_id => declared_variable_id})
76
+ @overrides = false
77
+ end
78
+
79
+ # Returns this statement if it has the correct id
80
+ #
81
+ # @param id The id of the statement should exist
82
+ #
83
+ def find_statement(id)
84
+ if self.statement_id == id
85
+ return self
86
+ end
87
+ raise FailedToFindStatementError.new('Couldn\'t find statement with id '+id.to_s)
88
+ end
89
+
90
+ # Returns true if the statement overrides an existing variable.
91
+ # So if a = 6 but a was already set to 4 then this would be
92
+ # an overriding statement.
93
+ #
94
+ def overrides?
95
+ return @overrides
96
+ end
97
+
98
+ # Returns an array of variables in this statement
99
+ #
100
+ def variables
101
+ return self.select_all([]){|x| x.kind_of?(Variable)}
102
+ end
103
+
104
+ # Returns an array of all the tokens in the statement. A token
105
+ # is any literal, variable, intrinsic runtime or intrinsic testcase
106
+ #
107
+ def tokens
108
+ return self.select_all([]){|x| x.kind_of?(Token)}
109
+ end
110
+
111
+ #
112
+ def each_variable
113
+ variables.each { |x| yield x }
114
+ end
115
+
116
+ # Attempt to convert the statement into a string without any references
117
+ # to variables where possible. So varA = varB.chop might become
118
+ # "varA = 'test'chop"
119
+ #
120
+ def literalise
121
+
122
+ # Go through each element in the statement and attempt to literalise it
123
+ line = ''
124
+ self.each do |code|
125
+ unless code.kind_of? Variable or code.kind_of? InstanceCallContainer
126
+ line += code.write
127
+ next
128
+ end
129
+ if code.kind_of?(Variable)
130
+ if code.literalisable?
131
+ literal = code.literalise
132
+ line += literal.write
133
+ next
134
+ end
135
+ line += code.write
136
+ elsif code.kind_of?(InstanceCallContainer)
137
+ if(code.subject.literalisable?)
138
+ literal = code.subject.literalise
139
+ line += literal.write+'.'+code.method_call.write
140
+ next
141
+ end
142
+ line += code.write
143
+ end
144
+ end
145
+ return line
146
+ end
147
+
148
+ # TODO Maybe use a opject to handle the output of the statement.
149
+ def write(tab=0)
150
+
151
+ # Check the file type of tab
152
+ raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum
153
+
154
+ line = ''
155
+ tab.times {line += "\t" }
156
+ self.each do |code|
157
+ line += code.write
158
+ break if code.object_id == self.last.object_id
159
+ line += ' '
160
+ end
161
+ return line
162
+ end
163
+
164
+ def describe(tab=0)
165
+ # Check the file type of tab
166
+ raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum
167
+
168
+ line = ''
169
+ tab.times {line += "\t" }
170
+ self.each do |code|
171
+ line += code.describe
172
+ break if code.object_id == self.last.object_id
173
+ line += ' '
174
+ end
175
+ return line
176
+ end
177
+
178
+ def write_with_uniq_id(tab=0)
179
+ # Check the file type of tab
180
+ raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum
181
+
182
+ line = ''
183
+ tab.times {line += "\t" }
184
+ self.each do |code|
185
+ # TODO Doesn't need a space on the last code element
186
+ #line += code.write_with_uniq_id+' '
187
+ if code.respond_to?('write_with_uniq_id')
188
+ line += code.write_with_uniq_id+' '
189
+ next
190
+ end
191
+ line += code.write+' '
192
+ end
193
+ return line
194
+ end
195
+
196
+ # NOTE This method should only be used on realised statements
197
+ def write_with_value(tab=0)
198
+
199
+ # Check the file type of tab
200
+ raise StandardError.new('Unexpexted class "'+tab.class.to_s+'" for Fixnum (number of tabs)') unless tab.kind_of? Fixnum
201
+
202
+ line = ''
203
+ tab.times {line += "\t" }
204
+ self.each do |code|
205
+
206
+ if code.kind_of?(Variable)
207
+
208
+ line += code.write+'('+code.value.write+')'
209
+ unless code == self.last
210
+ line += ' '
211
+ end
212
+ next
213
+ end
214
+
215
+ line += code.write
216
+
217
+ end
218
+ return line
219
+
220
+ end
221
+
222
+ # Returns a string containing the written version of the statement
223
+ # but any variables will have there id in brackets after them.
224
+ #
225
+ # TODO This method is duplicated with requirements
226
+ #
227
+ def write_with_variable_id(tab=0,context=self)
228
+
229
+ line = ''
230
+ tab.times {line += "\t" }
231
+ self.each do |x|
232
+ if x.kind_of? Variable
233
+ line += x.write+'('+x.variable_id.to_s+') '
234
+ next
235
+ end
236
+ if x.kind_of? InstanceCallContainer
237
+ line += x.write+'('+x.subject.variable_id.to_s+')'
238
+ next
239
+ end
240
+ line += x.write
241
+ end
242
+ return line
243
+
244
+ end
245
+
246
+
247
+ # Creates a copy of the statement. The copy's variables should have
248
+ # the same variable ids but should be different instances. When
249
+ # all the code elements are added the statement is ascessed and the
250
+ # the requirements updated approriately.
251
+ #
252
+ def copy
253
+ # tmp = self.collect{|x| x.copy}
254
+ # result = self.class.new(*tmp) {{:review=>false}}
255
+ # result.statement_level = statement_level
256
+ # return result
257
+ return Marshal.load(Marshal.dump(self))
258
+ end
259
+
260
+ # Returns true if the statement contains any calls to a runtime
261
+ # method.
262
+ #
263
+ def contains_method_call?
264
+ return self.any? {|x| x.kind_of?(DefCall)}
265
+ end
266
+
267
+ # Adds the new piece of code to the statement and update
268
+ # the variables requirements to accomodate any change.
269
+ #
270
+ def push(code)
271
+
272
+ # Add the new piece of code to the statement
273
+ array_push(code)
274
+
275
+ # Update the requirements to reflect the change
276
+ update
277
+
278
+ end
279
+
280
+ def add(element)
281
+ push(element)
282
+ end
283
+
284
+ # Indicates whether the statement is one that assigns
285
+ # a value to another. Essential "Does the statement
286
+ # contain an equals sign?"
287
+ #
288
+ def assignment?
289
+ if detect_class(Equivalent).nil?
290
+ return false
291
+ end
292
+ return true
293
+ end
294
+
295
+ #
296
+ def right_hand_side
297
+ l, r = self.split(Equivalent)
298
+ return r
299
+ end
300
+
301
+ def left_hand_side
302
+ l, r = self.split(Equivalent)
303
+ return l
304
+ end
305
+
306
+ # Indicates whether the statement has been confirmed.
307
+ #
308
+ def confirmed?
309
+ return @confirmed
310
+ end
311
+
312
+ # This writes and evalutes the syntax of a statement to
313
+ # determine whether it can be used by it self.
314
+ #
315
+ # So something like var1 = var0.chop would fail since
316
+ # var0 doesn't exist. It needs to write to a different
317
+ # class to avoid the situation where the statement
318
+ # 'return false' would perceived as invalid syntax.
319
+ #
320
+ def valid_syntax?
321
+ return StatementCheck.new.valid_syntax?(self.write)
322
+ end
323
+
324
+ # yeilds each variable that is not declared in the statement and
325
+ # isn't known e.g. cat be literalised in the statement.
326
+ #
327
+ def each_untyped_variable
328
+ untyped_variables.each do |x|
329
+ yield x
330
+ end
331
+ end
332
+
333
+ # Returns an array of all the untyped variables in the statement.
334
+ # Excluding any declared variables in the statement.
335
+ #
336
+ def untyped_variables
337
+ x = []
338
+ not_declared_variables.each do |y|
339
+ x.push(y) unless y.kind_of?(TypeVariable)
340
+ end
341
+ return x
342
+ end
343
+
344
+ # Returns each of the variables that aren't realised. In that
345
+ # they aren't TypeVariables and don't have a literal value.
346
+ #
347
+ def unrealised_variables
348
+ results = []
349
+ variables.each do |x|
350
+ unless x.kind_of?(TypeVariable)
351
+ results.push(x)
352
+ next
353
+ end
354
+ if x.value.nil? and !x.kind_of?(NilVariable)
355
+ results.push(x)
356
+ end
357
+ end
358
+ return results
359
+ end
360
+
361
+ # Displays each of the unrealised variables within the statement
362
+ #
363
+ def each_unrealised_variable
364
+ unrealised_variables.each do |x|
365
+ yield x
366
+ end
367
+ end
368
+
369
+ # Returns an array of all the undeclared variables in the
370
+ # statement. An undeclared variable is simply a
371
+ # variable not declared in the statement but used in it.
372
+ # e.g. var_c = var_a+var_b var_a and var_b are the undeclared
373
+ # variable.
374
+ #
375
+ def not_declared_variables()
376
+
377
+ # The statement shouldn't be valid if there are undeclared variables
378
+ return [] if valid_syntax?
379
+
380
+ # Find any excluded variables(ones that are delcared within the statement)
381
+ # e.g. var = 'test'.chop
382
+ declared_variables = []
383
+ if( (self[0].kind_of? Variable)&&(self[1].class == Equal) )
384
+ declared_variables.push(self[0].copy)
385
+ end
386
+
387
+ # Attempt to find all the undeclared variables
388
+ undeclared = []
389
+ variables.each do |x|
390
+ next if declared_variables.any? {|y| y.uniq_id == x.uniq_id}
391
+ undeclared.push(x.copy)
392
+ end
393
+ return undeclared
394
+
395
+ end
396
+
397
+ # TODO It would be nicer to a subst that allows a block passed though
398
+ # e.g. a.subst(sub) {|x| x.variable_id == 9}
399
+ #
400
+ # Returns a new statement that is a duplicate of this statement
401
+ # but with the specified variable replaced.
402
+ #
403
+ # TODO Use the name nest for more than one statement
404
+ # TODO Write allot!! of tests for this
405
+ #
406
+ # @param id The id of the variable that will be replaced from the statement
407
+ #
408
+ def subst(id,var,context=self)
409
+ return self.copy.subst!(var){|x| x.uniq_id == id}
410
+ end
411
+
412
+ def subst!(var,&block)
413
+
414
+ # TODO I should probably check whether anything was substituted or or not
415
+ self.each_with_index do |x,i|
416
+ next unless x.kind_of?(Variable) or x.kind_of?(InstanceCallContainer)
417
+
418
+ # Essentially checks whether element is an InstanceCallContainer
419
+ if x.respond_to?(:subst!)
420
+ self[i] = x.subst!(var,&block)
421
+ next
422
+ end
423
+
424
+ if block.call(x)
425
+ self[i] = var.copy
426
+ end
427
+ end
428
+ return self
429
+ end
430
+
431
+ # TODO I should have a realised statement class
432
+ # Finds each element that satisfy the
433
+ #
434
+ # @param var The variable to replace any elements that match the block.
435
+ #
436
+ def replace_variable_if(var,&block)
437
+ container = self.copy.clear
438
+ self.each do |x|
439
+ if x.kind_of?(Variable)
440
+ if block.call(x)
441
+ container.push(var)
442
+ next
443
+ end
444
+ end
445
+ if x.kind_of?(InstanceCallContainer)
446
+ container.push(x.replace_variable_if(var,&block))
447
+ next
448
+ end
449
+ container.push(x.copy)
450
+ end
451
+ return container
452
+
453
+ end
454
+
455
+ # Returns a variable instance with the contextual requirements for the statement.
456
+ # TODO Don't really need these contextual_variable calls
457
+ #
458
+ def context_variable(id)
459
+ return find_variable(id)
460
+ end
461
+
462
+ def contextual_variable(id)
463
+ return context_variable(id)
464
+ end
465
+
466
+ # Returns the variable or instance call that contains
467
+ # the variable with the specidied id. It doesn't search
468
+ # the requirements.
469
+ #
470
+ # @param id The id of the variable that should be returned
471
+ #
472
+ # TODO Write test to retrieve declarared variable in a statement with two variables
473
+ # e.g. varA = varB-varC
474
+ #
475
+ # TODO Write tests for this
476
+ #
477
+ def find_variable(id)
478
+
479
+ # Go through each element of code in the statement and find instance calls and variables
480
+ self.each do |code|
481
+ next unless code.kind_of? Variable or code.kind_of? InstanceCallContainer
482
+
483
+ # Determine if the variable matches the id
484
+ if code.variable_id == id
485
+
486
+ # Does the statement declare a new variable?
487
+ if decalares_variable?
488
+ return find_variable_in_declaration_statement(code)
489
+ else
490
+ return code.copy
491
+ end
492
+
493
+ end
494
+
495
+ end
496
+
497
+ raise FailedToFindVariableError.new('Couldn\'t find variable with id = '+id.to_s+' in "'+self.write+'"')
498
+ end
499
+
500
+ # Returns the variable in this statement with uniq_id specified. In
501
+ # the event the variable resides in a instance call then that is
502
+ # returned.
503
+ #
504
+ def find_actual_variable(uniq_id)
505
+ target = self.variables.select {|x| x.uniq_id == uniq_id}
506
+ return target[0] unless target.empty?
507
+ raise FailedToFindVariableError.new('Couldn\'t find a variable with the id '+uniq_id.to_s+' in "'+self.write+'"')
508
+ end
509
+
510
+ # TODO This doesn't check anything
511
+ #
512
+ def replace_variable!(id,var)
513
+
514
+ unless var.kind_of?(Variable) then raise StandardError.new('Only expecting a variable') end
515
+
516
+ # Find the variable to be replaced
517
+ target = self.find_actual_variable(id)
518
+
519
+ #raise StandardError.new('Both target and variable should be the same class('+target.class.to_s+' != '+var.class.to_s+')') unless(target.kind_of?(var.class))
520
+ # TODO Should check for two variable kinds to two instance call kinds
521
+ self.each_with_index do |code,i|
522
+
523
+ # TODO Need to test with changing instance calls
524
+ next unless code.kind_of?(Variable) or code.kind_of?(InstanceCallContainer)
525
+
526
+ if(code.variable_id==target.variable_id)
527
+
528
+ if code.kind_of?(Variable)
529
+ self[i] = var
530
+ elsif code.kind_of?(InstanceCallContainer)
531
+ self[i].subject = var
532
+ end
533
+ return self
534
+ end
535
+ end
536
+
537
+ end
538
+
539
+ # Returns a declaration for this statement. So it will look something
540
+ # like -
541
+ # Statement.new(StringVariable.new('test'),Equal.new,'test')
542
+ #
543
+ # @param except An array of variable ids indicating what variables not to convert to
544
+ # new declarations. This is useful when you don't want to redclare an
545
+ # exisitng variable.
546
+ #
547
+ # e.g.
548
+ # Statement.new(Unknown.new,Equal.new,var_12,Addition.new,Literal.new(9))
549
+ #
550
+ def to_declaration(except=[])
551
+ if except.empty? then return VariableDeclaration.new('Statement',*self.collect {|x| x.to_declaration}) end
552
+ results = []
553
+ self.each do |x|
554
+ if x.kind_of?(Variable)
555
+ if except.any? {|y| x.variable_id == y}
556
+ results.push Declaration.new(x.write)
557
+ next
558
+ end
559
+ end
560
+ results.push x.to_declaration
561
+ end
562
+ return VariableDeclaration.new('Statement',*results)
563
+ end
564
+
565
+ # Returns the id of the variable declared in this statement
566
+ #
567
+ def declared_variable_id
568
+ raise UnexpectedStatementTypeError.new('Should be declaration statement type '+self.write) unless decalares_variable?
569
+ return self[0].variable_id
570
+ end
571
+
572
+ # Retuns an array of all the variable ids required for the
573
+ # statement.
574
+ #
575
+ def required_variable_ids
576
+ results = self.variables.collect {|x| x.variable_id}
577
+ return (results-[declared_variable_id])
578
+ end
579
+
580
+ # Returns true if the statement is simple. In that it just re-declares
581
+ # an existing variable e.g. var_a = var_b.
582
+ #
583
+ def is_simple?
584
+ return false unless decalares_variable?
585
+ # TODO Look at what you call the right hand side of the equation
586
+ if right_hand_side.length == 1 && right_hand_side[0].kind_of?(Variable)
587
+ return true
588
+ end
589
+ return false
590
+ end
591
+
592
+ # TODO Write tests
593
+ # This method writes the statement out as a literal string. In the sense
594
+ # that any of the variables used in the statement are converted to literals
595
+ # and written. Unknown variables are not written yet though.
596
+ #
597
+ # This method is called during tracking to give an indication what the statement
598
+ # being tracked is doing.
599
+ #
600
+ # TODO I am treating unknown variables as a special case that is the same
601
+ # value e.g. 'var' - but for determining equivalent processes it isn't
602
+ # ideal becuase you loose track of what variables is used in each
603
+ # statement. Although I'll wait unitl I can come up with an example
604
+ # and come up with a solution then.
605
+ #
606
+ def to_literal_string
607
+ return self.inject('') do |complete,part|
608
+ complete += part.to_literal_string
609
+ end
610
+ end
611
+
612
+ # Returns the number of statments in the statement. This will always
613
+ # be one but nested statements may have more.
614
+ #
615
+ def statement_count
616
+ return 1
617
+ end
618
+
619
+ # Returns true if the statement contains the same undeclared variables
620
+ # as the statement provided as well as the same number of elements.
621
+ #
622
+ # @param statement The statement thats undeclared variables are being compared.
623
+ #
624
+ def same_not_declared_variables?(statement)
625
+ return false if statement.length != self.length
626
+ statement.not_declared_variables.each do |x|
627
+ return false unless self.not_declared_variables.any? {|y| y.variable_id == x.variable_id}
628
+ end
629
+ return true
630
+ end
631
+
632
+ # Adds this statement to array of overriding statements if it
633
+ # overrides an existing variable.
634
+ #
635
+ # @param overriding_statements An array containing other overriding statements.
636
+ #
637
+ def find_overriding_statements(overriding_statements=[])
638
+ overriding_statements.push self if self.overrides?
639
+ return overriding_statements
640
+ end
641
+
642
+ # Returns an updated statement where all the variables within the statement
643
+ # have been realised. If the statement resides inside a nested statement
644
+ # or multiple nested statements the variables will be changed into a Dynamic
645
+ # Variable. These dynamic variables contain multiple variables with different
646
+ # values but the same variable_id.
647
+ #
648
+ # For example:
649
+ #
650
+ # 3.times do |var_a|
651
+ # var_b = var_a+1
652
+ # end
653
+ #
654
+ # In the above case var_b would be a dynamic variable would contain 3 FixnumVariable
655
+ # with the values 1,2,3. The statement itself doesn't indicate that it is nested, it
656
+ # is still just a regular statement.
657
+ #
658
+ # In a more complex example where we have two nested statements we might have something
659
+ # like the following:
660
+ #
661
+ # 2.times do |var_a|
662
+ # 2.times do |var_b|
663
+ # var_c = var_b+1
664
+ # end
665
+ # end
666
+ #
667
+ # We would end up with another dynamic variable with the values 1,2,1,2.
668
+ #
669
+ # The final tricky situation is when variables are overwritten. As a rule block
670
+ # variables are never overwritten - I should also include the subject of a loop
671
+ # as well.
672
+ #
673
+ # For example:
674
+ #
675
+ # var_a = 0
676
+ # 3.times do |var_b|
677
+ # var_a += var_b
678
+ # end
679
+ #
680
+ # In this situation there will be 3 versions of var_a the first one, the dynamic internal
681
+ # one and a post statement variable. The post statement variable will have a statement
682
+ # dependencey on the above nested statement. The internal variable will have a scope
683
+ # depenencey on the nested statement.
684
+ #
685
+ # TODO I suspect my approach to this is wrong. I pass in the history instance with
686
+ # all the information and then try to work out the realised value for this statement
687
+ # but it would probably be easier if the history instance itself to determine this.
688
+ #
689
+ def realise2(method_map)
690
+ return copy if realised?
691
+
692
+ raise StandardError.new('Unexpected data type ') unless method_map.kind_of?(History)
693
+ # Create a duplcate statement to be modified
694
+ result = self.copy
695
+
696
+ # Find value(s) for each unrealised variable.
697
+ y = []
698
+ each_unrealised_variable do |x|
699
+ if x.kind_of?(BlockVariable)
700
+ y.push(method_map.find_realised_variable(x.variable_id,x.uniq_id,'BlockVariable'))
701
+ else
702
+ y.push(method_map.find_realised_variable(x.variable_id,x.uniq_id))
703
+ end
704
+ # TODO Change to elsif x.kind_of?(Variable)
705
+ end
706
+
707
+ # Substitue the realised variables for the unrealised ones
708
+ self.each_unrealised_variable do |x|
709
+ catch(:variable_substituted) do
710
+ y.each do |z|
711
+ if z.uniq_id == x.uniq_id
712
+ result = result.replace_variable_if(z) {|a| a.uniq_id == x.uniq_id}
713
+ throw :variable_substituted
714
+ end
715
+ end
716
+ raise StandardError.new('Couldn\'t find realised value for variable with id '+x.variable_id.to_s+' in "'+self.write+'"')
717
+ end
718
+ end
719
+ return result
720
+
721
+ end
722
+
723
+ # Returns an array of all the RuntimeMethods instances contained in this
724
+ # statement. In all likelyhood there will no more than one.
725
+ #
726
+ def find_all_required_runtime_methods
727
+ defcalls = self.find_all {|x| x.kind_of?(DefCall)}
728
+ return defcalls.collect {|x| x.runtime_method}
729
+ end
730
+
731
+ # Returns true if the statement has been fully realsied - in that all the variables
732
+ # contained within it are realised. Otherwise it returns false.
733
+ #
734
+ def realised?
735
+ return self.variables.all? {|x| x.realised?}
736
+ end
737
+
738
+ # Returns the statement as a StatementVariable
739
+ #
740
+ # @param id The id of the variable to give to the returned statement
741
+ # variable.
742
+ #
743
+ def to_var(id=nil,uniq_id=nil)
744
+ var = StatementVariable.new(self.copy) {{:variable_id => id,:uniq_id=>uniq_id}}
745
+ return var
746
+ end
747
+
748
+ # Returns true if the statement declares a variable
749
+ def decalares_variable?
750
+ return true if self[0].kind_of?(Variable) and self[1].kind_of?(Equal)
751
+ return false
752
+ end
753
+
754
+ # Returns the variable declared in the statement. (if one exists)
755
+ #
756
+ def declared_variable
757
+ raise ImproperStatementUsageError.new(self.write+' does not declare a variable') unless decalares_variable?
758
+ return nil if declared_variable_id.nil?
759
+ return self[0]
760
+ end
761
+
762
+ # Returns true if this statement creates a new variable. A variable is considered created
763
+ # if it is declared in the variable or it modifies a variable. e.g. var_a.chop! or var_a.push(var_b)
764
+ #
765
+ def creates_variable?
766
+ created_variable
767
+ return true
768
+ rescue ImproperStatementUsageError
769
+ return false
770
+ end
771
+
772
+ # Returns the id of the created variable in this statement or raises an error if
773
+ # no variable is created.
774
+ #
775
+ def created_variable_id
776
+ return created_variable.variable_id
777
+ end
778
+
779
+ # Returns the variable created by this statement or raises an error if the
780
+ # statement doesn't create a variable.
781
+ #
782
+ def created_variable
783
+
784
+ # Check if the statement declares a new variable
785
+ begin
786
+ return declared_variable
787
+ rescue ImproperStatementUsageError => e
788
+ if first.kind_of?(InstanceCallContainer)
789
+ if first.subject.kind_of?(Variable) and first.method_call.destructive?
790
+ return first.subject
791
+ end
792
+ end
793
+ raise ImproperStatementUsageError.new(self.write+' statement does not create a new variable "'+e+"'")
794
+ end
795
+
796
+ end
797
+
798
+ # TODO Write tests for this
799
+ # Returns true if this statement is equivalent to the statement
800
+ # supplied. They are equalvalent if they have the same length,
801
+ # classes and values.
802
+ #
803
+ # @param statement The statement that this statement is being compared to
804
+ #
805
+ def equivalent?(statement)
806
+ return false unless statement.length == self.length
807
+
808
+ # TODO It would be nice to come up with a method to itterate through
809
+ # groups in an array.
810
+ # e.g. [self,statement].each_pair do |x,y|
811
+ # end
812
+ # where x is the first element in self and y is the first element in statement
813
+ # TODO I think Unknowns should only be accepted if they are the first paramter in
814
+ # a declaration statement. Current var_a = Unknown.chop is the same as var_b = var_c.chop
815
+ self.each_with_index do |elem,i|
816
+ return false unless elem.equivalent?(statement[i])
817
+ end
818
+ return true
819
+
820
+ # # TODO Tidy this up - pass the element to each other
821
+ # # e.g.
822
+ # # self.each_with_index do |elem,i|
823
+ # # return false unless eleme.equivalent?(statement[i])
824
+ # # end
825
+ # #
826
+ # self.each_with_index do |elem,i|
827
+ # return false if statement[i].class == elem.class
828
+ # if(elem.kind_of?(Variable))
829
+ # return false if elem.variable_id != statement[i].variable_id
830
+ # elsif(elem.kind_of?(InstanceCallContainer))
831
+ # return false if elem.variable_id != statement[i].variable_id
832
+ # return false if elem.method_call != statement[i].method_call
833
+ # end
834
+ # end
835
+ # return true
836
+ end
837
+
838
+ def has?(&block)
839
+ self.each do |x|
840
+ return true if block.call(x)
841
+ end
842
+ return false
843
+ end
844
+
845
+ # Returns the statement with the any variables in the conversions
846
+ # table replaced with the supplied variables. This is used when
847
+ # a runtime method with parameters needs evaluated.
848
+ #
849
+ # @param conversions A hash that identifies the uniq id's of the variables
850
+ # that should be replaced.
851
+ # e.g. {:6 => <#Variable>,:8 => <#Variable>} where variables with id 6 would
852
+ # changed to indicated variable.
853
+ #
854
+ def exchange_variables(conversions)
855
+ copied_statement = self.copy
856
+ conversions.each do |x,y|
857
+ begin
858
+ #copied_statement = copied_statement.subst(x.to_s.to_i,y.copy)
859
+ copied_statement = copied_statement.replace_variable_if(y) {|a| a.uniq_id == x.to_s.to_i}
860
+ rescue FailedToFindVariableError
861
+ next
862
+ end
863
+ end
864
+ return copied_statement
865
+ end
866
+
867
+ def cauldron_method_calls
868
+ return ['.statement_id']
869
+ end
870
+
871
+ def map_to(mapping)
872
+
873
+ # Duplicate the current statement before it is rewritten
874
+ rewritten_statement = self.copy
875
+
876
+ # Find all the containers that contain TheoryVariables
877
+ # NOTE The statement is put in an array because select all doesn't include the array itself
878
+ containers = [rewritten_statement].select_all {|x| x.respond_to?(:has?)}
879
+ theory_variable_containers = containers.select {|x| x.has? {|y| y.kind_of?(Variable)}}
880
+
881
+ # Rewrite the statement replacing the values
882
+ theory_variable_containers.each do |z|
883
+ z.replace_variables!(mapping)
884
+ end
885
+
886
+ return rewritten_statement
887
+ #return TheoryDependent.new(rewritten_statement,@theory_component_id)
888
+ end
889
+
890
+ protected
891
+
892
+ # Presumes this is a declaration statement and attempts to return
893
+ # specified variable in the context of the method.
894
+ #
895
+ def find_variable_in_declaration_statement(var)
896
+
897
+ # Duplicate the variable
898
+ # TODo I think I want to get rid of this "copy_contextual_variable"and just use copy
899
+ copied_variable = var.copy_contextual_variable
900
+
901
+ # Is the variable declared in this statement?
902
+ if(self[0].variable_id == copied_variable.variable_id)
903
+
904
+ # Create a requirement reflecting the declaration statement
905
+ # e.g varA = 'test'.chop becomes self = 'test'.chop
906
+ # statement_requirement = declared_variable_requirement
907
+
908
+ # Add this requirement to the variable and return it
909
+ # copied_variable.push(statement_requirement)
910
+
911
+ # TODO I think determining the value of variables at this point should
912
+ # be removed or re-thought. I think the typify method is more useful.
913
+ # The problem is that each statement is dependent on other statements
914
+ # or method calls.
915
+
916
+ # # NOTE I have included the untyped_variables call becuase it was continually throwing
917
+ # # since so many statements include method calls.
918
+ # if self.untyped_variables.length == 0 && !contains_method_call?
919
+ # # Convert the variable to be typed (if possible)
920
+ # if copied_variable.kind_of?(Unknown)
921
+ # begin
922
+ # return copied_variable.classify(CodeEvaluation.new.evaluate_code(literalise))
923
+ # # TODO I shouldn't use NameError - since I want to catch badly formed syntax - I
924
+ # # should have a custom error for bad syntax that will occu
925
+ # rescue NameError => e
926
+ # StandardLogger.log(' -- Statement: find_variable_in_declaration_statement'+e)
927
+ # end
928
+ # end
929
+ # end
930
+
931
+ return copied_variable
932
+
933
+ else
934
+
935
+ # The variable isn't declared in this statement
936
+ # So if varB is the declared variriable we might have
937
+ # varB = varA.chop
938
+ #
939
+ # This would create the requirement self.chop = varB
940
+ #
941
+ # Declare the statement requirement to be created
942
+ statement_requirement = nil
943
+
944
+ # Does the statement only have three elements
945
+ if(self.length == 3)
946
+
947
+ # Create a requirement for the variable in the statement
948
+ if(self[2].kind_of?(InstanceCallContainer))
949
+
950
+ # Create the matching requirement
951
+ statement_requirement = Requirement.new(InstanceCallContainer.new(This.new,self[2].method_call.class.new),Equal.new,self[0].copy)
952
+
953
+ elsif(self[2].kind_of?(Variable))
954
+
955
+ # Create the requirement reflecting the statement
956
+ statement_requirement = Requirement.new(This.new,Equal.new,self[0].copy)
957
+
958
+ else
959
+ raise StandardError.new('Unexpected class type '+self[2].class.to_s)
960
+ end
961
+
962
+ else
963
+
964
+ raise StandardError.new('Unexpected statement length'+self.length.to_s+' for requirement re-write') unless self.length == 5
965
+
966
+ # Handle the case were we have varA = varB-varC and we want varB's requirement
967
+ # e.g. we need varB = varA+varC
968
+
969
+ # TODO This can probably be re-written to be more abstract
970
+ # Case varA = varB-varC
971
+ if( self[2].kind_of?(Variable) and self[3].kind_of?(Subtract) and self[4].kind_of?(Variable) )
972
+
973
+ # where varB is the subject -> this = varA + varC
974
+ if(self[2].variable_id == var.variable_id)
975
+ statement_requirement = Requirement.new(This.new,Equal.new,self[0].copy,Addition.new,self[4].copy)
976
+ end
977
+
978
+ # where varC is the subject -> this = varB-varA
979
+ if(self[4].variable_id == var.variable_id)
980
+ statement_requirement = Requirement.new(This.new,Equal.new,self[2].copy,Subtract.new,self[0].copy)
981
+ end
982
+
983
+ elsif(self[2].kind_of?(Variable) and self[3].kind_of?(Addition) and self[4].kind_of?(Variable) )
984
+
985
+ if(self[2].variable_id == var.variable_id)
986
+ statement_requirement = Requirement.new(This.new,Equal.new,self[0].copy,Subtract.new,self[4].copy)
987
+ end
988
+
989
+ if(self[4].variable_id == var.variable_id)
990
+ statement_requirement = Requirement.new(This.new,Equal.new,self[2].copy,Addition.new,self[0].copy)
991
+ end
992
+
993
+ else
994
+ raise StandardError.new('Unknown statement structure "'+self.write+'"')
995
+ end
996
+
997
+ end
998
+
999
+ # Adding the new requirement to the variable
1000
+ copied_variable.push(statement_requirement)
1001
+ return copied_variable
1002
+
1003
+ end
1004
+
1005
+ end
1006
+
1007
+ # @param var The subsitute variable
1008
+ # @param id The id of the substitee
1009
+ # @param target The instance call being substituted
1010
+ #
1011
+ def subst_instance_call(var,id,target,context)
1012
+
1013
+ # Duplicate the current statement (variables are not in context)
1014
+ copied_statement = self.copy
1015
+
1016
+ # 2. Outside the context of the statement does the variable meet the requirements
1017
+ #begin
1018
+
1019
+ # If the target is a instance call does the new variable meet the requirements of the instance call?
1020
+ var_with_instance_call = nil
1021
+
1022
+ # Can the replacing variable be litralised?
1023
+ if(var.literalisable?)
1024
+
1025
+ # Change the variable into a literal instance
1026
+ begin
1027
+ literal_instance = var.literalise
1028
+ rescue StandardError => e
1029
+ StandardLogger.log('literalise: '+e)
1030
+ end
1031
+
1032
+ # Retrieve the instance call requirements and use the litralised variable with them
1033
+ unless target.method_call.valid_syntax?(literal_instance)
1034
+ raise RuntimeSyntaxError.new(literal_instance.write+' doesn\'t have the method "'+target.method_call.write+'"')
1035
+ end
1036
+
1037
+ # The substitute variable can use the same instance call as the variable being substituted
1038
+ var_with_instance_call = InstanceCallContainer.new(var,target.method_call.copy)
1039
+
1040
+ else
1041
+
1042
+ # TODO Write tests to test variables that can't be literalised
1043
+ # self.class == String can use the .chop method call
1044
+
1045
+ # Does the substitute variable meet the requirements of the target variable
1046
+ if(var.meets_requirements?(target.subject))
1047
+
1048
+ # The individual variables can be replaced - but can it use the same method call as the target
1049
+ var_with_instance_call = InstanceCallContainer.new(var,target.method_call.copy)
1050
+
1051
+ else
1052
+ StandardLogger.log(var.write_variable_id+' doesn\'t meet the requirements of '+target.subject.write)
1053
+
1054
+ end
1055
+ end
1056
+
1057
+ # At this point the variable being substitued either doesn't make an instance call or makes a valid one
1058
+ # Now we need to see whether it is valid with in the context of the statement.
1059
+
1060
+ # Get the requirements added to the variable in the context of the statement
1061
+ reqs = requirements_for(target.subject)
1062
+
1063
+ # If there are no requirements then its fine to use
1064
+ if(reqs.empty?)
1065
+ copied_statement = self.copy
1066
+ #copied_statement.replace_variable!(id,var_with_instance_call)
1067
+ copied_statement.replace_variable!(id,var_with_instance_call.subject)
1068
+ return copied_statement
1069
+ end
1070
+ StandardLogger.log('Statement: haven\'t accounted for requirements')
1071
+ return
1072
+
1073
+ end
1074
+
1075
+ #
1076
+ # @param var The variable that is being substituted into the statement
1077
+ # @param id The id of the variable to be included in the statement
1078
+ # @param target The variable in the statement that will be replaced
1079
+ #
1080
+ def subst_variable_call(var,id,target,context)
1081
+
1082
+ # The variable must meet the requirements of the statement - so add it to a duplicate statement
1083
+ copied_statement = self.copy
1084
+ copied_statement.replace_variable!(id,var)
1085
+
1086
+ return copied_statement
1087
+
1088
+ end
1089
+
1090
+ # Returns a copy of the variable with the id supplied, otherwise
1091
+ # raise an exception. This variable is not in the context of
1092
+ # the statement.
1093
+ #
1094
+ # @param id The id of the variable that should exist in this statement
1095
+ #
1096
+ def copy_original_variable(id)
1097
+ self.each do |code|
1098
+ next unless code.kind_of? Variable or code.kind_of? InstanceCallContainer
1099
+ return code.copy if code.variable_id == id
1100
+ end
1101
+ end
1102
+
1103
+ # Updates any of the requirements of the variables if
1104
+ # it's needed and confirms the statement so it can be
1105
+ # used in a method.
1106
+ # TODO This class might be redundant
1107
+ #
1108
+ # Write tests for exceptable statements
1109
+ #
1110
+ def update
1111
+
1112
+ # Narrow down what type of statement it is. Does it contain a equal or equivalent sign?
1113
+ equivaltent_assignment = detect_class(Equivalent)
1114
+
1115
+ unless equivaltent_assignment.nil?
1116
+ begin
1117
+ #update_requirements
1118
+ @confirmed = true
1119
+ rescue InvalidStatementError
1120
+ end
1121
+ return
1122
+ end
1123
+
1124
+ # Check if the statement contains return syntax
1125
+ if detect_class(Return)
1126
+
1127
+ # Check there are two
1128
+ unless self.length == 2
1129
+ @confirmed = false
1130
+ return
1131
+ end
1132
+ @confirmed = true
1133
+ return
1134
+ end
1135
+
1136
+ if self.length == 1 and detect_class(DefCall)
1137
+ @confirmed = true
1138
+ end
1139
+
1140
+ end
1141
+
1142
+ # This runs some simple checks of the structure of the statement
1143
+ # for example if the statement had two = signs then that would
1144
+ # invalidate it.
1145
+ #
1146
+ def validate_statment_structure
1147
+
1148
+ end
1149
+
1150
+ # Returns the two arrays split between the kind of class
1151
+ # provided.
1152
+ #
1153
+ # @param klass
1154
+ #
1155
+ def split klass
1156
+
1157
+ # Find the index of the equivalent assignment
1158
+ equivaltent_assignment = detect_class(klass)
1159
+ if equivaltent_assignment.nil? then raise InvalidStatementError.new('No equivalent assignment found when spliting') end
1160
+ equalivalent_index = self.index(equivaltent_assignment)
1161
+
1162
+ # Slice the array between the two values
1163
+ left = self.slice(0...equalivalent_index)
1164
+ right = self.slice((equalivalent_index+1)...self.length)
1165
+
1166
+ # Check there is only ever one thing on the left hand side of the equation
1167
+ if(left.length > 1) then throw InvalidStatementError.new('"Equivalent statements" can only have one value on the left hand side') end
1168
+
1169
+ return [left, right]
1170
+
1171
+ end
1172
+
1173
+ # Returns the first instance with the class declared.
1174
+ #
1175
+ # @param class_name The kind of class that is being searched for e.g. Equal or Equivalent
1176
+ #
1177
+ def detect_class(class_name)
1178
+ not_found = lambda{raise StandardError.new(''+class_name.to_s+' could not be found')}
1179
+ begin
1180
+ return self.detect(not_found) {|x| x.kind_of? class_name}
1181
+ rescue StandardError
1182
+ return nil
1183
+ end
1184
+ end
1185
+
1186
+ # Returns the requirement for the declared variable in the statement
1187
+ #
1188
+ def declared_variable_requirement
1189
+
1190
+ # Check that this statement declares a variable (they all should)
1191
+ if(detect_class(Equal).nil?)then raise StandardError.new('Expecting statement to declare a variable') end
1192
+
1193
+ # Check that the equals sign is the second code
1194
+ unless(self[1].kind_of?(Equal)) then raise StandardError.new('Expecting statement to include equal sign as secound code element') end
1195
+
1196
+ # Return the requirement of the declared variable
1197
+ declaration_requirement = Requirement.new(This.new,Equal.new,*self[2..self.length])
1198
+
1199
+ return declaration_requirement
1200
+
1201
+ end
1202
+
1203
+ # Currently this involves changing the 'uniq_id' of any
1204
+ # variables modified in the statment.
1205
+ # e.g. var_a.push(9)
1206
+ #
1207
+ def review
1208
+
1209
+ # TODO I have dropped this for now I don't know if it is redundent or not - it effect
1210
+ # tc_statement.rb test_created_variable
1211
+ # # A modifying statement would be "var_16.push('Normandy SR2')"
1212
+ # if statement_type == StatementStructure::MODIFYING_STATEMENT
1213
+ # created_variable.uniq_id_history.push(created_variable.uniq_id)
1214
+ # created_variable.increament_uniq_id!
1215
+ # end
1216
+ rescue StandardError => e
1217
+ # TODO I shouldn't really need this it is just temporary because of the way
1218
+ # structures are created in StatementStructure2.statements - they create a
1219
+ # partial statement.
1220
+ StandardLogger.instance.warning(e)
1221
+ end
1222
+
1223
+ end