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