From fc1d8591fbf767215b3f1a532d53044414308829 Mon Sep 17 00:00:00 2001 From: Rudolf FERENC Date: Tue, 6 Mar 2018 13:02:08 +0100 Subject: [PATCH] Add Python language support. --- .gitmodules | 6 + 3rdparty/CMakeLists.txt | 77 +- 3rdparty/python/pylint/bin/pylint | 7 + 3rdparty/python2 | 1 + 3rdparty/python3 | 1 + CMake/PlatformOptions.cmake | 2 + CMake/UtilityFunctions.cmake | 3 + CMakeLists.txt | 7 +- OpenStaticAnalyzer/CMakeLists.txt | 2 + OpenStaticAnalyzer/doc/readme.txt | 9 +- OpenStaticAnalyzer/java/CMakeLists.txt | 12 +- .../md/CodeDuplicationMetricsRef.md | 21 + .../java/doc/usersguide/md/Main.md | 50 +- .../java/doc/usersguide/md/PMDRef.md | 2 +- OpenStaticAnalyzer/python/CMakeLists.txt | 75 + .../python/Licenses/ANTLR-LICENSE.txt | 26 + .../python/Licenses/BOOST-LICENSE.txt | 23 + .../python/Licenses/CRYPTO-LICENSE.txt | 51 + .../python/Licenses/CURL-LICENSE.txt | 21 + .../python/Licenses/PYTHON-LICENSE.txt | 48 + .../python/Licenses/XERCES-C-LICENSE.txt | 202 + .../python/Licenses/XERCES-C-NOTICE | 10 + .../python/Licenses/ZLIB-LICENSE.txt | 31 + OpenStaticAnalyzer/python/demo/analyze.bat | 3 + OpenStaticAnalyzer/python/demo/analyze.sh | 3 + OpenStaticAnalyzer/python/demo/ceilometer.zip | Bin 0 -> 1523052 bytes .../python/demo/filter_linux.txt | 2 + OpenStaticAnalyzer/python/demo/filter_win.txt | 2 + .../python/doc/usersguide/CMakeLists.txt | 10 + .../md/CodeDuplicationMetricsRef.md | 152 + .../python/doc/usersguide/md/Footnotes.md | 10 + .../python/doc/usersguide/md/Main.md | 389 + .../python/doc/usersguide/md/PylintRef.md | 1247 +++ .../doc/usersguide/md/SourceCodeMetricsRef.md | 357 + README.md | 17 +- cl/DuplicatedCodeFinder/CMakeLists.txt | 14 +- cl/DuplicatedCodeFinder/DCF.rul | 1180 +-- .../inc/{ => Visitors}/CloneVisitorBase.h | 2 +- .../inc/{ => Visitors}/CoverageVisitorBase.h | 4 +- .../inc/{ => Visitors}/DistanceVisitor.h | 0 .../inc/{ => Visitors}/JCoverageVisitor.h | 4 +- .../inc/Visitors/JNodeEmbeddednessVisitor.h | 2 + .../inc/{ => Visitors}/NamedVisitor.h | 15 + .../inc/Visitors/PCoverageVisitor.h | 62 + .../inc/Visitors/PNodeEmbeddednessVisitor.h | 62 + cl/DuplicatedCodeFinder/inc/common.h | 21 +- cl/DuplicatedCodeFinder/inc/dcm.h | 6 + cl/DuplicatedCodeFinder/inc/types.h | 26 +- .../src/CloneVisitorBase.cpp | 26 +- .../src/CoverageVisitorBase.cpp | 4 +- .../src/JCoverageVisitor.cpp | 2 + .../src/JNodeEmbeddednessVisitor.cpp | 4 + .../src/LanguageFactory.cpp | 2 + .../src/PNodeEmbeddednessVisitor.cpp | 166 + .../src/StatementFilter.cpp | 10 + cl/DuplicatedCodeFinder/src/dcm.cpp | 70 +- cl/DuplicatedCodeFinder/src/main.cpp | 18 +- cl/FindBugs2Graph/inc/ResultConverter.h | 1 - cl/FindBugs2Graph/src/ResultConverter.cpp | 4 - cl/FindBugs2Graph/src/main.cpp | 1 - cl/LIM2Metrics/CMakeLists.txt | 18 +- cl/MetricHunter/CMakeLists.txt | 1 + cl/MetricHunter/MetricHunter_PYTHON.threshold | 125 + cl/OpenStaticAnalyzerJava/inc/Properties.h | 2 - cl/OpenStaticAnalyzerJava/inc/Task.h | 20 - cl/OpenStaticAnalyzerJava/rules_java.csv | 216 +- cl/OpenStaticAnalyzerJava/src/Task.cpp | 17 +- cl/OpenStaticAnalyzerJava/src/main.cpp | 10 +- cl/OpenStaticAnalyzerPython/CMakeLists.txt | 16 + cl/OpenStaticAnalyzerPython/inc/Properties.h | 79 + cl/OpenStaticAnalyzerPython/inc/Task.h | 44 + cl/OpenStaticAnalyzerPython/inc/messages.h | 31 + cl/OpenStaticAnalyzerPython/rules_python.csv | 292 + cl/OpenStaticAnalyzerPython/src/Task.cpp | 459 ++ cl/OpenStaticAnalyzerPython/src/main.cpp | 490 ++ cl/PAN/CMakeLists.txt | 43 + cl/PAN/inc/PBuilder.h | 123 + cl/PAN/inc/PVisitor.h | 148 + cl/PAN/inc/PlLOC.h | 54 + cl/PAN/inc/VisitorImport.h | 82 + cl/PAN/inc/VisitorType.h | 175 + cl/PAN/inc/messages.h | 81 + cl/PAN/src/PBuilder.cpp | 778 ++ cl/PAN/src/PVisitor.cpp | 1638 ++++ cl/PAN/src/VisitorImport.cpp | 423 + cl/PAN/src/VisitorType.cpp | 769 ++ cl/PAN/src/main.cpp | 521 ++ cl/PAN/src/plloc.cpp | 186 + cl/PAN2Lim/CMakeLists.txt | 14 + cl/PAN2Lim/inc/messages.h | 56 + cl/PAN2Lim/inc/python2lim.h | 306 + cl/PAN2Lim/src/main.cpp | 365 + cl/PAN2Lim/src/python2lim.cpp | 1106 +++ cl/PMD2Graph/CheckerStrategy.cpp | 4 - cl/PMD2Graph/CheckerStrategy.h | 4 +- cl/PMD2Graph/MetricTree.h | 5 - cl/PMD2Graph/PMD/PMD.rul | 2797 +------ cl/PMD2Graph/PMD/PMDStrategy-rul.cpp | 56 +- cl/PMD2Graph/PMD/PMDStrategy.h | 3 +- cl/PMD2Graph/main.cpp | 11 +- cl/PMD2Graph/messages.h | 1 - cl/Pylint2Graph/CMakeLists.txt | 20 + cl/Pylint2Graph/Pylint.conf | 32 + cl/Pylint2Graph/Pylint.rul | 6855 +++++++++++++++++ cl/Pylint2Graph/inc/Pylint2Graph.h | 55 + cl/Pylint2Graph/inc/PylintRulMaker.h | 34 + cl/Pylint2Graph/inc/PylintRunner.h | 35 + cl/Pylint2Graph/inc/messages.h | 49 + cl/Pylint2Graph/src/Pylint2Graph.cpp | 247 + cl/Pylint2Graph/src/PylintRulMaker.cpp | 362 + cl/Pylint2Graph/src/PylintRunner.cpp | 74 + cl/Pylint2Graph/src/main.cpp | 225 + inc/ReleaseVersion.h | 2 +- .../columbus-maven-plugin/pom.2.2.1.xml | 2 +- .../columbus-maven-plugin/pom.3.0.5.xml | 2 +- .../columbus-maven-plugin/pom.3.1.0.xml | 2 +- .../maven/plugins/AbstractColumbusMojo.java | 2 +- .../ext/maveninstall/installMavenWrapper.bat | 10 +- .../ext/maveninstall/installMavenWrapper.sh | 10 +- .../maven-agent/pom.xml | 2 +- java/columbus-toolchain-maven-plugin/pom.xml | 12 +- java/lib/langtools | 2 +- lib/controller/inc/Properties.h | 2 +- lib/controller/inc/Task.h | 8 +- lib/controller/src/Controller.cpp | 30 +- lib/controller/src/Task.cpp | 14 +- lib/limmetrics/CMakeLists.txt | 11 +- lib/limmetrics/src/metrics/LCOM5.cpp | 26 +- lib/python/CMakeLists.txt | 217 + lib/python/inc/Common.h | 795 ++ lib/python/inc/Constant.h | 45 + lib/python/inc/Factory.h | 1012 +++ lib/python/inc/Filter.h | 148 + lib/python/inc/Forwards.h | 151 + lib/python/inc/ListIterator.h | 286 + lib/python/inc/PythonCollector.h | 35 + lib/python/inc/PythonException.h | 139 + lib/python/inc/Range.h | 141 + lib/python/inc/ReverseEdges.h | 284 + lib/python/inc/Types.h | 313 + lib/python/inc/algorithms/Algorithm.h | 69 + lib/python/inc/algorithms/AlgorithmPreorder.h | 1298 ++++ lib/python/inc/base/Base.h | 298 + lib/python/inc/base/Comment.h | 202 + lib/python/inc/base/Docstring.h | 202 + lib/python/inc/base/Named.h | 202 + lib/python/inc/base/Positioned.h | 260 + lib/python/inc/expression/ArgumentList.h | 306 + lib/python/inc/expression/AttributeRef.h | 160 + lib/python/inc/expression/Binary.h | 227 + lib/python/inc/expression/BinaryArithmetic.h | 189 + lib/python/inc/expression/BinaryLogical.h | 189 + lib/python/inc/expression/Call.h | 227 + lib/python/inc/expression/DictComp.h | 252 + lib/python/inc/expression/Dictionary.h | 225 + lib/python/inc/expression/Ellipsis.h | 160 + lib/python/inc/expression/Expression.h | 200 + lib/python/inc/expression/ExpressionList.h | 254 + lib/python/inc/expression/ExtSlice.h | 225 + lib/python/inc/expression/FloatNumber.h | 189 + lib/python/inc/expression/Generator.h | 279 + .../inc/expression/GeneratorExpression.h | 252 + lib/python/inc/expression/Identifier.h | 242 + lib/python/inc/expression/IfExpression.h | 254 + lib/python/inc/expression/ImagNumber.h | 206 + lib/python/inc/expression/Index.h | 160 + lib/python/inc/expression/IntegerLiteral.h | 189 + lib/python/inc/expression/KeyValue.h | 227 + lib/python/inc/expression/Keyword.h | 227 + lib/python/inc/expression/Lambda.h | 304 + lib/python/inc/expression/List.h | 254 + lib/python/inc/expression/ListComp.h | 252 + lib/python/inc/expression/Literal.h | 160 + lib/python/inc/expression/LongInteger.h | 189 + lib/python/inc/expression/Set.h | 225 + lib/python/inc/expression/SetComp.h | 252 + lib/python/inc/expression/Slice.h | 254 + lib/python/inc/expression/Slicing.h | 160 + lib/python/inc/expression/StringConversion.h | 200 + lib/python/inc/expression/StringLiteral.h | 202 + lib/python/inc/expression/Subscription.h | 200 + lib/python/inc/expression/Unary.h | 200 + lib/python/inc/expression/UnaryOperation.h | 189 + lib/python/inc/expression/YieldExpression.h | 200 + lib/python/inc/messages.h | 74 + lib/python/inc/module/Module.h | 333 + lib/python/inc/module/Object.h | 319 + lib/python/inc/module/Package.h | 349 + lib/python/inc/python.h | 156 + lib/python/inc/statement/Alias.h | 242 + lib/python/inc/statement/Assert.h | 227 + lib/python/inc/statement/Assign.h | 227 + lib/python/inc/statement/AugAssign.h | 189 + lib/python/inc/statement/BaseSpecifier.h | 227 + lib/python/inc/statement/Break.h | 160 + lib/python/inc/statement/ClassDef.h | 442 ++ lib/python/inc/statement/CompoundStatement.h | 200 + lib/python/inc/statement/Continue.h | 160 + lib/python/inc/statement/Delete.h | 200 + lib/python/inc/statement/Exec.h | 254 + lib/python/inc/statement/For.h | 227 + lib/python/inc/statement/FunctionDef.h | 469 ++ lib/python/inc/statement/Global.h | 225 + lib/python/inc/statement/Handler.h | 254 + lib/python/inc/statement/If.h | 227 + lib/python/inc/statement/ImportFrom.h | 219 + lib/python/inc/statement/ImportStatement.h | 225 + lib/python/inc/statement/Iteration.h | 200 + lib/python/inc/statement/Parameter.h | 256 + lib/python/inc/statement/Pass.h | 160 + lib/python/inc/statement/Print.h | 256 + lib/python/inc/statement/Raise.h | 254 + lib/python/inc/statement/Return.h | 200 + lib/python/inc/statement/SimpleStatement.h | 160 + lib/python/inc/statement/Statement.h | 160 + lib/python/inc/statement/Suite.h | 225 + lib/python/inc/statement/TargetList.h | 225 + lib/python/inc/statement/Try.h | 160 + lib/python/inc/statement/TryExcept.h | 279 + lib/python/inc/statement/TryFinal.h | 200 + lib/python/inc/statement/While.h | 200 + lib/python/inc/statement/With.h | 227 + lib/python/inc/type/DictType.h | 160 + lib/python/inc/type/ReferenceType.h | 242 + lib/python/inc/type/SequenceType.h | 189 + lib/python/inc/type/SimpleType.h | 189 + lib/python/inc/type/Type.h | 160 + lib/python/inc/visitors/Visitor.h | 2337 ++++++ .../inc/visitors/VisitorAbstractNodes.h | 1209 +++ lib/python/inc/visitors/VisitorFilter.h | 471 ++ lib/python/inc/visitors/VisitorPYTHONML.h | 2856 +++++++ lib/python/inc/visitors/VisitorReverseEdges.h | 795 ++ lib/python/inc/visitors/VisitorSave.h | 60 + lib/python/inc/visitors/VisitorSimpleEdge.h | 1492 ++++ .../inc/visitors/VisitorSubtreeCollector.h | 58 + lib/python/src/Common.cpp | 1392 ++++ lib/python/src/Factory.cpp | 1013 +++ lib/python/src/Filter.cpp | 111 + lib/python/src/ListIterator.cpp | 215 + lib/python/src/PythonCollector.cpp | 155 + lib/python/src/PythonException.cpp | 78 + lib/python/src/Range.cpp | 304 + lib/python/src/ReverseEdges.cpp | 279 + lib/python/src/Types.cpp | 27 + lib/python/src/algorithms/Algorithm.cpp | 33 + .../src/algorithms/AlgorithmPreorder.cpp | 5861 ++++++++++++++ lib/python/src/base/Base.cpp | 167 + lib/python/src/base/Comment.cpp | 159 + lib/python/src/base/Docstring.cpp | 159 + lib/python/src/base/Named.cpp | 147 + lib/python/src/base/Positioned.cpp | 254 + lib/python/src/expression/ArgumentList.cpp | 429 ++ lib/python/src/expression/AttributeRef.cpp | 117 + lib/python/src/expression/Binary.cpp | 252 + .../src/expression/BinaryArithmetic.cpp | 133 + lib/python/src/expression/BinaryLogical.cpp | 133 + lib/python/src/expression/Call.cpp | 262 + lib/python/src/expression/DictComp.cpp | 291 + lib/python/src/expression/Dictionary.cpp | 221 + lib/python/src/expression/Ellipsis.cpp | 117 + lib/python/src/expression/Expression.cpp | 177 + lib/python/src/expression/ExpressionList.cpp | 243 + lib/python/src/expression/ExtSlice.cpp | 221 + lib/python/src/expression/FloatNumber.cpp | 133 + lib/python/src/expression/Generator.cpp | 360 + .../src/expression/GeneratorExpression.cpp | 291 + lib/python/src/expression/Identifier.cpp | 231 + lib/python/src/expression/IfExpression.cpp | 333 + lib/python/src/expression/ImagNumber.cpp | 145 + lib/python/src/expression/Index.cpp | 117 + lib/python/src/expression/IntegerLiteral.cpp | 133 + lib/python/src/expression/KeyValue.cpp | 264 + lib/python/src/expression/Keyword.cpp | 264 + lib/python/src/expression/Lambda.cpp | 386 + lib/python/src/expression/List.cpp | 243 + lib/python/src/expression/ListComp.cpp | 291 + lib/python/src/expression/Literal.cpp | 105 + lib/python/src/expression/LongInteger.cpp | 133 + lib/python/src/expression/Set.cpp | 221 + lib/python/src/expression/SetComp.cpp | 291 + lib/python/src/expression/Slice.cpp | 333 + lib/python/src/expression/Slicing.cpp | 105 + .../src/expression/StringConversion.cpp | 195 + lib/python/src/expression/StringLiteral.cpp | 159 + lib/python/src/expression/Subscription.cpp | 195 + lib/python/src/expression/Unary.cpp | 183 + lib/python/src/expression/UnaryOperation.cpp | 133 + lib/python/src/expression/YieldExpression.cpp | 195 + lib/python/src/module/Module.cpp | 414 + lib/python/src/module/Object.cpp | 346 + lib/python/src/module/Package.cpp | 393 + lib/python/src/python.cpp | 22 + lib/python/src/statement/Alias.cpp | 250 + lib/python/src/statement/Assert.cpp | 264 + lib/python/src/statement/Assign.cpp | 264 + lib/python/src/statement/AugAssign.cpp | 133 + lib/python/src/statement/BaseSpecifier.cpp | 258 + lib/python/src/statement/Break.cpp | 117 + lib/python/src/statement/ClassDef.cpp | 592 ++ .../src/statement/CompoundStatement.cpp | 183 + lib/python/src/statement/Continue.cpp | 117 + lib/python/src/statement/Delete.cpp | 195 + lib/python/src/statement/Exec.cpp | 333 + lib/python/src/statement/For.cpp | 264 + lib/python/src/statement/FunctionDef.cpp | 655 ++ lib/python/src/statement/Global.cpp | 221 + lib/python/src/statement/Handler.cpp | 333 + lib/python/src/statement/If.cpp | 264 + lib/python/src/statement/ImportFrom.cpp | 171 + lib/python/src/statement/ImportStatement.cpp | 221 + lib/python/src/statement/Iteration.cpp | 183 + lib/python/src/statement/Parameter.cpp | 292 + lib/python/src/statement/Pass.cpp | 117 + lib/python/src/statement/Print.cpp | 286 + lib/python/src/statement/Raise.cpp | 333 + lib/python/src/statement/Return.cpp | 195 + lib/python/src/statement/SimpleStatement.cpp | 105 + lib/python/src/statement/Statement.cpp | 105 + lib/python/src/statement/Suite.cpp | 221 + lib/python/src/statement/TargetList.cpp | 221 + lib/python/src/statement/Try.cpp | 105 + lib/python/src/statement/TryExcept.cpp | 360 + lib/python/src/statement/TryFinal.cpp | 195 + lib/python/src/statement/While.cpp | 195 + lib/python/src/statement/With.cpp | 264 + lib/python/src/type/DictType.cpp | 117 + lib/python/src/type/ReferenceType.cpp | 235 + lib/python/src/type/SequenceType.cpp | 133 + lib/python/src/type/SimpleType.cpp | 133 + lib/python/src/type/Type.cpp | 105 + lib/python/src/visitors/Visitor.cpp | 734 ++ .../src/visitors/VisitorAbstractNodes.cpp | 687 ++ lib/python/src/visitors/VisitorFilter.cpp | 308 + lib/python/src/visitors/VisitorPYTHONML.cpp | 2801 +++++++ .../src/visitors/VisitorReverseEdges.cpp | 445 ++ lib/python/src/visitors/VisitorSave.cpp | 33 + lib/python/src/visitors/VisitorSimpleEdge.cpp | 1664 ++++ .../src/visitors/VisitorSubtreeCollector.cpp | 33 + lib/rul/inc/RulHandler.h | 6 +- lib/rul/src/RulHandler.cpp | 16 +- 340 files changed, 88127 insertions(+), 4340 deletions(-) create mode 100644 3rdparty/python/pylint/bin/pylint create mode 160000 3rdparty/python2 create mode 160000 3rdparty/python3 create mode 100644 OpenStaticAnalyzer/python/CMakeLists.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/ANTLR-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/BOOST-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/CRYPTO-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/CURL-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/PYTHON-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/XERCES-C-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/Licenses/XERCES-C-NOTICE create mode 100644 OpenStaticAnalyzer/python/Licenses/ZLIB-LICENSE.txt create mode 100644 OpenStaticAnalyzer/python/demo/analyze.bat create mode 100755 OpenStaticAnalyzer/python/demo/analyze.sh create mode 100644 OpenStaticAnalyzer/python/demo/ceilometer.zip create mode 100644 OpenStaticAnalyzer/python/demo/filter_linux.txt create mode 100644 OpenStaticAnalyzer/python/demo/filter_win.txt create mode 100644 OpenStaticAnalyzer/python/doc/usersguide/CMakeLists.txt create mode 100644 OpenStaticAnalyzer/python/doc/usersguide/md/CodeDuplicationMetricsRef.md create mode 100644 OpenStaticAnalyzer/python/doc/usersguide/md/Footnotes.md create mode 100644 OpenStaticAnalyzer/python/doc/usersguide/md/Main.md create mode 100644 OpenStaticAnalyzer/python/doc/usersguide/md/PylintRef.md create mode 100644 OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md rename cl/DuplicatedCodeFinder/inc/{ => Visitors}/CloneVisitorBase.h (99%) rename cl/DuplicatedCodeFinder/inc/{ => Visitors}/CoverageVisitorBase.h (98%) rename cl/DuplicatedCodeFinder/inc/{ => Visitors}/DistanceVisitor.h (100%) rename cl/DuplicatedCodeFinder/inc/{ => Visitors}/JCoverageVisitor.h (96%) rename cl/DuplicatedCodeFinder/inc/{ => Visitors}/NamedVisitor.h (79%) create mode 100644 cl/DuplicatedCodeFinder/inc/Visitors/PCoverageVisitor.h create mode 100644 cl/DuplicatedCodeFinder/inc/Visitors/PNodeEmbeddednessVisitor.h create mode 100644 cl/DuplicatedCodeFinder/src/PNodeEmbeddednessVisitor.cpp create mode 100644 cl/MetricHunter/MetricHunter_PYTHON.threshold create mode 100644 cl/OpenStaticAnalyzerPython/CMakeLists.txt create mode 100644 cl/OpenStaticAnalyzerPython/inc/Properties.h create mode 100644 cl/OpenStaticAnalyzerPython/inc/Task.h create mode 100644 cl/OpenStaticAnalyzerPython/inc/messages.h create mode 100644 cl/OpenStaticAnalyzerPython/rules_python.csv create mode 100644 cl/OpenStaticAnalyzerPython/src/Task.cpp create mode 100644 cl/OpenStaticAnalyzerPython/src/main.cpp create mode 100644 cl/PAN/CMakeLists.txt create mode 100644 cl/PAN/inc/PBuilder.h create mode 100644 cl/PAN/inc/PVisitor.h create mode 100644 cl/PAN/inc/PlLOC.h create mode 100644 cl/PAN/inc/VisitorImport.h create mode 100644 cl/PAN/inc/VisitorType.h create mode 100644 cl/PAN/inc/messages.h create mode 100644 cl/PAN/src/PBuilder.cpp create mode 100644 cl/PAN/src/PVisitor.cpp create mode 100644 cl/PAN/src/VisitorImport.cpp create mode 100644 cl/PAN/src/VisitorType.cpp create mode 100644 cl/PAN/src/main.cpp create mode 100644 cl/PAN/src/plloc.cpp create mode 100644 cl/PAN2Lim/CMakeLists.txt create mode 100644 cl/PAN2Lim/inc/messages.h create mode 100644 cl/PAN2Lim/inc/python2lim.h create mode 100644 cl/PAN2Lim/src/main.cpp create mode 100644 cl/PAN2Lim/src/python2lim.cpp create mode 100644 cl/Pylint2Graph/CMakeLists.txt create mode 100644 cl/Pylint2Graph/Pylint.conf create mode 100644 cl/Pylint2Graph/Pylint.rul create mode 100644 cl/Pylint2Graph/inc/Pylint2Graph.h create mode 100644 cl/Pylint2Graph/inc/PylintRulMaker.h create mode 100644 cl/Pylint2Graph/inc/PylintRunner.h create mode 100644 cl/Pylint2Graph/inc/messages.h create mode 100644 cl/Pylint2Graph/src/Pylint2Graph.cpp create mode 100644 cl/Pylint2Graph/src/PylintRulMaker.cpp create mode 100644 cl/Pylint2Graph/src/PylintRunner.cpp create mode 100644 cl/Pylint2Graph/src/main.cpp create mode 100644 lib/python/CMakeLists.txt create mode 100644 lib/python/inc/Common.h create mode 100644 lib/python/inc/Constant.h create mode 100644 lib/python/inc/Factory.h create mode 100644 lib/python/inc/Filter.h create mode 100644 lib/python/inc/Forwards.h create mode 100644 lib/python/inc/ListIterator.h create mode 100644 lib/python/inc/PythonCollector.h create mode 100644 lib/python/inc/PythonException.h create mode 100644 lib/python/inc/Range.h create mode 100644 lib/python/inc/ReverseEdges.h create mode 100644 lib/python/inc/Types.h create mode 100644 lib/python/inc/algorithms/Algorithm.h create mode 100644 lib/python/inc/algorithms/AlgorithmPreorder.h create mode 100644 lib/python/inc/base/Base.h create mode 100644 lib/python/inc/base/Comment.h create mode 100644 lib/python/inc/base/Docstring.h create mode 100644 lib/python/inc/base/Named.h create mode 100644 lib/python/inc/base/Positioned.h create mode 100644 lib/python/inc/expression/ArgumentList.h create mode 100644 lib/python/inc/expression/AttributeRef.h create mode 100644 lib/python/inc/expression/Binary.h create mode 100644 lib/python/inc/expression/BinaryArithmetic.h create mode 100644 lib/python/inc/expression/BinaryLogical.h create mode 100644 lib/python/inc/expression/Call.h create mode 100644 lib/python/inc/expression/DictComp.h create mode 100644 lib/python/inc/expression/Dictionary.h create mode 100644 lib/python/inc/expression/Ellipsis.h create mode 100644 lib/python/inc/expression/Expression.h create mode 100644 lib/python/inc/expression/ExpressionList.h create mode 100644 lib/python/inc/expression/ExtSlice.h create mode 100644 lib/python/inc/expression/FloatNumber.h create mode 100644 lib/python/inc/expression/Generator.h create mode 100644 lib/python/inc/expression/GeneratorExpression.h create mode 100644 lib/python/inc/expression/Identifier.h create mode 100644 lib/python/inc/expression/IfExpression.h create mode 100644 lib/python/inc/expression/ImagNumber.h create mode 100644 lib/python/inc/expression/Index.h create mode 100644 lib/python/inc/expression/IntegerLiteral.h create mode 100644 lib/python/inc/expression/KeyValue.h create mode 100644 lib/python/inc/expression/Keyword.h create mode 100644 lib/python/inc/expression/Lambda.h create mode 100644 lib/python/inc/expression/List.h create mode 100644 lib/python/inc/expression/ListComp.h create mode 100644 lib/python/inc/expression/Literal.h create mode 100644 lib/python/inc/expression/LongInteger.h create mode 100644 lib/python/inc/expression/Set.h create mode 100644 lib/python/inc/expression/SetComp.h create mode 100644 lib/python/inc/expression/Slice.h create mode 100644 lib/python/inc/expression/Slicing.h create mode 100644 lib/python/inc/expression/StringConversion.h create mode 100644 lib/python/inc/expression/StringLiteral.h create mode 100644 lib/python/inc/expression/Subscription.h create mode 100644 lib/python/inc/expression/Unary.h create mode 100644 lib/python/inc/expression/UnaryOperation.h create mode 100644 lib/python/inc/expression/YieldExpression.h create mode 100644 lib/python/inc/messages.h create mode 100644 lib/python/inc/module/Module.h create mode 100644 lib/python/inc/module/Object.h create mode 100644 lib/python/inc/module/Package.h create mode 100644 lib/python/inc/python.h create mode 100644 lib/python/inc/statement/Alias.h create mode 100644 lib/python/inc/statement/Assert.h create mode 100644 lib/python/inc/statement/Assign.h create mode 100644 lib/python/inc/statement/AugAssign.h create mode 100644 lib/python/inc/statement/BaseSpecifier.h create mode 100644 lib/python/inc/statement/Break.h create mode 100644 lib/python/inc/statement/ClassDef.h create mode 100644 lib/python/inc/statement/CompoundStatement.h create mode 100644 lib/python/inc/statement/Continue.h create mode 100644 lib/python/inc/statement/Delete.h create mode 100644 lib/python/inc/statement/Exec.h create mode 100644 lib/python/inc/statement/For.h create mode 100644 lib/python/inc/statement/FunctionDef.h create mode 100644 lib/python/inc/statement/Global.h create mode 100644 lib/python/inc/statement/Handler.h create mode 100644 lib/python/inc/statement/If.h create mode 100644 lib/python/inc/statement/ImportFrom.h create mode 100644 lib/python/inc/statement/ImportStatement.h create mode 100644 lib/python/inc/statement/Iteration.h create mode 100644 lib/python/inc/statement/Parameter.h create mode 100644 lib/python/inc/statement/Pass.h create mode 100644 lib/python/inc/statement/Print.h create mode 100644 lib/python/inc/statement/Raise.h create mode 100644 lib/python/inc/statement/Return.h create mode 100644 lib/python/inc/statement/SimpleStatement.h create mode 100644 lib/python/inc/statement/Statement.h create mode 100644 lib/python/inc/statement/Suite.h create mode 100644 lib/python/inc/statement/TargetList.h create mode 100644 lib/python/inc/statement/Try.h create mode 100644 lib/python/inc/statement/TryExcept.h create mode 100644 lib/python/inc/statement/TryFinal.h create mode 100644 lib/python/inc/statement/While.h create mode 100644 lib/python/inc/statement/With.h create mode 100644 lib/python/inc/type/DictType.h create mode 100644 lib/python/inc/type/ReferenceType.h create mode 100644 lib/python/inc/type/SequenceType.h create mode 100644 lib/python/inc/type/SimpleType.h create mode 100644 lib/python/inc/type/Type.h create mode 100644 lib/python/inc/visitors/Visitor.h create mode 100644 lib/python/inc/visitors/VisitorAbstractNodes.h create mode 100644 lib/python/inc/visitors/VisitorFilter.h create mode 100644 lib/python/inc/visitors/VisitorPYTHONML.h create mode 100644 lib/python/inc/visitors/VisitorReverseEdges.h create mode 100644 lib/python/inc/visitors/VisitorSave.h create mode 100644 lib/python/inc/visitors/VisitorSimpleEdge.h create mode 100644 lib/python/inc/visitors/VisitorSubtreeCollector.h create mode 100644 lib/python/src/Common.cpp create mode 100644 lib/python/src/Factory.cpp create mode 100644 lib/python/src/Filter.cpp create mode 100644 lib/python/src/ListIterator.cpp create mode 100644 lib/python/src/PythonCollector.cpp create mode 100644 lib/python/src/PythonException.cpp create mode 100644 lib/python/src/Range.cpp create mode 100644 lib/python/src/ReverseEdges.cpp create mode 100644 lib/python/src/Types.cpp create mode 100644 lib/python/src/algorithms/Algorithm.cpp create mode 100644 lib/python/src/algorithms/AlgorithmPreorder.cpp create mode 100644 lib/python/src/base/Base.cpp create mode 100644 lib/python/src/base/Comment.cpp create mode 100644 lib/python/src/base/Docstring.cpp create mode 100644 lib/python/src/base/Named.cpp create mode 100644 lib/python/src/base/Positioned.cpp create mode 100644 lib/python/src/expression/ArgumentList.cpp create mode 100644 lib/python/src/expression/AttributeRef.cpp create mode 100644 lib/python/src/expression/Binary.cpp create mode 100644 lib/python/src/expression/BinaryArithmetic.cpp create mode 100644 lib/python/src/expression/BinaryLogical.cpp create mode 100644 lib/python/src/expression/Call.cpp create mode 100644 lib/python/src/expression/DictComp.cpp create mode 100644 lib/python/src/expression/Dictionary.cpp create mode 100644 lib/python/src/expression/Ellipsis.cpp create mode 100644 lib/python/src/expression/Expression.cpp create mode 100644 lib/python/src/expression/ExpressionList.cpp create mode 100644 lib/python/src/expression/ExtSlice.cpp create mode 100644 lib/python/src/expression/FloatNumber.cpp create mode 100644 lib/python/src/expression/Generator.cpp create mode 100644 lib/python/src/expression/GeneratorExpression.cpp create mode 100644 lib/python/src/expression/Identifier.cpp create mode 100644 lib/python/src/expression/IfExpression.cpp create mode 100644 lib/python/src/expression/ImagNumber.cpp create mode 100644 lib/python/src/expression/Index.cpp create mode 100644 lib/python/src/expression/IntegerLiteral.cpp create mode 100644 lib/python/src/expression/KeyValue.cpp create mode 100644 lib/python/src/expression/Keyword.cpp create mode 100644 lib/python/src/expression/Lambda.cpp create mode 100644 lib/python/src/expression/List.cpp create mode 100644 lib/python/src/expression/ListComp.cpp create mode 100644 lib/python/src/expression/Literal.cpp create mode 100644 lib/python/src/expression/LongInteger.cpp create mode 100644 lib/python/src/expression/Set.cpp create mode 100644 lib/python/src/expression/SetComp.cpp create mode 100644 lib/python/src/expression/Slice.cpp create mode 100644 lib/python/src/expression/Slicing.cpp create mode 100644 lib/python/src/expression/StringConversion.cpp create mode 100644 lib/python/src/expression/StringLiteral.cpp create mode 100644 lib/python/src/expression/Subscription.cpp create mode 100644 lib/python/src/expression/Unary.cpp create mode 100644 lib/python/src/expression/UnaryOperation.cpp create mode 100644 lib/python/src/expression/YieldExpression.cpp create mode 100644 lib/python/src/module/Module.cpp create mode 100644 lib/python/src/module/Object.cpp create mode 100644 lib/python/src/module/Package.cpp create mode 100644 lib/python/src/python.cpp create mode 100644 lib/python/src/statement/Alias.cpp create mode 100644 lib/python/src/statement/Assert.cpp create mode 100644 lib/python/src/statement/Assign.cpp create mode 100644 lib/python/src/statement/AugAssign.cpp create mode 100644 lib/python/src/statement/BaseSpecifier.cpp create mode 100644 lib/python/src/statement/Break.cpp create mode 100644 lib/python/src/statement/ClassDef.cpp create mode 100644 lib/python/src/statement/CompoundStatement.cpp create mode 100644 lib/python/src/statement/Continue.cpp create mode 100644 lib/python/src/statement/Delete.cpp create mode 100644 lib/python/src/statement/Exec.cpp create mode 100644 lib/python/src/statement/For.cpp create mode 100644 lib/python/src/statement/FunctionDef.cpp create mode 100644 lib/python/src/statement/Global.cpp create mode 100644 lib/python/src/statement/Handler.cpp create mode 100644 lib/python/src/statement/If.cpp create mode 100644 lib/python/src/statement/ImportFrom.cpp create mode 100644 lib/python/src/statement/ImportStatement.cpp create mode 100644 lib/python/src/statement/Iteration.cpp create mode 100644 lib/python/src/statement/Parameter.cpp create mode 100644 lib/python/src/statement/Pass.cpp create mode 100644 lib/python/src/statement/Print.cpp create mode 100644 lib/python/src/statement/Raise.cpp create mode 100644 lib/python/src/statement/Return.cpp create mode 100644 lib/python/src/statement/SimpleStatement.cpp create mode 100644 lib/python/src/statement/Statement.cpp create mode 100644 lib/python/src/statement/Suite.cpp create mode 100644 lib/python/src/statement/TargetList.cpp create mode 100644 lib/python/src/statement/Try.cpp create mode 100644 lib/python/src/statement/TryExcept.cpp create mode 100644 lib/python/src/statement/TryFinal.cpp create mode 100644 lib/python/src/statement/While.cpp create mode 100644 lib/python/src/statement/With.cpp create mode 100644 lib/python/src/type/DictType.cpp create mode 100644 lib/python/src/type/ReferenceType.cpp create mode 100644 lib/python/src/type/SequenceType.cpp create mode 100644 lib/python/src/type/SimpleType.cpp create mode 100644 lib/python/src/type/Type.cpp create mode 100644 lib/python/src/visitors/Visitor.cpp create mode 100644 lib/python/src/visitors/VisitorAbstractNodes.cpp create mode 100644 lib/python/src/visitors/VisitorFilter.cpp create mode 100644 lib/python/src/visitors/VisitorPYTHONML.cpp create mode 100644 lib/python/src/visitors/VisitorReverseEdges.cpp create mode 100644 lib/python/src/visitors/VisitorSave.cpp create mode 100644 lib/python/src/visitors/VisitorSimpleEdge.cpp create mode 100644 lib/python/src/visitors/VisitorSubtreeCollector.cpp diff --git a/.gitmodules b/.gitmodules index 211d6f2..830b4e7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,9 @@ [submodule "java/lib/langtools"] path = java/lib/langtools url = https://github.com/sed-inf-u-szeged/langtools.git +[submodule "3rdparty/python2"] + path = 3rdparty/python2 + url = ../cpython +[submodule "3rdparty/python3"] + path = 3rdparty/python3 + url = ../cpython diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 8017196..f6d5061 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -88,9 +88,9 @@ endif () if (CMAKE_SYSTEM_NAME STREQUAL Linux) ExternalProject_Add( xerces-c - SVN_REPOSITORY https://svn.apache.org/repos/asf/xerces/c/tags/Xerces-C_3_1_4 - BUILD_IN_SOURCE 1 - UPDATE_COMMAND "" + URL http://archive.apache.org/dist/xerces/c/3/sources/xerces-c-3.1.4.tar.gz + URL_HASH MD5=21bb097b711a513275379b59757cba4c + BUILD_IN_SOURCE 1 CONFIGURE_COMMAND ./reconf COMMAND ./configure --disable-shared -disable-network --disable-transcoder-icu --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} BUILD_COMMAND make -j8 all @@ -111,16 +111,15 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) endif () ExternalProject_Add( xerces-c - SVN_REPOSITORY https://svn.apache.org/repos/asf/xerces/c/tags/Xerces-C_3_1_4 + URL http://archive.apache.org/dist/xerces/c/3/sources/xerces-c-3.1.4.zip + URL_HASH MD5=6fcd8ec268f6bfe11d8ce2cd7d25a185 BUILD_IN_SOURCE 1 - UPDATE_COMMAND "" CONFIGURE_COMMAND ${CMAKE_COMMAND} -E echo "No configuration is required." BUILD_COMMAND msbuild projects/Win32/VC14/xerces-all/xerces-all.sln /m /t:XercesLib "/p:Configuration=Static $" /p:Platform=${VS_PLATFORM} /p:PlatformToolset=${CMAKE_VS_PLATFORM_TOOLSET} INSTALL_COMMAND ${CMAKE_COMMAND} "-DCOPY_SOURCE=${CMAKE_CURRENT_BINARY_DIR}/xerces-c-prefix/src/xerces-c/src/xercesc/" "-DCOPY_TARGET=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/xercesc" -DCOPY_PATTERN=*.hpp -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/SearchAndCopyFiles.cmake COMMAND ${CMAKE_COMMAND} "-DCOPY_SOURCE=${CMAKE_CURRENT_BINARY_DIR}/xerces-c-prefix/src/xerces-c/src/xercesc/" "-DCOPY_TARGET=${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/xercesc" -DCOPY_PATTERN=*.c -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/SearchAndCopyFiles.cmake COMMAND ${CMAKE_COMMAND} -E copy "Build/${XERCESC_BUILD_OUTPUT_DIR}/VC14/Static $/xerces-c_static_3$<$:d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/xerces-c.lib LOG_DOWNLOAD 1 - LOG_UPDATE 1 LOG_CONFIGURE 1 LOG_BUILD 1 LOG_INSTALL 1 @@ -151,3 +150,69 @@ add_custom_target ( ) set_target_properties (PMD PROPERTIES FOLDER "ExternalProjectTargets/pmd") + +########################### python27 ######################### +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + + ExternalProject_Add( python2.7 + DEPENDS zlib + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python2 + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND ./configure --enable-optimizations --disable-shared --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} + BUILD_COMMAND make -j8 altbininstall inclinstall + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "No install step is required as the build step installs the library." + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + if (COLUMBUS_64BIT) + set (PYTHON_BUILD_OUTPUT_DIR amd64) + endif () + + ExternalProject_Add( python2.7 + DEPENDS zlib + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python2 + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND msbuild PCbuild/pythoncore.vcxproj /m /t:Build /p:Configuration=$ /p:Platform=${VS_PLATFORM} /p:PlatformToolset=${CMAKE_VS_PLATFORM_TOOLSET} + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory Include ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python2.7 + COMMAND ${CMAKE_COMMAND} -E copy "PC/pyconfig.h" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python2.7/pyconfig.h + COMMAND ${CMAKE_COMMAND} -E copy "PCbuild/${PYTHON_BUILD_OUTPUT_DIR}/python27$<$:_d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/python2.7.lib + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) + +endif () + +########################### python36 ######################### +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + + ExternalProject_Add( python3.6 + DEPENDS zlib + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python3 + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND ./configure --enable-optimizations --disable-shared --prefix=${COLUMBUS_3RDPARTY_INSTALL_DIR} --without-pymalloc + BUILD_COMMAND make -j8 altbininstall inclinstall + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "No install step is required as the build step installs the library." + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + + ExternalProject_Add( python3.6 + DEPENDS zlib + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python3 + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND msbuild PCbuild/pythoncore.vcxproj /m /t:Build /p:Configuration=$ /p:Platform=${VS_PLATFORM} /p:PlatformToolset=${CMAKE_VS_PLATFORM_TOOLSET} + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory Include ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python3.6 + COMMAND ${CMAKE_COMMAND} -E copy "PC/pyconfig.h" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/include/python3.6/pyconfig.h + COMMAND ${CMAKE_COMMAND} -E copy "PCbuild/${PYTHON_PLATFORM_NAME}/python36$<$:_d>.lib" ${COLUMBUS_3RDPARTY_INSTALL_DIR}/lib/python3.6.lib + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) +endif () diff --git a/3rdparty/python/pylint/bin/pylint b/3rdparty/python/pylint/bin/pylint new file mode 100644 index 0000000..a63cdcc --- /dev/null +++ b/3rdparty/python/pylint/bin/pylint @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +import sys + +if __name__ == '__main__': + from pylint.lint import Run + Run(sys.argv[1:], exit=False) + sys.exit(0) diff --git a/3rdparty/python2 b/3rdparty/python2 new file mode 160000 index 0000000..56a58ee --- /dev/null +++ b/3rdparty/python2 @@ -0,0 +1 @@ +Subproject commit 56a58ee1830b786593b1b74f0a311d5922161e91 diff --git a/3rdparty/python3 b/3rdparty/python3 new file mode 160000 index 0000000..63aa5b5 --- /dev/null +++ b/3rdparty/python3 @@ -0,0 +1 @@ +Subproject commit 63aa5b52af63af24d8c1e9f4c6abbc82cdacdd18 diff --git a/CMake/PlatformOptions.cmake b/CMake/PlatformOptions.cmake index f306833..3289e08 100644 --- a/CMake/PlatformOptions.cmake +++ b/CMake/PlatformOptions.cmake @@ -10,10 +10,12 @@ if (COLUMBUS_64BIT) set (COLUMBUS_PLATFORM_NAME x64) set (VS_PLATFORM x64) set (VS_PLATFORM_DIR x64/) + set (PYTHON_PLATFORM_NAME amd64) else () set (COLUMBUS_PLATFORM_NAME x86) set (VS_PLATFORM WIN32) set (VS_PLATFORM_DIR ) + set (PYTHON_PLATFORM_NAME win32) endif () if (CMAKE_SYSTEM_NAME STREQUAL Windows) diff --git a/CMake/UtilityFunctions.cmake b/CMake/UtilityFunctions.cmake index 075b7db..e7c0363 100644 --- a/CMake/UtilityFunctions.cmake +++ b/CMake/UtilityFunctions.cmake @@ -20,6 +20,9 @@ function (set_schema_language_compiler_settings TARGET SCHEMA) if (SCHEMA STREQUAL "java") target_compile_definitions(${TARGET} PUBLIC SCHEMA_JAVA) target_link_libraries(${TARGET} java) + elseif (SCHEMA STREQUAL "python") + target_compile_definitions(${TARGET} PUBLIC SCHEMA_PYTHON) + target_link_libraries(${TARGET} python) else () message (FATAL_ERROR "Unknown schema language: ${SCHEMA}") endif () diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ef2c22..1ace721 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ if (NOT CMAKE_BUILD_TYPE ) set (CMAKE_BUILD_TYPE Release CACHE STRING "Build Type: Release or Debug" FORCE) endif() -project (OSA VERSION 1.0.0) +project (OSA VERSION 2.0.0) set (EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${EXECUTABLE_OUTPUT_PATH}) @@ -38,8 +38,12 @@ add_subdirectory (cl/JANFilter) add_subdirectory (cl/JANLink) add_subdirectory (cl/LIM2Metrics) add_subdirectory (cl/MetricHunter) +add_subdirectory (cl/PAN) +add_subdirectory (cl/PAN2Lim) add_subdirectory (cl/PMD2Graph) +add_subdirectory (cl/Pylint2Graph) add_subdirectory (cl/OpenStaticAnalyzerJava) +add_subdirectory (cl/OpenStaticAnalyzerPython) add_subdirectory (wrapper/AbstractWrapperLib) add_subdirectory (wrapper/AnalyzerWrapperConfig) @@ -61,6 +65,7 @@ add_subdirectory (lib/java) add_subdirectory (lib/lim) add_subdirectory (lib/lim2graph) add_subdirectory (lib/limmetrics) +add_subdirectory (lib/python) add_subdirectory (lib/rul) add_subdirectory (lib/strtable) add_subdirectory (lib/threadpool) diff --git a/OpenStaticAnalyzer/CMakeLists.txt b/OpenStaticAnalyzer/CMakeLists.txt index 2299016..afef5a6 100644 --- a/OpenStaticAnalyzer/CMakeLists.txt +++ b/OpenStaticAnalyzer/CMakeLists.txt @@ -13,6 +13,7 @@ endif () add_custom_target ( ${OSA_TARGET_NAME} DEPENDS OSA-Java + DEPENDS OSA-Python COMMAND ${CMAKE_COMMAND} -E ${COMPRESS_COMMAND} ) @@ -49,3 +50,4 @@ function (copy_licenses) endfunction () add_subdirectory (java) +add_subdirectory (python) diff --git a/OpenStaticAnalyzer/doc/readme.txt b/OpenStaticAnalyzer/doc/readme.txt index 433a48b..26e7e21 100644 --- a/OpenStaticAnalyzer/doc/readme.txt +++ b/OpenStaticAnalyzer/doc/readme.txt @@ -1,6 +1,6 @@ OpenStaticAnalyzer is a source code analyzer tool, which can perform deep static analysis of the source code of complex software systems implemented in -Java programming languages. +Java or Python programming languages. The source code of a program is usually its only up-to-date documentation. At the same time, the source code is the exquisite bearer of knowledge, business @@ -13,10 +13,13 @@ and is merely considered as a tool. Product characteristics The most important product characteristics of OpenStaticAnalyzer are the following: -* Support Java 8 +* Support for Java 8, Python 2.7.x and 3.6.x * Platform-independent command line tools * Transparent integration into build processes * Powerful filter management +* Coding issue detection + - Metric threshold violations + - Integration of popular free tools (PMD, FindBugs, Pylint) * Clone detection (copy-pasted source code fragments) extended with clone tracking and "clone smells" - Syntax-based, so-called Type-2 clones @@ -35,4 +38,4 @@ By continuous static analysis, the software developers can: operational risks can be decreased, increasing the company's reputation. For more information about OpenStaticAnalyzer please read the files UsersGuide.html, -which can be found in the Java subdirectory of the package. +which can be found in the Java and Python subdirectories of the package. diff --git a/OpenStaticAnalyzer/java/CMakeLists.txt b/OpenStaticAnalyzer/java/CMakeLists.txt index 2c8e73d..67a1141 100644 --- a/OpenStaticAnalyzer/java/CMakeLists.txt +++ b/OpenStaticAnalyzer/java/CMakeLists.txt @@ -46,8 +46,8 @@ add_custom_generated_copy_dependency_to_tools_dir (GraphMerge${EXE}) add_custom_generated_copy_dependency_to_tools_dir (JAN2ChangePath${EXE}) add_custom_generated_copy_dependency_to_tools_dir (JAN2Lim${EXE}) add_custom_generated_copy_dependency_to_tools_dir (JANFilter${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (LIM2Metrics_java${EXE} LIM2Metrics_java LIM2Metrics${EXE}) -add_custom_generated_copy_dependency_to_tools_dir (MET.rul LIM2Metrics_java) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Metrics${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (MET.rul LIM2Metrics) add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_java${EXE} MetricHunter_java MetricHunter${EXE}) add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_JAVA.threshold MetricHunter_java_copy_MetricHunter_JAVA.threshold MetricHunter.threshold) add_custom_generated_copy_dependency_to_tools_dir (PMD2Graph${EXE}) @@ -137,16 +137,16 @@ set (MAVEN_PLUGIN_DIR ${CMAKE_SOURCE_DIR}/java/columbus-toolchain-maven-plugin) add_custom_create_file_target ( ${OSA_TARGET_NAME} - ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-8.2.jar + ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-2.0.jar ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-Maven-plugin-mojo-executer-2.2.1.jar ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-Maven-plugin-mojo-executer-2.2.1.pom ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-Maven-plugin-mojo-executer-3.0.jar ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-Maven-plugin-mojo-executer-3.0.pom ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-Maven-plugin-mojo-executer-3.1.jar ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-Maven-plugin-mojo-executer-3.1.pom - ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-8.2-V2.pom - ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-8.2-V3.pom - ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-8.2-V31.pom + ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-2.0-V2.pom + ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-2.0-V3.pom + ${WRAPPER_TOOLS_DIR}/OpenStaticAnalyzer-maven-plugin-2.0-V31.pom ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/installMavenWrapper${SCRIPT_EXT} COMMAND mvn${MVN_POSTFIX} install -f ${MAVEN_PLUGIN_DIR}/ext/mojoExecutorModule/v3/pom.xml > ${CMAKE_CURRENT_BINARY_DIR}/v3install.log COMMAND mvn${MVN_POSTFIX} install -f ${MAVEN_PLUGIN_DIR}/ext/mojoExecutorModule/v31/pom.xml > ${CMAKE_CURRENT_BINARY_DIR}/v31install.log diff --git a/OpenStaticAnalyzer/java/doc/usersguide/md/CodeDuplicationMetricsRef.md b/OpenStaticAnalyzer/java/doc/usersguide/md/CodeDuplicationMetricsRef.md index e8a6a4f..fa17ebd 100644 --- a/OpenStaticAnalyzer/java/doc/usersguide/md/CodeDuplicationMetricsRef.md +++ b/OpenStaticAnalyzer/java/doc/usersguide/md/CodeDuplicationMetricsRef.md @@ -36,11 +36,14 @@ The following table summarizes the code duplication metrics, their abbreviations Clone Classes CCL X X X X X X Clone Complexity CCO X X X X X X X X Clone Coverage CC X X X X X X + Clone Elimination Effort CEE X X + Clone Elimination Gain CEG X X Clone Embeddedness CE X X Clone Instances CI X X X X X X X Clone Line Coverage CLC X X X X X X Clone Lines of Code CLLOC X X Clone Logical Line Coverage CLLC X X X X X X + Clone Risk CR X X Clone Variability CV X X Lines of Duplicated Code LDC X X X X X X Logical Lines of Duplicated Code LLDC X X X X X X @@ -74,6 +77,18 @@ The following table summarizes the code duplication metrics, their abbreviations **Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). +#### Clone Elimination Effort (CEE) {#CEE} + +**Clone class:** index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR. + +**Component:** index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. + +#### Clone Elimination Gain (CEG) {#CEG} + +**Clone class:** index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE. + +**Component:** index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. + #### Clone Embeddedness (CE) {#CE} **Clone instance:** sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments. @@ -106,6 +121,12 @@ The following table summarizes the code duplication metrics, their abbreviations **Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). +#### Clone Risk (CR) {#CR} + +**Clone class:** risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV. + +**Component:** relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. + #### Clone Variability (CV) {#CV} **Clone instance:** instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA). diff --git a/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md b/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md index ebfc6cd..28de874 100644 --- a/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md +++ b/OpenStaticAnalyzer/java/doc/usersguide/md/Main.md @@ -120,27 +120,29 @@ The OpenStaticAnalyzer for Java package contains the following directories and f Windows: ------------------ ----------------------- -------------------------------------- -OpenStaticAnalyzer\\Java\\ - Demo \# Example project directory - WindowsTools \# ASG checker and exporter tools directory - WindowsWrapper \# Wrapper and analyzer tools directory - OpenStaticAnalyzerJava.exe \# Program file to execute the analysis - installMavenWrapper.bat \# Batch file to install the Maven wrapper - UsersGuide.html \# User's guide ------------------ ----------------------- --------------------------------------- +| | | | +|----------------------------|----------------------------|-----------------------------------------------| +|OpenStaticAnalyzer\\Java\\ | | | +| | Demo | \# Example project directory | +| | WindowsTools | \# ASG checker and exporter tools directory | +| | WindowsWrapper | \# Wrapper and analyzer tools directory | +| | OpenStaticAnalyzerJava.exe | \# Program file to execute the analysis | +| | installMavenWrapper.bat | \# Batch file to install the Maven wrapper | +| | UsersGuide.html | \# User's guide | + Linux: -------------------- ----------------------- -------------------------------------- -OpenStaticAnalyzer/Java/ - Demo \# Example project directory - LinuxTools \# ASG checker and exporter tools directory - LinuxWrapper \# Wrapper and analyzer tools directory - OpenStaticAnalyzerJava \# Program file to execute the analysis - installMavenWrapper.sh \# Shell script to install the Maven wrapper - UsersGuide.html \# User's guide -------------------- ----------------------- -------------------------------------- +| | | | +|----------------------------|---------------------------|---------------------------------------------| +|OpenStaticAnalyzer/Java/ | | | +| | Demo | \# Example project directory | +| | LinuxTools | \# ASG checker and exporter tools directory | +| | LinuxWrapper | \# Wrapper and analyzer tools directory | +| | OpenStaticAnalyzerJava | \# Program file to execute the analysis | +| | installMavenWrapper.sh | \# Shell script to install the Maven wrapper| +| | UsersGuide.html | \# User's guide | + To analyze Maven based projects, installMavenWrapper.bat (in case of Windows) or installMavenWrapper.sh (in case of Linux) must be executed in an environment where all the necessary environment variables of Maven are set and the user has write privilege for the Maven repository required for the install. @@ -309,12 +311,12 @@ Source code elements in the files marked with darker background will not be cons : There are certain rule violations that are computed by more than one tool. E.g. ADLIBDC (Avoid Decimal Literals In BigDecimal Constructor) is checked by both FindBugs and PMD. In these cases, in order to avoid duplications, there is a priority order among the tools. This parameter can be used to override these default priorizations by specifying a .csv file in the following format: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.csv} - toolId;FH;AH;VH;FB;PMD + toolId;FB;PMD ... - ADLIBDC;-;-;-;1;2 - ADNIS;1;-;-;-;2 - ADS;-;-;-;-;1 - AEAI;-;-;-;-;1 + ADLIBDC;1;2 + ADNIS;-;1 + ADS;-;1 + AEAI;-;1 ... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -372,7 +374,7 @@ Source code elements in the files marked with darker background will not be cons **-FBOptions** - : Extra command line parameters for FindBugs can be set with this option. For instance if some auxiliary classes are needed, these can be set by adding the –FBOptions="–auxclasspath external.jar" option. + : Extra command line parameters for FindBugs can be set with this option. For instance if some auxiliary classes are needed, these can be set by adding the -FBOptions="-auxclasspath external.jar" option. **-runPMD** diff --git a/OpenStaticAnalyzer/java/doc/usersguide/md/PMDRef.md b/OpenStaticAnalyzer/java/doc/usersguide/md/PMDRef.md index 85af16f..391eb2f 100644 --- a/OpenStaticAnalyzer/java/doc/usersguide/md/PMDRef.md +++ b/OpenStaticAnalyzer/java/doc/usersguide/md/PMDRef.md @@ -1,6 +1,6 @@ ## Reference of PMD coding rule violations -OpenStaticAnalyzer incorporates the [PMD] tool for coding rule violation checking and imports its results. OpenStaticAnalyzer also associates the issued rule violations with source code elements (i.e. methods, classes, packages, and components), and calculates metrics for the source code elements, which represent the amount of violations of each ruleset, rule, and priority groups, respectively. In addition, OpenStaticAnalyzer uses an optimized PMD setting, where the poorly performing PMD rule checks are disabled, and all other rules are reprioritized by our software developer and QA experts. Please note that if a valid FaultHunter license key is available, then the reimplemented PMD rules will be swithed off automatically and FaultHunter will provide the results instead. If no license key is available (free version), then the original PMD rule violation checks will be executed. +OpenStaticAnalyzer incorporates the [PMD] tool for coding rule violation checking and imports its results. OpenStaticAnalyzer also associates the issued rule violations with source code elements (i.e. methods, classes, packages, and components), and calculates metrics for the source code elements, which represent the amount of violations of each ruleset, rule, and priority groups, respectively. In addition, OpenStaticAnalyzer uses an optimized PMD setting, where the poorly performing PMD rule checks are disabled, and all other rules are reprioritized by our software developer and QA experts. OpenStaticAnalyzer uses PMD "as is", without any guaranties that the results of PMD are correct. All statements of the PMD license apply here as well. All texts describing the rulesets and the individual rules are copied from its official home page with some minor grammatical fixes. diff --git a/OpenStaticAnalyzer/python/CMakeLists.txt b/OpenStaticAnalyzer/python/CMakeLists.txt new file mode 100644 index 0000000..cc6ffc3 --- /dev/null +++ b/OpenStaticAnalyzer/python/CMakeLists.txt @@ -0,0 +1,75 @@ +set (PACKAGE_LANG Python) +set (OSA_TARGET_NAME OSA-${PACKAGE_LANG}) + +add_subdirectory (doc/usersguide) + +add_custom_target ( + ${OSA_TARGET_NAME} +) +set_visual_studio_project_folder(${OSA_TARGET_NAME} FALSE) + +file (MAKE_DIRECTORY + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools +) + +# These functions copy the SOURCE file into different directories of the OpenStaticAnalyzer package. +# The second parameter is optional. You can set the name of the target, which will be used for generating the SOURCE. +# The third parameter is also optional. You can set a different name for the SOURCE on which the file will be created in the tools directory. +function (add_custom_generated_copy_dependency_to_root_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG} ${ARGV}) +endfunction () + +function (add_custom_generated_copy_dependency_to_tools_dir SOURCE) + add_custom_generated_copy_dependency(${OSA_TARGET_NAME} ${EXECUTABLE_OUTPUT_PATH} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools ${ARGV}) +endfunction () + +add_custom_generated_copy_dependency_to_root_dir (OpenStaticAnalyzerPython${EXE}) + +add_custom_generated_copy_dependency_to_tools_dir (rules_python.csv OpenStaticAnalyzerPython) +add_custom_generated_copy_dependency_to_tools_dir (DuplicatedCodeFinder_python${EXE} DuplicatedCodeFinder_python DuplicatedCodeFinder${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (DCF.rul DuplicatedCodeFinder_python_copy_DCF.rul) +add_custom_generated_copy_dependency_to_tools_dir (GraphDump${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (GraphMerge${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (LIM2Metrics${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (MET.rul LIM2Metrics) +add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_python${EXE} MetricHunter_python MetricHunter${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (MetricHunter_PYTHON.threshold MetricHunter_python_copy_MetricHunter_PYTHON.threshold MetricHunter.threshold) +add_custom_generated_copy_dependency_to_tools_dir (PAN2${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (PAN3${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (PAN2Lim${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Pylint2Graph${EXE}) +add_custom_generated_copy_dependency_to_tools_dir (Pylint.rul Pylint2Graph) +add_custom_generated_copy_dependency_to_tools_dir (Pylint.conf Pylint2Graph) + +add_custom_generated_copy_dependency( + ${OSA_TARGET_NAME} + doc/usersguide + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG} + UsersGuide.html + ${OSA_TARGET_NAME}-UG +) + +add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/analyze${SCRIPT_EXT} ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/analyze${SCRIPT_EXT}) + +if (CMAKE_SYSTEM_NAME STREQUAL Linux) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/filter_linux.txt ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/filter.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + add_custom_copy_target (${OSA_TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/demo/filter_win.txt ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/filter.txt) +endif () + +add_custom_extract_target ( + ${OSA_TARGET_NAME} + ${CMAKE_CURRENT_SOURCE_DIR}/demo/ceilometer.zip + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Demo/ceilometer +) + +add_custom_copy_target ( + ${OSA_TARGET_NAME} + ${COLUMBUS_3RDPARTY_SOURCE_DIR}/python/pylint + ${OSA_PACKAGE_DIR}/${PACKAGE_LANG}/Tools/python + DIRECTORY +) + +copy_licenses() diff --git a/OpenStaticAnalyzer/python/Licenses/ANTLR-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/ANTLR-LICENSE.txt new file mode 100644 index 0000000..770ef58 --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/ANTLR-LICENSE.txt @@ -0,0 +1,26 @@ +[The "BSD license"] +Copyright (c) 2005-2009 Gokulakannan Somasundaram, ElectronDB + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/OpenStaticAnalyzer/python/Licenses/BOOST-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/BOOST-LICENSE.txt new file mode 100644 index 0000000..36b7cd9 --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/BOOST-LICENSE.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/OpenStaticAnalyzer/python/Licenses/CRYPTO-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/CRYPTO-LICENSE.txt new file mode 100644 index 0000000..c5d3f34 --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/CRYPTO-LICENSE.txt @@ -0,0 +1,51 @@ +Compilation Copyright (c) 1995-2013 by Wei Dai. All rights reserved. +This copyright applies only to this software distribution package +as a compilation, and does not imply a copyright on any particular +file in the package. + +All individual files in this compilation are placed in the public domain by +Wei Dai and other contributors. + +I would like to thank the following authors for placing their works into +the public domain: + +Joan Daemen - 3way.cpp +Leonard Janke - cast.cpp, seal.cpp +Steve Reid - cast.cpp +Phil Karn - des.cpp +Andrew M. Kuchling - md2.cpp, md4.cpp +Colin Plumb - md5.cpp +Seal Woods - rc6.cpp +Chris Morgan - rijndael.cpp +Paulo Baretto - rijndael.cpp, skipjack.cpp, square.cpp +Richard De Moliner - safer.cpp +Matthew Skala - twofish.cpp +Kevin Springle - camellia.cpp, shacal2.cpp, ttmac.cpp, whrlpool.cpp, ripemd.cpp +Ronny Van Keer - sha3.cpp + +The Crypto++ Library (as a compilation) is currently licensed under the Boost +Software License 1.0 (http://www.boost.org/users/license.html). + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/OpenStaticAnalyzer/python/Licenses/CURL-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/CURL-LICENSE.txt new file mode 100644 index 0000000..85d122e --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/CURL-LICENSE.txt @@ -0,0 +1,21 @@ +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1996 - 2013, Daniel Stenberg, . + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. diff --git a/OpenStaticAnalyzer/python/Licenses/PYTHON-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/PYTHON-LICENSE.txt new file mode 100644 index 0000000..b6bddd8 --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/PYTHON-LICENSE.txt @@ -0,0 +1,48 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017 Python Software Foundation; All Rights +Reserved" are retained in Python alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. diff --git a/OpenStaticAnalyzer/python/Licenses/XERCES-C-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/XERCES-C-LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/XERCES-C-LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/OpenStaticAnalyzer/python/Licenses/XERCES-C-NOTICE b/OpenStaticAnalyzer/python/Licenses/XERCES-C-NOTICE new file mode 100644 index 0000000..46994eb --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/XERCES-C-NOTICE @@ -0,0 +1,10 @@ + ========================================================================= + == NOTICE file corresponding to section 4(d) of the Apache License, == + == Version 2.0, in this case for the Apache Xerces distribution. == + ========================================================================= + + This product includes software developed by + The Apache Software Foundation (http://www.apache.org/). + + Portions of this software were originally based on the following: + - software copyright (c) 1999, IBM Corporation., http://www.ibm.com. diff --git a/OpenStaticAnalyzer/python/Licenses/ZLIB-LICENSE.txt b/OpenStaticAnalyzer/python/Licenses/ZLIB-LICENSE.txt new file mode 100644 index 0000000..42d1b48 --- /dev/null +++ b/OpenStaticAnalyzer/python/Licenses/ZLIB-LICENSE.txt @@ -0,0 +1,31 @@ +Copyright notice: + + (C) 1995-2012 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/OpenStaticAnalyzer/python/demo/analyze.bat b/OpenStaticAnalyzer/python/demo/analyze.bat new file mode 100644 index 0000000..b930f04 --- /dev/null +++ b/OpenStaticAnalyzer/python/demo/analyze.bat @@ -0,0 +1,3 @@ +@echo off + +call ..\OpenStaticAnalyzerPython.exe -projectBaseDir:ceilometer -projectName:ceilometer -resultsDir:Results -externalHardFilter:filter.txt -pylintOptions:--ignore=tests -pythonVersion:3 -pythonBinary:python diff --git a/OpenStaticAnalyzer/python/demo/analyze.sh b/OpenStaticAnalyzer/python/demo/analyze.sh new file mode 100755 index 0000000..83bbbc4 --- /dev/null +++ b/OpenStaticAnalyzer/python/demo/analyze.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +../OpenStaticAnalyzerPython -projectBaseDir:ceilometer -projectName:ceilometer -resultsDir:Results -externalHardFilter:filter.txt -pylintOptions:--ignore=tests -pythonVersion:3 -pythonBinary:python3 diff --git a/OpenStaticAnalyzer/python/demo/ceilometer.zip b/OpenStaticAnalyzer/python/demo/ceilometer.zip new file mode 100644 index 0000000000000000000000000000000000000000..45e2e4b42bd86afffbf0dc7f8ec34a40ca21101e GIT binary patch literal 1523052 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

aH3#?M@ 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

Pdk$LQJAxp^tP*+1St(iV6izRKN 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

B3x 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'd&EahjEMcx3E3Xa5 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

  • Ot^Xf-3RG5@6*P}XT5^X(q+tG8Y5wcPcT zX^zBaDWN^-)1v&^fO+6=5T4^cw3M8feIiJX3cqcM7L!vZXJ_rgy$_$Ymv_Uvon|TK z#~EXV_i2#9FrcUIUV@sT+DD%OY3Gg}%(f2~;x9qd1lNhtbFWFM!#sa5Xf*k*fWeuW z(L2kn#V+}UyVfuFr!Oy~vWZz)d=?P*EJS1Y1STL^gQM5X=?aP@t0^i_K5o@CfA1Xs zZia#j-C?5&uRA+@GRuPJSVi8ZH>d`cVQ#Bmn)MONneF_({x=;L-c;JhR zyq=E^FO_#!f*r;;2iOs7`!*GO-|)snA=yuFcqAI@xyjBy^7 zjoez4us_}&#dp-*7KZD&$Yu4+t9&K_iOJ3@ta%HczhiAwzQ3jo6MHtXi2e*_R&jqQ z`nFxmMD6Jx@Iogx&X+pR-FJN{ul_Mcf5qCTKGR-xOfJMb(ywWBG7qCHYhZ56opFu1^+R!K{F_$A`{q2>~*RU&9>EB z6GrRmoT1z;sne=bZ1l!>An77WfIyVhv}$=Jo$ubZ7R&v7ki-*khjooG%1x9v$oHnR zzxryt2TMTM_RkS;tLX6>xR81j78GnOB7MLLCd!W0n=qk1`DQt)FEBx0ioQbxtyQq~ zD+z#-PF~YCt#ZN2%fqBDIax_aC}9#Oe1FG6E*FcPiMbL#xuWcVSqYpK5rard%PAY% z+KRbcfwldmgYFzbE2LzFgDxRAJibPLY`0(Axi5IvhiJrpW$ZD5H5IO2bQ6cJx)uhm zi}|i4vV0Z}X030pnam8^mWk;nvZmIe?Fn-*ZDR*An>wGSQ!?<+ZNpm8mijz?sszeX zL$(WM<2}ijwLRU2X&-y65F|+Hnb#v$mKQ2sp5~YEfVI~b5|t$!8!wrC{h9*;*4#rS z`NysF6B5I~=^l_Ok)JWYU-1WaraPLtjXBmJXqSK7 z;NL+rHylqr!w;9Y%kQO zeriE6jr{Z7hXxTHGe@K#C3Z654Qg^^{3zMR4%b=GXh0^Hy4_opTJ?Wlbbcqs`8tfm zHBx~qwns(Ss2|;lTSMlse16YIlHLG@$U!`*+v_TJ4Q$3|RL!M2aVzB^F{+fz;V8qh z!0-Tze8_2>9NAzn1?CG43x7)4J?m>j3+gqNuKSn|4*onJkU*}WsS$P{*(dO`i9?I| zm-yi@y*3?bnH(ZSvKqv6zq5goSwjv+JWbftdYebXKSJpNW!nbRDG=u&D;bl@9;04L z0H7zLt_ZE0X_{AF`9SM`Lb3N7+54w(e|pZ{igYM}V-m;&5SkdCO~kvir(o(DcBX+! ziEkcJj)$DS#@N)g^28}?Tsr8JsU~ql0z3BwYc(tha5T#^a*@0ZOviT2FnhvrE9_>>QW^N_*eL@_C~o=eRYU->`UwUmihvNnbkDs=xu%fKjxdz5hmiZ`*;=$- zfHOeAjptI=-d#h!tMjA2PbgiE;WUraHt+PJxhKMwf*E8;u@5l=j+#7cIZNdh=B}0t zk5Xj=Z8m0(Y2?C@^+RcbSYQ*tSh-F?30w?GANvoW1MTi3jh_+mQjA|x;GIO8#&P!# z*I0k5Sosmdrno>k6;=Qe7<^V@R^e)T3yCyCF#$tUt>!nas;a4MQf(FtqSVqg?KHBg z;N{W!wt0F7xwuEjjGZvX`>n*-a7VswV+SY;2jFP{68-5~TR>BYNN!j*6Cu;&%U(q0 zT2mBw)|r3qCK)0M=^(436W##A06Ra0o|?p3pL_46jhueJx-JeHPV7~2NDLmB*YYj_ zn?*4(Ysw(6h%)e;4@<3wmL1A1wE~tTn?)`h>+s9numtIG#htlS!JV(USq2oZ29i>) zMmSeF6JMsvf4j2Jab6aLZ`BB0 z9|v3o727iwK|3kIV&aXd4nZ@gpP*hhVecPXI{ThtOHo7b$v#PO#8=m;e_NJz#h zD@kpCe}tQg7inphfrp_S9d`*gO-oyypC^d@RL8r!xs6j&s%FXlFcQ4+j}^l-h5rx( zkCe0&G9bDanee;V@$I)YvT$Q(RK~|6>MfyA7I1{wbOzwkqP9)gY?!X)!K{sX58BJU zI+%^wGw$kzE<5-wCwt8Snu>(XMMB)j`w-+K(VaV#^RLnWS*`mWB(!hdn6tazOhT2b z<%{)kg8RQB2>lKm85OWfqQ|mNefoed=Da~-LpIrwZW3IQ> z3g*O%oL1v?&exoVV&h>&U>+pV@r?9}><8tV`SX(~P@Bs}0y?@mfp0u7l9nbl^JeKy zx^`r2J~Inl10Q+U=vK&HsYg#b$1-3rxS-ZmR-5d`XU-Y0f-in{C+jWoryM_s;x;UUhKX zdy*Eg!`A~fWEGu7gn-O5sCcZ!Nyz>?LQ!2Oh(4=iUGH!QpMsdt4Vg%vq35Du36(;o6TL z)gaT6Lvy;Hx4VfY1=S@Zk~A&*YW!n`4lfrCvi(zSs8z?P234^~QxTX%?&@dm`t=q4 zKD2*&Zwq?iJ&yu?U@EbE=_m}}p@Sc0Mt1EMvT zpl5m$ykCPVwD;4!>0pcfj#mOTHI)+~GDN+@`4aoZxS8 zdJLgJ=bulXqn{oh>^uG7AATGid{1!m-d!&knXLsHmYHG>d|f)4kNOKDmi_h1eK;2erxr4#2Pk#&@zwKZrDyGwv?4>L6&8$RV9W_6_|dff zbXs$D6R|jiM@lC$0dw zCH%458yt%^$U1Gxo;&aX-{`9xo*eR3X@MQyJz5a?>h4CrB92)Qt`X@Zvl&!YTjfTd zy<*4G?;c&nb_@a4p1J}?Jnh(8-g9S4Zl?Kd8zE3VamiF33b{4-!KDQ2hPGN_GVQNF zy4`$_;6dTkQrOrS{b=c+BfZUF=Qm_5-KmGv4K^C|lGrg8{LhDji0jN;>aperel`wl zV)(R&g>-e~?5I#FJ%GkhC@U!TP2l^QOGap#n_;N8Ww9Q7h=anGSMQ~hkb ze@fW}B`8GSlDpO3j}v%1X%;hX-&)rxI-OglD08o#?lIw^iq@~cLfy%H?FU(y4`-E% zuhcw|DwDK54U0RhEWHh^R63^XJXj4e@TO@WcIg0%LgSD7yokGK)(#D{BoI_PW;?BDO+a3Ow&=C3k7-XM-k|IT%#`y#?*o zimYU0-k#MK26qa~?>yePE|IG-$5knlvl}pL9>9r;V1uE* zHtN-TTqfszWR?boWiVf~5`48JGGeQqf4%a`Kj7G?GDy2%ijZ!q92e#l? z|9Nhtk{m5X&Z^_^g9Y7HaCf#N!(rs7^#}u3pm3gEE>lK$^uRzXl$@xBMz7Fv2jl3v zO*e==wOaiFQ)jfSDg`o6Wnn#9xZ5YOl4Mp8-Pzpa0vfN}_`5pu=(0^$Nbp{MWU4Dx zz)WWaLE@#&R(XSCyKj0$;_Qh9(x%JF$fau81jbpm#X@c)J*;Y)aoQoSQ_Z8H+b?)4 z)>$yk$4{7~rvKwi<*8?Pj#XH5~N83fhl!9sE z=)=?VHVh{WG#OqtYJI+Z`e4wAPDfDZ?)oXCiuSv$^P6s84jLjV#Y>EyhD>S1?bmtK zODsp?>tld7+QO;7Sa`Aizt#fS&&oN@Qy#_pID1cQJ~Zl692+AiruXSoJsUe-pr_qP zvYE?V5KDDqnMFt~A9u*ZAa&Dmc<8FuxXre%tlt;dm#^)>{cw_(>ugr-k8U?PZFo7F z65YgTPwK3To9l4~%uI>=D9bmI+wgUhChKj31JR}ufb3$Ld+rYBbW~OUnWLb@XAR$I z?3F?9h=wN1LTi2Gu#Mf_(F;(*2*z`wfdvWo2|-&LWYG*yp&<(d3&?5`D>1HL@yNAt zn__brin?aND|)HBmXv&reW-T@Z}~fI&EN31aYlQ@vS!Z25&`t1-xDq#CsTj+rF*f- znwZ`T{hSoWf?atYI`2=U1Qlm8(l}0g+%&)34EFUfs;m#f--h(k(rT4r3I(U~4~Pu` zsx{SajUzTeGR*PwbRRWQU!8MjShYYaA?^}umVk0Y2#6Pp`_c;WnR|>UAafnU_AI&T zM`?QqR3j!zf!IH0TgN)7HTAW#=L(amQ$inwqURoo!lzI+9gWH_2G9IIkeO&G(2X=}_z$4gh55w7MgP(%=(#(o!{~Qz$)f8(HMW&=QSC zSB7ivNU^WCcHeE4g_?UxANRK#g_N8C^5ndZ9<;*{hTSQfZ8;JH1IN)>0~x|ZTyit% zY}sInOpLp8%al;hB+6R`G$lU)qO<{O0Llir76{SNC@jfRMh$v9%8^T5uTbKJ8pX}7 zZ;qz~*gIg=N^!=2_ex_|gj*Y zx~Nh-o7;psfCSeX7Ihm#b-ft*2*FN26l}u>B}HT%^{0 z_zOk6!#EO>01^TvkM@QL(Xz}FKxSJb*2SF7lgjUcHmC&$Lo{#pNL$C~?Gw1rTh<|P@4?gWO?rxJVp(Gm6tyc{u zw6Iu2!|I!CxJR;8NfFpn?DTRU$bbiuc~mrZ^ybd?(4EJ@>7%qUFDnw)^++`*_anvL z>@V3)^icB9cF0G%5E!#Zsb^gRUu2imN~HZXEglMbDF(l+4M9lFrBFK})|#pfTvqeZ zp0>9_k0W!#pw&Y8_b978-|`M3Ro{v#ME~9zZqQCaF;qf_v)^r!h2+k>V5ypKf*gJ& z?nM96hD9SP0i1{2Cz4172hgzd@}|PFpR+GbJ&a)mpxMKsxhuU7MHMfVM$_j6P_{A? z{zv_mcMZLk`piol;zv(IKp{DVz2OY}4!75OW-l*u`xFycZA7IJX~&)%@AGyC!YxCj z+^~4#qYIgo7Pd9_q64Ws>4QgZ7b=g`xcitu@R8jHl$s6Myh0--1x@6~Wik!ocXb~H z7p`_lmVt)lYWUM5v2`$jxT-8Uja5hXGm3tX9VkYBkmd4tKh~XY3Y*W4_%UO8WSNO8 zGC`V-8#*dr=BjGlAE?3@h=+TRmv+FUkYJ0*i&>E(YaPhvG)FLxK6Jc9l$pA><)zM% z;K~5_y-EJLT{nsF`;HaAWh4#Qaa{ap)GPy+VS>`e$kFrio2^T>lydMx2m6um?YKY& z*}ni%Mbq6>i@PFWVGnD#3=@B}c&StA*JM}*&FJ-A>&077bUOO&%^KR{CaP)6l_Jdh z>$DAoT^Twzeb$Lo_;8Kfib-`1UZ@kVYoTumr^m1cEijYk6Xv*tE(V8b+jiywRP>kf zm(97(rr1J#oablOhICwAhpE{PWQ1{NGE@OJ)!%XJ(+l~t9*);;LFpK3q`(ulX{KR> z6Pt2Si=lU+gikzo!W(wv8{+p1(FEuEyOoe+P52A)jEjpqZmm%4Shu$^#F$nbS~}-n z$HZ;M3JS-7Dvjce@KO!i`;<`$CZq*w0F`dTGbPdpoWVJ%hkhX&*F-cjJFO}H)ah2O zTVpGxb7r1c7$0OfknZ=#2MJ(l6sud_h15?p&>6W@=waGcN3XJ7Z)2Oe@nhDvwWNqYX)gHw}I{MK^3~p;ZS|)frBGd z0h<8#o(IBUnu4KM*YiUYgmxXMAPRGZj=#Mh^<*GI=?|*KTiFJCOJxP9NSxwZBKkP!-#_4_G0ks z`lWjLJBOU<$%b|*(A4sWlOSy60K2?Pn3q` zZKpfDQ1bzK?+6V_*2J$A`xLPSzbF(|MNmLQ3;>hC!uv?=dl@vfm&N{G@VYlhTyecA z^6FZGrO-7)>3>}hlvOa2$kb;@MB|Sd`kHbLe%L;a9trKd(YK6`30dY|Nq1x*HK*UH zfk)j?(ZhQ%jqF~d`oWBK()M3I5)~6_n=&wGhz?!}y(zfSm}ZyP(Mnv5>0o-arla7^ z@9J5kSqK!7JsVlzTsGUX=-{69=zdi@^h_7bn7UIbj!zz%Lq_Twg)}eX&JI9)J?;bX zg6ndIbGdH}8cofJy6s?YMikJ{}|@I+%yoRl?_WOpWubyGM-oP%c-6TVE~h0rlLNop8M5KckrHUH(eir+c;k^>Kz%jJc@9Cl1MB(Rigd_ z%-l9UQq~!}s-*g9WeXPZPU~#pf^E#Kq#|^;u)iEVLUGr~{NcG1mE7hvmAtyWgDb)K zY1K}NO1HG}pPBH&l9K`Kzt6U|F>UzMK0VJ+ysyk>u#vWAD00WY0wvII1PoVulJQID zqq5Uu>)vQCXpH@#q>0C8H9T#Hz(T1~4MpbXofTHAx-sGwSE%i_VI~P<>zh?)Ago6H z_Ck@8*_oCbO**t@VfRhGq-$kxN#A<~Q%}iCvTbo@BY&aSo3a(;P^oLIA??$=ZqL-K zp;qSu=oLBLFh&2R;6Zz9LvX_(@18{0>Lm#H6W)6);8K4Yyv@JV?>&KFFWezqQTdWY z0bwils2F>pFY7dz0#!tkRs6<`Mse%y#dWczr=RSFKsHIR%_;8 zm`rs~)QNTBd&CS&oTX8i;SgtTU~kOEcBDLxrCkYoeWe{B?e;U^+QBHZ)R%m?S%&*n zPnEG;h}(j=w)59lY%r3*L0gm&H6uVPT5;CrSeoJJw}|QccXJJ#HC}#5 zOjnoOTk?RXUZy}#yftgN$FvE8Ljtc@RM|0|qYr`MVPGjm!5F1m$;>UTv4@1!QySR} zx}%c;sLjQpnADI!(rr}2LC^p`cB6KxE97(FJFibf@Jm*#{Y-!KDBDAs)JsP#08=!m zpr+%XrIShdnpS_G9Wn*u+oeM3Gr`>K@1%PJDeK|t<*j-lYIHkeesitX<4}2#&Uv@J zyYb{$d)u=GX?_d-#?Ox3r$jHY4ww^U-20^qv~6F4oWLnAwGtt22f<+uigbQ>ngS{{ z<-eVi>8B7a|MTleeI_$FWz)Occ&^w$+`$EE2Fx#-lDd^NubGdS;1jnUlzr=+lZusV zLmgPbhz?)&2ipazT>Tg9*9V+RaPY9FB|JGWRSFSMBoi38pzHKbb~?mS zoZ(tJXx@s0YF+PCvf_x#G=W1qEI-(t7bGtH$?j-|grLWjGb_wRl^h4nG6V0I>h9M^ z3!*oMiWLBM3B3>X`6_*C^?l8b>mFb48^~P*s|~6=L&@jvu|C~9%CJSYkxIMGx=X(q z;rABC@E9K-$(nI(CM`ZIGG>q9R6v8&4Kn{>x)}SYO(|GbQTR`+vFU+*y0jmsbgM=w)2t6dldV;K)ZAKt_Wi5f$kVBJ zdl#iEGcfiqnqWbS!B_8kCMXw_yE4B?71a~%%LQ^^xe#1iATuz_;~Y@aH|2Vh<~O$a zmDDSo5*1CK6o6T5|5!qAK*iDbp!>4~mZ@ZzK7QQ)m){F{0a0l+p2rZ`!D zTW4uTUsqrMg|y46)_P()AMiKTDTMV}hiY5p=L~1fu{dx-PO*cML%g7{5|>W)UIM&R zrw6 z^c0#X>wED{*DTd)CNlZ^W-Is(OK+IcZXUq*Tp+ELEsZq8=S!xn1uP-axRo>nOyRk* zcGj;oYQAXP=cFzmNIiaHy{`wMa{=(nCfEUgv~X;n!*p-Qr+ca!T*B0!q=0R?t%GeF zzEBTPEhF{AwGBTt3P&b$eXC{TTFU^0{ipc%!?Fl{##398O%k+`gJkjJ;6N+eE+8sV zbE`app-+bq-9HDAu3y~BYQR>1~Q>40|d&}*bj1Her;-saC=tJ7^B z103kgEGxT2IjrXpcHfa-mmpo{uz)3C10W(Dxp-FE-M1oVu%NH0oVyA8CiU`+*@GLc zqm;jSrGx%Hx2-I>ZhHw7{OKuB0n6@0u&T|`V`jD3`9e;6sI}8d=YrHqyzwv{yGu`x zp05Zdu<{cNH0t`BVhK@J;`F(^eVzpGFAMROF|sv1|Lw zLJp$ig8M8a`1JMhYlUO=J0a*}m_@_HHwd`_6Q#cRZ^KjL8Q6Erln2qj%+t|YMO4jKU6 zLVgE5r5{!=o^Zq6^wkIx8gvNnkOWsBH9Q{i{* z(N*ikLD7Bh1)NjTRc4hy7V#k=pa~F9z^hwvXQ<@(WVW=!SnPhJFB-c_Z@WyG(l2XA zCu#Ih;c46iz_>JxYDyj9cUHJ0+Vv#uKD2GoR&Vr#DND>%1}ZEnNH0b4AeS-(e$?bfl4Zq&Ow8r>Gp zB|ow?+NJlUF;#Q4f*+DazY+7A$j^?pg9CCG(2#1!O`{s= zy9)n|c8#8Q$m!ToqQ!fPDNpuQ}or1p5Wz4f@dTi!roS<{rcwkU4F<)}@CWp|*k@&()_ae(> zIQ@$E&_tnRSm>?vR1>@RM*zWf9^QyyN0a_^w0i!{q_yw4$&^|X7~`s?y% zYDWv^{EyFxuhdn+_FIPXCxhvWr@zgbEb_-u&RSB>dAY4pgVJ-*#cxaBTW%P-yMa9R zmYbAHigufv*r*Ys={BL>&m2CR3LM|*qU})9@HP3Q&vwtA9$(9+hsWsW^?Iq7M~!^? ze3#AE_q5%e`h9(qGvF#RnDie7C@#7VSG8jE47cgJc=-FXcU6O9k0F3+S!{&<1WkG=@F>nU|yApxUKFMTGK{bHg^ zO0Udzu8EW)sgP$#{{cLp98Q>nDR&H2biIr3`?}oCCj8jf#SCU;XCq>lVL?pHF0x+9 zNjO(uKZ^0^`P2$geLN+M#p?_J^*tH#U>*i9^UyL4hr`^@A@56;f)*ClBeH|-A+ z4!+z6{cZ<+d|_~RA1L+6E695t*k$k2p7=Mc)7WKDVfS(^d#=NmwW$ugv_T*_Cn^q0 z#sfD39jDbn>)HMZg(n=_?rQh2;F+FA|MD2hW`rENtYj&I+T;^qr$iR;w&|Pj`spZ0?2LW` z&K@GP;SWpa#Z9(RY-R%r16oj*Jq4R-b!t;JrNXs1ONu57U#DEra;#-JtsxsT&-al1FU=>pqSWR z4{e9=m@s$V(XvpopB`usv@AgRxacD;D{j{dNQ8!b%274$8pGpt4k3mCc-4%K%^_;zo&t4o!hsLjcqTQ=(49ioCoc-DsYE(m18n^ z!n~((ZN#y$K$xG%y4yH@MTB`X)WJMPhTR4--+xIExU z!o~$_6&gvb(Fuq5P`}p_5bS=-UeHnA!wHuL=)%h4@Hc?B!Cs9VaeW~H%|PF4SUb0 z3N$~brj?cFxPX3Cp6-3GHgj}&ymAhiODOZ?)8O&PK5#Z=m1B`4unH$Zngr&5G zqt5g*6cm#aMnKC+IKQX7dBCY5_kCUkha!XPF9K+oyb3o(92QNTrJ$8(aglLZfMVjU zUbjhe!dB!U4OE~}y6=j?q3iX8h@LV|K%3&9^P}C|7L51o3b&6(bM4Gw>StOoWtbJB z>9++@(}*}Jk$OO;yO64Rfc)Ve#@;6P@8K0_qCoK*S3ChK+7_1rT9sdSP`AEpfjYDh zmElGg!uu_32fEE0^q}DYx_nF)VVt#35Wc~T$2!rjHj4zXw)c zrtdzXqvO#+-1D}Oe?V_NCiswVGP1J;K1F1kqJ$6u&kC~!Tnpf#Iv`*I3NYhuoy%jf zZ!}Abmb@(Gi>^^f?Q3f_M#ZGRi`wn|SmOxg6)$&$rtyUIl|6v|V(#RVi;`>}!1f3# zJ@C6Gzx}Y_GZ`8n)zO{}?%VIKZDR1f) zd-p$GFt>GUD7 zqI{q#U$BYHBp^-n|>a+|QKG z?=}>h(qSO#C_8hQ&n(Ml(WmC+CA=_9vS4yn4-JKm&QUb+8y3l)v)01K$>Ha@HQOUq zf(6qP;`p5&WxAl2vv^D=ChWV~cYnVZX$UFiiqcWm(tSO2dM-HQ;qS4A4@XVNh`KI# zAAHx#te@jUZfqZYBjSoZPfk9&`eBsBwJ1T8r|4HwgIl2^#psilw6NWS6=l~gg+e=# z=(>{g<-UU{>{{9~jY9yFAfa(W8M}|#WD4YHIv^tBWTRfWJDPL%xDkOGZ4afpD|_h2 z_Y{(Vd0Y*X2Xt$dlh4S0!Ox+QLAVYwxet4q+d2g&g5|2#=pn5iJ zJ7&bTJ!K2!BQJUzZa_%&e4)pT->LSt855Xg<)b;mJD%ylurDdt^;Co;B|q-3nD&C; zRk~X*d{XzKJEJ&;&R)6NN$+spn>1q=&(+?b;bRb8%E?5Fyx^Mpvtbf3VeuBn5mP`J z?u%P1Ue%VSAIfSFb2Z}~>fJZgV<;3k3H>b=L)~Z@Nv3FhdEZ)(H`jEDhWiw`5A-5x zM@S{y-;!dFhvU47=XeaWcVW~_gwCnnp=(@BDt6XB|zh_?@l|s zLrQNan>LSgc~LR_*--VSFl5BkneAObvQ~ObIp1|gxM)dDRvwoHIBiJ1D#1q!b0Wyg3y=PO8WM(ma|uiDg&3Lfki z!~+^3VWCE*yk1iuGvh*D(cgN>>LGLMP!)7Z|10eD`ES4P{(Ueoc|Q-6!EP{>a_e1S zSc5#0fiknCex=LbgPGxN)7wip1aFj!t8;$BpnH`vkoWkW4uL!6u(^t&+UOHGz&IZAbd7r!rE zh2CNqY%LPR5PrCtri_YbyNG?-fCcxTO?(3uQzs-VTxm3fX8X;>=LWt#dT>2b6c%FF+yD9n>1KXupa^J58&ncj9x9|C$;%{HV?zl!X zFi7D3cMS3Wi$C5~qq+X=1^B<`n`LB?pkLwnnU=|bNt5Mi{JSfIRJXsdVl`Z@pVH;S zZohPQ)zujNfIT`a@)^9gQ+mF=e_oqu^B(w)T(s%ur+MCie%NV_601aB`mMSjgp8vr zcwH2~_g11d*Z*AAw@Zbl1x*`bm$EW@n9~ zzI<^(2}K#yWqph;=6|&I;BF`l?cUgGK1rQVucuz#i=`Qb3p8uzS4cJ0l&AeX(l2_6H5Q&MV|z6wBGVL_(C; zdeV|VLo;fcY=1RLmA=VgD3W22;U#<8jg60wP6@Q$q=ilnXTZ_#T-lxgtw@%`YY_sX1*&9$~-YI~PC($C?$W z9>Gjm&Hwn{_Yd}Kz%2W{25j3&)S04>UZ#JPj4!`zKiXhr(i=xWnLMI028==ch&cv# z>Y9n1D!SF=I;CUv5F^9f?ye3wI2?bJ(=_qe2=C9g7;kKV&~gz;RtZYU!&RQK+q*hu zqHDPh=-_VzfzpOwZ`Tt4jHXtN4{3jbW;%?O*bKhXn7Uw7&P4L}bB)*OXls8U_z-OX z8FFqHSrn^yOEyNr0ffOUIdutk75t%z+;EOj_+r@J3N(Z#TYwVsdL?=W8T*o>(tZZ# z-*Z~WG@Tb)4`Wf09b}9J(#`bjD{u>nhPtJUyvYbHzR3tv5MGA2jGjs0z|0l&c95m+ zGZiP;s6?ANN@ly27B@|#9AaMN0~dZ75w7fvRU-cT>`S9Xt%aQ&CI@eR#aSJq8YM=6 z%@U=A^f3*CAwrP5j6TNV%W)u7HB7NkuL+t^L5LPoUQtOvt7g!3yKih8#LTRE$I3$4p8PB*oO~bAFjJp zYbU2Fou2R3c#?|QIBu?>*V+b&gzOTJGNQ(I(!BMQhEJ%@B08#$a6Sw@&p>0EyPg$bCV3U zvlI$TQpEa~0J~}=Jm_f;8`|q}-$cNhNroOBF$Q4sv9dNNv5)WX#{9k5X}ivXy@1Wj z@fls6GDFa+Gw*@%i@@5%24ccq-2nf`uM^w|A=vy0+F z%qnwkE8!z}s9-2H0akYUPBWY$>ZsGtTlHTsKLFRy`ja(s5dxG^sviHuUl*WKmx;Kx z8MN}+xi}}Vo`3h3_k_Om?+=cufdyY@`pON*ehw2%Qi}1}3d$=Mc=2!B|3IOfxTQ{- z`NY|6dI>0ycKcGwu%gDasqf>{i`9*$nQ8COm$-0IPPq~k&M+doZV0IEKNB9RxJCRwCUA>s4- ztBs%VQmW3z^Lnx0V}QqN&c2f|PUSw@fhczQGx^(#!s8Bqhh`0ZDaXIh2>w^z+x_$0 zViV&(SFkDC0x?av$}SMGz-jC6T4f?cEP0K;{xc_$1_$C4$NppGE#`8HJSis!fzR86)=x;OPo&d4yv9DYux{%4Tp!|9{Wpi)geb;lOD zV?CCpOONW$kM$G%yiX6HgdMZJgM6jGk~vVEXh+ML(igZUh$31=nWgmC#eP1UyS zFOPjip2i*CA#HS$dV^1u8XO!-JZx~dA! zNW8o1b(4-R;k8{IgQHl|Ig0CWLjD3rF|>y@PJzYR+WG-{u3@0XNl{VJl$Qp=UBke2 zp-7rK+lgkeGr_;BtBabNy5`miBQZ(v@MXk8w#3;=&1^8cF0_Wh;>Yr`v|^`Sp=VT&YO9FJNL~;%HH@*;D0a_pq`A{mJ2` zvcvfx$*0*(f|*c=C=X_$#$$VStk!u+QtKEAgOL(81ohhFMe1qd91Hb)=!^w%MFIBhV?9%5?wWK#CJCX<${91x&@-Se$0VFgOD%=e-Om@G>|$Q*MB#o zyqr(pYb7%+63(bGue_vpVG*S-5N^`1b%sL zPkg-A39F$ug|0!)5D>eqpQ3u{vSy|`Gy7psE;$3b&8BVtiGr4vCkU2ARxvTL!QtV^ z8NZdxm|4KW1-M^_UwwdAZhXJR>FHNus*MR<0}9U;ry1Arl6zc+GeC4;dFtn}S$%zd z4F<&6^lLB_(!*>^f}A6p$&%RZ;nS!11?FT`P6`Pmn;4z1Lk9=foYj5sM3~$E#P4Yc z4-fxgUQQ9sDC)u8sQ;EozJ|D`#_8R{`!_V^$gf|&zPBmg@^}6fusrqV7*OZInVAQM zAFaSGp0`JqP*hoV+`+Z%<=k9`2l1E6Q9$Uvda2E>km`K43gE$`qu}5M8=bHCMU=! ztXU;5%ujTmeTN-Tzjg#hIrO~y4Bq?yz2Dyt?}z{W;API7vt#XNJ?mNP>^X;Dy&hWO-2}gWZ~1Y!P3q|) zr!V75smN$~E|$Bq2&56MjlP8as8k(I5~mLG=0P>(W+b&(!1uk4sSPI*cFq}YP6OJM zZeI12)gNU(l-bxc!9?W3#SRSLEo|FD)gNy}p6^qrY`h#oM#?X*q429~y+#IP_ zHF7~;X)|~1qMN85z+3v8t1kuIca}a5w+a^}PHJxGlUf>=zFjk$z9V1WZU5+y-hU=!5Ct;l{?sT4s~!{^(G{=iob=$j|!l@O1b0 z2lItCTG)88`}BDdcKm+6L>!{~qmahiALhGbDhaWUH@ ztc&$#QPcNP`=r7Qrw3`#6ktd3!C?KSBTuK2q^aTH%dHS$wan zoA5VV$ZDclbTKk!QdhV|@K!qPPGC-|_gJ8hOs6vB1C`cK55)$X6JMo_bI1%2H)pPK z2GubxRJ1Lvt~#zYx-n=GWEViZHu9~O?z95Nn&N&?SBu?E_S{Iq47+UAT}GXtPD@6< ziC~}m_)s$Hq|)lX=E`rhr(5QYKfYt<==gYV4Yf!ly1kBX_bz-p{#wDyM@f1P*wYgo z;X!pRH^ zJA|`1M+@yIvAM%`I=_TCL0;@%UpvJ38f-4XQpaM8MlJd3H$!dq?FlDc{!BN%T`tx7 zm19oc+`-f~+vbbb`$?sJEpp5E=^%@vE*seFZDh~?S3F4 zM=5o&hr@L=O{}Es_(~N9ZDF)YCLhS7-T>3#{!V2M zNqsvhwt^Sf_n!A&M~N#s*1!yFgjjm-Nk~l7c_i8BIQH&VHHaV1;wO#8%R<7!XrLgt zMmU23)qR%Fnwpi54 z>73*6IL;&NDgraH;U2Hy4%Xi^;+Z1!sugW*a$Wjav+P|{Q`0RJOZ-YK8mIj`^Ufr} z@>+QD*SNvUd@C^=0gA;ZdPh}c{SBS3aj8v1!SB`8&K2L&aHiJu-A$LRp(=B;=84qm zg4OnuZ0@QB5Z(<-Mui zEw>)QW!z1RIF;SqT_p{hxwVq-a4&m9^YBq%<$<9gAxci)vKFW*JyoxntGW-}ra%}* zZ?@5}8k( zGaC0`Slbe2Dt1}{+j|vOsM{nY#Nx-cWo2cb$DgRFsacMGe?Ujq+S=N6;PdIzC;g+n zHM=P<%)DRI-Me>7JTU8~*4AN`e2MHf78b!1H7<)*2FL_npv9FOPqvLVChNHP_-+># z7A}83Jv}wGv`i`~!9CNn@>Nhp%hK|)3|5x(Q(y<;IMDY-gXCtQcHJ!vvnUtJ9;Dk`F&q6!Mw44OS!uPI)_ zd$6*o`pkqozH+1fXsa~?fe;5Vpnp-rRgQ%A<4%q9TEe$fL)vz(LhTy9gv7*Pg0=Sg z-zzH_xw(&^aRS5kPEEmv7W)SW$&!UQ$s@^tY7cY5Z^of z+VROwznLwdVKOo@=;`S4^77KFtA%u6C%Xc+(@#K)!R$rv9~IdU*qBKo?ckUrkw+32=eQ`dxBMnygX(OEgE1BHqDB;aym*Xs+Zwr z!$sO|DEU_UQD+;QjgLn))z!1*!#c8U;=N;I3433Qii^Vm2KQSyyh#8M0)RnX_h%HMf-Rm(WVs~($Ll_(3Z0PRtwg8 zhbt>A7vO>@2D3UERU{6)157h8U=vRiuHkBF$$A(5-2Xb%P&HDYY!XQ21!N)`%p(|# z9Rh$ft=D5pU{*>&0|D*2>FtccFzz z8T8YoIU^A6`&tU_51G~|hKjTkRd0~1Hr>7|7Zrp8jY3PQqv@nkURb{URU9#E~|Htf#KmpLqm^WDK^aqym-E&-%T$# zIX(}9zS+0&!NKTZV+eOddso{;1-lp+x~xtjM6zGqtmWtBonOl-DdF;xdl!IvP~NMT zI+a>^{`NP;ZWA>5J#}m*OtaL~)a(`O3=Iu^t)fCka`4VLcM>V%X9XO&*Vc`B1+%jw z0sLKAMMd89euSj~u!h;7O|$F#rbTg`DtCd`$?h-{t8B`1FRzo2M_2GSfGHhCWL2&) zp%YNt4EzlsrH<<%6sC+d3?Y>fsCU_zynNr@!ouQ?kmJ{-5uDj>MGZStDHG2FCR7I$ zQ+s;25`i?%$jW-aG1o~X7d8Femaa}KUXHQ&rNFGO`FK;%RQt2VTz17KRCaduWtA=x z^x$aAvpK*7OKWTL_$vV~j_#9-VFLQzyR6$i=;p{}002$Baf4i#&<~Xh04~&;)tUv` z2RZ!C-d<}An`Sz&lZJ*ydR3KRUVeVCY6z|n`Z-dq3Nn~Prb;33W0DA3d&U`4>v`*v z8~m@;cQskRDttDNeO+K)J#ZLRKK{@MPSKQX9F&=vSs?IVGk@Iu=Fe;#TI?#jR9rM4 zR8>^6RBEyqk--5nzVpDwm%Rd+u4c)~e^kqZ+m-A_an>mN*`@)QKrRK~Hd1P$I7Vjx zKo6X%-z$dNm0Zlf^sds(Tu@cVOTUhmLwP1JQTjw=D_F?efYO4%RZANi;lS-L#o_4s z`b8`S8Zi?H5K->3$k96c=!1gN?dtx&fD5% zzBD;Qe~lmXp8;a1q2e;2*GL2WGe4nXkG*2-0MUDe^#qlusHh}MEHyQCzv@*P(|E{L zQ8oxsC}yt=6)NSmvJL9)Th@hM9ah|n)~rhuSu}k6rb?5QvuomX4L+5E@sur0JgN=8 z*d(JjK05l=Q5;oaB^%CiIfyBLq^l0W`KLH9FDM|+R)J0|PW_wmgU7hZbCEX9m->ZN zk$v+c9h3CzL9lCl`FAhC9;6mZj5=aQ>O5R5Q59@ZYzO0n)QV%W1ozWPAUL)Tu`xo~ z_U_b7ZAm-9^}w(C4XVMv27qg6y!U4uHG!Bh>j(o&p2@~zjX2qZLcfl1xW2oGhe1aS z+p<9Pm5kHZU?m0it{0ur91_t{LWk{Vs$Jh{!DlznOHW)H+iH0_%gYC4&-M9W7;| z3-bRNwadp&CImb~T2WCEXr|_wAO73tr@(oaS4>JrO@St=^T1>`T6%eTi5xCv^bQQ% zf?|*E@hmx1ucUdtiqe{zsLxEoxQ9RnJiN)S*kVXJCmG_ODC3hz-4N3UoVaXp<0?lj z=eyCda*O_#i@61|2^>k=73eieY|XQLqi4vLP92O6Ci$DF~F6mIO=x#GFJ+8>V%kC zSdtmQsXp5hmDl9jfBt-NyaGEZHhCZ-me|X$*B|855e48^G@!kLX@lFlM@p>*OXozS2-n&kdjwIKx9*CivNf za_&`qhRVPTP6uS285WKVzt1(VePIQ$(@mwxCMj&+852+8Wnwvm zNxslwlXR*VuLtdDn{K+nj&D?R<6P<4$5}cpg6w%ug3b>RG57?B+fv3=Y?E+a#bsIS z3Qb1SNu9~A|gxAD84GDZcq1e3>}RDyq{8KdIW3{(mvKmENX z%bv39DPU0m2#SD5%msQ1mtx{qq@<)~=h~xQYie3>g45!7K6W&?sZfB)#IFz#5Tw`D ziAqUJL&dvz7lZ~lLvJ0rkD&eh`Eyp?dJ#IhqN)Wd{HCPA{(jO?OFnQeJzaWDjV6T3 zhNSyi1nig6xE-`zTreMRbJEk(6A(aI?2nJ$c$`0iE<%vy9R8|B;6wQtX^j3ELBG64 z%n`J|ONj<~c*A&xJtdy;i+A5V0ha94S}~R2{7!kX&GQX{RFsr~U0q#Jk{&xz>Hc)w zZsNoKC`a2hsJP}3X-kRM)d-LcRbr>7^{Q7}2d~Z+bv9vaaJ8to#E%`XzWgy+YZ(9L zd9YQvnBtLMQQ_QL@s?HnbZ0E65{Rd^-2*=&Kp2F z1V=F`W_O6`A~?lVG~I=K&pgKks))sr0%v@c{r>%Xa3mafjpOL(hxvd2@R#dyR_wKV zP{SW=DH$UU{ISM2rf<4f4(18i4dzjzCVMla4W{b7%)TAZNRqfrRdW80At#QpU?!Jn zt|3RddU{Iwi9;@F{1Hqs`)f^&FqBxM{^!d7(_=@=gAuzf< zn7H1RE57qa!Sw6(c3XOauS*5ejZ0pUgDFNb&QExOE;l=5l-NiDn zwdK@yhQ3uZPHP0l_rZWG@A>P+I{=kIih|p4xWNE)LGl6A1(bbLPM82m0)U#?0k<5z zc~@4Nr-~jZDz&n5uLEu48!g5l*g*epfPpbV&+$PTB|M=|aeG-QDTvAh8P4Ne#zje8TIHR6{qs#|N2Kchv`h%Mm>B zogdL7wQdfR)j)PYICRe8wa2-g`2=(434|V@vc06{J41-ak{Hs z>uM+Ad4m%>w;$J-mYJ582IU|D0v1NL_OP4R$ooMy@M$orkmvE^TO<+W#!NHzxjsjh z_Hg0o#pG3DfL2`ytrB3)t0N`!9D1jd+a|Lcgp)i1x1y=PrLYaie?T1`9@fsEoSc+c zp(@lXEZ-Jr!r8%SGt$%PfJ#<#5AR=&D;>2IYM;V* zOoavnC=MQa$9T$YpqswH<1*J?zGDf7q;gNstAXL+Ht2D`B7MSK=hd2*_tbrlYrwZDppyz!s=K$+Pw_l@miTQ%z1W?{m0OWvD zGT%D_Nz1BP0VSGHrA*s@Clo}BXeBPZBuOKq`Hwya zZN3I1c2W&;%$IFEK*|9ULDKaN0Dz*RqQ~kWL-FtbQ(joe_BYdVYqXb;aB^~j5^G@o z*^)LImg;W(_jV;Toqq3aw)S}~hM;PNj*8;%NjZn- zBkQl&jK_IVrlA&4hJgLt3kZQzb`v1Zzm;rn^WJcaI@je?MLG@o$|7rNDR^7T2rQbO zoBPPi^5#!xN5@-UayJJS_O!d!{F11*7}*{LmH&Ep%`?gh3{C!0RMZU-y1pkuiO6g# z;UK@Zzy2iPx&JMO0=NM2B|v6DK*&Hf4mvsj+EI=!$e)4;I=z^t5~CXJjf}Fy1MXBk z-6+zo2`VaeUK<1KLi%iYTn9N{7V%=Q3d-|FdwP1_da#hM!}Ic(PiokmwW?5xj7uyP z-uIzf4V(~DeUW2hV=HmpoONA@H=)Db%9~nezsuPz31r9V4f{EQIzKD6F2>v&DXbyL zLOS+wlaf7hkgc`nOR%dVJu7H>Th1?o%+0Im`!mLEe88s90VDMPIYMBMK;TWR;BiGe zHY1KuJe$(|>_Pd(4{11UM!wyz--<4#s1^LGj0((s@oZdQG>lZH#TF_PwUOmZv0rn} z(EzQt-MU(JHQd3})bv>;5fmP;UOR^;rwG;#Du}=pL&MZKv8%C%EZzJqj6;ceb6iy? zpRcY#aN0t>mg57y(cs2B*x8bzw0;6rkayIh(8}c?esB9iQS>Qj$@8E?Hw+RL63xZk zA%u{Lc?7m4aszj>nU_nCM-0Nr>JR{BP$>eit660dibD{txNR79Fi)eIJK5>ioojp4 z?i_VPP>nB9H0O#nq)6yN+;?z z*(7=SoyC07gZ%fVA%dY&&86@1RCBP6`MAQC`3*I-O~DcfB`HT#x--5>VO$WS&8e{{yLoTrw#jC zt9;DICuLw@0Amk0Z0bpMQ_g;88gm_>rIz?hgA zQ%g%ZrVY&+XRF7&ykyCaKorHH0L^py0-rHx3%l!fj>kdMy1|1Tns0eIuZE^(PI-4` zQ01$>Uvz3WHDXIoPESu=Pj-hhfM;++kxj12NClb!%ry8M9uMo~I2Bv&Si{m$&=)I} zHwJ^rA-$>a;119l3j{OVc%2`9{ra`vL|%V`n%`P3c5rBjih}*EjN}#wcLqQ|EgO1+ z&>s#30y?_&nvHrhdGkwncv=Z%EqFd}2m1PM(jJYp={q_;E~?%7MFHgAuU{|me>{Nd zu~6v+Dy0C4AR#R+J$ZteaGCmO1aTt}=RR*^+70_?I&s&7xf1xvzTuA71+)g;duetp zUdqm9B!i|x3~8d}J5C$t5z^Ad*W2_&08EXm|pt$fc#PjgbEB z;!2~%>pb5G2|b78UqI))o0yn@q|;;d(?96}x~W|3kW6J`25l2Koozb<^2o+_!yZze z9-dAK5FT(J2E!9PLh)2HFob<>pP)R zFDE}3@$?-sf{qmnI-ugf@q+ZF!*KD_%BQ|=vje$G1YqETkmBfn%*}msZEcN9Kp>92 z=I_q7zP9;_E+}h}jlO(>r$_aRD5khNz3EG%h}!RA;PSS)Z>p~08BtMC1b7|owSe@l z-zc?Mmm)Qf?Id{(BxFH|qtp#5k+>XHHMW3!ul5Ug4R;_vhIYV6fB+N{7M9)7b(>XM zVt_Ra+G#~_0}}iY;VBKAU)pEcfoLGpp7yHYXz4;!ceM!Jtc%c|ghX?` z;>p9q6xXKq+6!9sj%HdFhBDV^g^fA&Mf6Tb+Qe={WppkYPHYWAloaNO#%;I7zW_{9 z%b@j1R$@Mgtb{HqzOR~vo5Tq|c{A10I_!tAOKWa@{af*{_ArjO-nBWyfuM1ZMUz=l zBytljj4iYklm<*HAwk8NN_DqbuO9xi0kZNj)MO8fq8R0mHpN?YHtoO2Ue}l@d78FI zs(&{(Ivz?94{sBLsnt3imc2(8s2X$I{fMnMy!R4>Bgj-BV}LdXBE)!TIH#iD-bz(} zqz5uUJ#P~B9}kuWnNow$qM{Er5T45}2I%4S@UcYeppIDfP{qgmZQI16j*Vd$toitC zCYOmJcl=0+fi&>MoO9cl6minOuoR7M%vNjd+7%(`~4T^o+K+A+W-nq$=(xjB_Ud>{fDANj=@?oK6MCnsn<)g5ov zQ`hfgEqTng@7qkBtcUEFpC;GcB_ZieTniyD9lhLv&35u&eOu0ax=g+v2v#uJmX*V} z6nxEEy;iMh!**B+%^JHm;q|&oUvdEcxGivUa=+KB(CDtqTDH914|0S$cM@!6XIbFz zC;fx)wND)0Tw?AWNXhWEpYT)GqLbC+lJt7-rb>wr|GL!uAL1bv;vS11*Sx=HJy6)$ zY2GIGGI&mIjOc}zz(Sr9UW~J9KxV?x;d>bk@Sd)lgWDn_TAiNLoPdr^rEP9bk>8ThfVYW zBrI#O`Tf@gE%>d1TE)HYP3$$4c4tRDWHfLD*m@9dg+9ULberw(ZwmDGliCntnSleA z6j*ybK3&F-3R{6j_cb?PmR9`Fs>9~qAKL-TufdRuk;Tj5To;Rh9ibyty4(3ah0})f z>$*Ld6!Q{N1zEV^{IAPVqKs%vS~#mre(cn$$Aih!LEA$(glf08XyFn=?uB+cWR462 z3s4k`UC9w=1ssT)5Q6TEr%RvwO7_18lAcUBqpVKxF9J4spjdg$LHUgn6$#g$)zW1| zl+T~7ELrs0%#6VCZn9exetjIWwLG5bvQ($Ucs9drUUV-5U-iWM=6d3lW7TQiG0(08s)KS=f3ylQqsqbL*u zD_^RJ;?jt3&y238t(#w{HP8fqH*PgJbhkthBBC+-hMreh5*)g zec0`S&99vnqud7lJJpi?WaDpBg#G#9=7cOSE0d7OJm)agUILXYE8*{6_d=lpkKGB# zcP)3|zqG|S*|re7@bR07{t~95x@{g3E*+;M{YBlZaHLiLAL6M4YaQ3P{bgeBxV<@T zFrpH}!MwLH1wWAEH3PPHoo{ENr(^usjELAizVc%#AfTQpC4gL5ILC>#JdrQUU?35B zyRboYvOj9?v4Q|cK)ApAot(BkZaFS{&(GmAt$*p)Q5k zS!Bzs(Pj{ zL=P#;@0D%le>ebB-i5b^tu4`qXGRZK*&op(_H8TX>W@-f=?aT<>dcgS(Vn~QIYDB3 zh5b1Oz@;!K1G$r6Ul(uQB(XM&jbpjv9sh7S^_-O{Pp?VcRK!6df-;z#BdiO97=Ljd zivDpHA3Hb+ABcMEt{&%KPP6K3+izw_Gm~ikQ(^#lA1-P}w0D|UYK@Q{S^{4+`y#ya zizTY)Xo00Tv%Bh!O|qEw<8Rupb!h?D2N|sllP5p489m%xM!>|{DIf#a0)&rE2}CFp zN=xA4g8ORD;bA&(2XnrGXc7Ocfh~+-WqTNr#DlF0sg*~YHA&pirH%g^dWzE zvC(q?DzcLRNd*-r_scCIks|n_@>=YdMZ|Wp>-PLC>0sT#FBYYQ7lq1_wlfu~1H-Y} z2bx7n92ohdl2S@jcEI)C=rG}QII;C7G1;#uUxK+zR z8E~Tj%IjllV12%ccpkeRhfC8uqFPcb))k*AnOAM7`_5EOUrgbe1ZQQv|F z@bTg&yoFf)qgIbw#XsdH{axGhRLscMtI7)Fh^p>yfH@{PPB7f#XtVL$>)M&}N7VCp zANtbXF1*Dtw6c#(qUp&G-Z4~w#Nxn!{OP_vW^oNsWG%&#m7@=uB4s>x2iU~*G|hju z7j{6%^=I5+qZrPus!$UB)AQBax0KL!YYx~!M~TCt0zOoDPr9e|$&K-{jK%NYj6@vb z?%T*^1YxSzUb+Vja63Z@iGup&?8tK~fU6xeW-Q(edZokRh8F%H@Uu~AK{y@jN_UPl zs9E4ieN=tie3ka&2rZjwRfGi?&t?tmfPAyc7yF2+-WlsgxsAeZU@73(wv9F--9!E5 z?XBi0_U|`=5JAt!>V`qqqM+b}YUWy7z`?qq<&eSFZCYT+iNwJOXZgh(q$NVsgmgpd z9I$P~ZK-XL-J#%jd9VyfU@Ay1Bn?$W@!bP#5FFMGecft}UDf}0FTfE(gImCRbH)-h zvtjK$t;ks5vX-10co?&g9xggK9Q&z%c=8|~Qt;_VQ$RP!Q3S`U3JA^wVi0j(>wqm( z+E;82rey=inO6_24GkG+T&Leddys2)`eg0?Oh5HKkBfiZMsX&e!tVw{ZdN%HtQ(S0 zT|IJmg1sTWyeg-u3$)6u;rglDvmhh_e`yTfa)Uw({nTOUh$~hN7ZQhISXgThOL22< z>=DlUei}ljQ;2zs#1v?~9jX8e#h(0i9lm$$R=aP@H|e=Mxc@U+tu<05e-;oWh!VeC zJzNC}?dyREas`SjfTH+1cA1zq5Mnvdoc;<1`~0{T&Oa$6dWV;~m8I2zR`csoqfN`k zX$vBpnCw#m<_D_ei~JB8lwr3B^5SYJXzqAxF>^-*H-)f1mZY2AfWPly%>=O zJslLoAqzn<7Z>Fd`(c8VsJRk9Xz37U6Eum~o%ayQg7x~0*&jE6e9PETF6!5Erg@EX ze>P-Q=orudK#W3d*sYmt$RPsa*3i|;qNn@lyw6ZAp!8#hZQ#C}qT-Hm8&=eFwpq}o zcq5QWe|ppeodF+DBG;-H6}eL^vT3OEO5?Xc_IDAwbbeHP5l{5I(uDQ;HZp~CKNO9pm}I30*A^sht3h4K@DU3=YHjdXpt{pP@(IL0GkHxM0X_pgd_ zy)jJwp*uwhsVET5n!zHrC-!UtGQYF$+r2m;9*s`0k&=?qpQ`uT?33j<2!~$M=@4T} z$xhPd;ojH2Z~RL$M-iulAo1eb)y6ftSr>D;e~_$8l-kcVM|^{F5FwtRQKE zIL=Xgzp#`B6-e%$)FYS<+DhbS4bUupO99nBpFrv1BcRl5AH8I{SG$~@ei8tfNFRNo z8yc{A+M#47$z{+sgt0$kO7#P8;w3E>p7{M7-AX39)*}uJdb?$6O3FY$Znb&`KZ5D% z%k18byCa|B68WS|d&)|Nlgv_{p(%R@NH&-r_Y=+n6H^Hc0|}piIpRP7U`W4IChm?Q z7sfI}YYFAeQ|lu<%Oy_Y`(L8m0$BzL(CgIXEwdfWL1M;^j>_UtykmE3GMbKrQsYhj zLR9}A1+NqB$BIBmt{uZ^g*KuaL9Wy?Rc0Ojso0AR2vH6X<47h!L zeS0S-t?>YYD>E<0zLy;WY7@%kAOWf#-wu@^NJzNsXC>}zELVMLT!X~u@p=tJU#eQE zfgNJs8R%L)#1TMYJe!vt|M~L;L78!JD|N@Hi#= zt$ZU!YOSAI>X@)=46UoT1-$KNe)f~-L3C*YBIumIHQF+`wA*Coj*Hm z6uK|i)*i)#eosi#LjYBex}HJz^{Q)Xwm;10$4HH%Y~yitqVwLUtGN4ptU9#|~_wfCQmULbmxT=(eO?eIXE z$2Zp*NALnkpFL$;44W zmvCp1u;b(17)qB6-YHEzVbzmst)Yc=#GU;_UIG~BiGPv;lfl{V9mGMjCjWQbp0$R1Q2z}oH_heF9(&+>5ug`O?e$kKN+4mgIC0iIx8eR0 zoI7X~(hmI)`uEC;(_*sAn_IXRe59ckc@*sc7W=j08-%a;9v*{Ve%7KAg5J%e06TjdOuB)xZ+dP7#=nbhioldvT zQ9ObA4e)70N1)c$RpDD;c=Jo3cg;X)CNlfxemOtzX{LBS!LJRjaC^)#> zW~$!j$Xe!))tL0(@5CVV?vKK4bf0`X23MsD6b~2jo$Z^%JKl7u!^3l&wwZbX+tf+F zfje0Ce3857eZq!(_N4|q7rW-40Vyy5x|fm8>*KlGi`}x3&T3xy2CxHFahWpG)N}u?kmJLp zQCe7DuzFnJ;!FL*QjNkTR@2+JqlEpr>}f zY`eEezE(Q3v}ENqnLg;3xF8Rl6{Z&wRa8qsZ@L~jRo1%inhy>SZ>QlA#4jx^S)ZUB zfP1wsJN{a8PJ~Uob~udm_L{b+#%%+~drmdO&2VsfVH~V_NK56rxm_wz=g$mg%5tA? zGKH?~hy+Hp=FN8$I~KK&E5imI6?Ap?TRlYpK_r=s=}JmVvj_^t6JNxOny?=JJ(&N) znTsQyPwO>5XE2U?ILofpI4<`+_=VTb?{L76IFNtRki>Un9GaLgQn;PGU-?ve&r{z! z`Sa(@oD_HSCrA+1_JD)pSI0eA79N%rx6>)sw7N^!xrnIG#0t5|z>Yo%K`^Y#s$Sm6 z6I=_1dmp1|SL%<}GafeZKC2ADt0UtiWyPmh#j384S1Dl+Qn8e_Sb$)6&Ig|4+wZ%v zMK0o}G3TL1)Gp6(+gfowym<~R?e2h*;v*dK{Y+7GoJD_PPxaNKYvtcD}eh;^ot|)td-!%wN>$xL4edf9|ZUjMColn2@PoMU2 zA`_`bT53yXEe2CICsM?`gr@d!bNFcu?^t$xb7`82PD@HXf}rz42i_-$(@xf15d9$P zAdhC#GYOM_%m-jj(*A)}9?wN7es_ELAImod8A=c|a{HvQ3ktqP9M5w^M@H&Tx-8U| zE%(6PF=!j7Qw#6dt2i3cTGEor5n9n>R44FxLK7}+4Hy0z{C4YN*UePO9?X$KC``%>4VySt&mhekue-7Djvn#IG;nw()O`#tT!H1sfGh29$Km3BfmsPyMMfTy3 z!{%AwuX~pa{(CDiNrnS7i-s@TYky{hXvrSP2=ONrp;ClQs^0tnVE}|Xk6T7QiDF*W zvy@Kf@s{p4;b_jcsU?Db@Fox7o_q~`gGWDA-l(W#0iayrx-{7aJSXTGh*BSMCTj56 z1C5)@$qnd|T4z!`A@@35&bf6CugBnQ8!kbC5|;jTPW_Sg$;sg~tyOy4$m8Qr5kWFZ zFVcKE6lhp7F5&s;JjdBpui?OX-!@t9W#4GYdme*A{;=WDsQz09iC-gbOBvv;K`P7r zEa>{2n@7$3P&uhSswob?GlM9IjQ2i9>*~G)Z!9mmz70;b$TS3N6#w!3yJ>mbhQ-4=%yjIk+`Ni2` zEyc@cNa4ISFg$Dl@>D92G(!}pbmNQvC7iSEXf770Zaarq(Oo=;xAPOoBS#QdWPoan z(qboCH^7k#v6gLwR5;{>pI7Fh>vL8MnzVY`FPlLfpWK|I_eK&~SD5e+^TC zhDHBtcwt;^d?GoXVyS%g(ikr8!`yPl^9=Fiw!t0XY^$;`GGY;|$B5{>vcASkP9zSkrT@S&vwmZNQ?hZt(_Fo3IApepM6>}W6z zmyL_jM=9y*ek(1vW_Z`$`<)Sqn(WLh45!w*4rUwJ*Yu@^dvVC+b3S3;+G%gloJEBm zY33TP>*cB)yuHei=A~E}sIcVi)Q# zo<29Q{IZ5#cqu_m>eU5;hSuGaZX2zm>2-Y-n!;C_7QwA!t1lJg)mrOmr^V`{$@I~yw7vKpx|f7vZwX|KR(gYldF5KSse3zdk@xe)SW#VzX1O^Ub?%(a z;A`C{Jbb-HPT}2GT?<%|U9ZKf0G?dVmxVGRr|bag&oea6EMQx%%rORiQ{ zleY^!JnNaml^+W7YGV(FV1xxODA^9DogaM)QyGn!g@vJ50WO9R3bG6eRC7SMfds*g zfG!-{Ea6L0F#D}*S#MW-?Q?h`Tv5oMnus30?`fngxzxim@RJCu=hXF_CAxI(*MTvI zy998#p~eZ6O1(vm;Q4eU>gJY4n(>3wuVO_2NRdkY_zM!@iJrmsF$DvysT@PS#In27 zTjah&QL9NsOgheqy3(2kk00=At4On)=M(#UEL`t9tOV9aHs#SJide1(Y}#nXDShjg zrVrhaYN)vZN71_FWS?EJy5+ltT7U3Mj|BVTdwie1d6~W1MY~1I(sTW8X9L+^Vj^Td z`OwwEV|iDM{};CgF*}S)Z^7p4YqHZ$Yjjz|>)VmHY)U~m{8T3Vz0<92t(X*i3@N=d zh_w7Fq>;9zjlw@a3BL1{dPA`i_&sFk$Ng3XitVhEVv>OHHtd3ZdW?z*|T3E58j7i*X4akK8c;?Kg*hkxZ7LODiHXvW9gqp(-FKObdC71-q!$7fKZ(EG~>OaB7yHp=$ z4l~+mQx^M%_l)WVJ@?C(FO}cCNpEU;Cgu8N_$*#F@D7dE&KJ?puB+1@?-EO%)VTa` z`u$0Wea_hXU3EOs8Lel5epP^neg)Bx8dk4PEVB7QFnAOe?(*sVo2{H5yC8_;guv>&gDfu5F>l#I-52_^?A$KJ26f%)y~y0Ev4 zo$)*m0wXBapb=HGwnSS@iY>7J?&IRiQM%mqIUsB~+UC#qQeNg6sbt~ZEOY0L>+T|5 zGq1Le4}ua`UnTuWQ=$nM^MHjjIJs)U^kw7*GChoCBNg1ja(mG;&#&O&f5hHFhczL) z!idR!fw19NR;&DGDS~2VpVlOae?Z{!RMm&)Gruy(%q>n{Dkb%kS%toafEusM;i>>4 z!f;sARNRbx<=d{cVU*Yi5%2ZPjDN<|6F1_fImcbS)}jI1^4Z9atlQ#U+CRt$$2ZRD zADyWT?(CEkOjamVFL@UEIW?67j+!X8NJvecDjw>m&JZNXSb2C3?@PY5LschMUbCV= zwrzaLF`;dzB0@F)jaJqDZZD-F(Q4#;pZr_Q1<~7!wo64sh-i9YS-b20438R@2QC)F zf1nS8kjn$%r{8#&yk(z#c#EPwavMI!jxY%fOh`sN<(uTt`+0Tn{+-JPo|0eDm|Hfx ziSRoj1kWN5D#hvLLgAyx*Cc7JGB47E-G|u{b3zqsK0I4BwFsf{u4t$&B3V%VMBzq~ zCzaN!>zI`&IN*MQZ;!4@YnliA1Kw#0k>iS!-H?VSl3wfb&h$E8<@E4C-T>vx5n z|9nbQ!>#E2!o}?)k$W{R9WmB^LvS`{v&=zenLIYOK`xhwu&Q9kii!%Xmv2IHVa+yw z+2|!SNWh7lxd-*c@atD zo!zi;dIQbSviCX?iCj1V*=eaUvajH6>D=;k@%`5p zPOiz3kvD-m%l`O8)E~!X@YrQt%Yi|fL8w~C!J+iZl`EYq*QojAa&vP@wDSuJ@g4!iBezbazCK8LjA_=Ypma1KwSrtk-Bp5oFA)w>wI|Jo+l(+>&rQi5FK9)6 z`iGr=72cMCPk4Q)FH81aYN_kytk0kFs;bfP7d>mvD@v9z>|9im!ycXDz{5O%SC zbz^i?&XtBz~33)@2!ix7(r1ylqXhzuDes30IAA6~$vG4%K0?ow=4N3JQ0|eG)`1J9`F0#}mEnHq@+kNWbc8%U;`!NN zbwC7%Js@;(!x@KDvNc$?g-(^LWx~pDK8*PpS&YeZraWrNn#-2b{19QYpi^j512n`V zFL}-S9USZYT^HFh{38(R4+y43j8h{$`G#!y{{0((#H!HGF((o5H#9pzS~j_^!vZ7^*EN_fKnU zYh*;k)BK!IpEUUS`N{9)ojLc8w>gp9yQ)@d(VUV#`)=T(7tWvG7$zd2fCnYyW%bcT zKPnusu5@qkN)UvvL=mQbu+xtUTSfBDjl`f#HtUN^3M@x!PsY?K{n{O=5DM(#$$R{D z4D)WsnYVfC6`#nX6x-?oMba%3JZ}QhC70Asrqrrvu3IKKSFnxMCB9`RjW7H_y+d!Z zP}wg%R8rBMXlUY0;2B~~$q=tG3n-qvqAqrK08%sJ1kn)H;^Ri5lVkUltE5$~3b{%L zp0*H=d3^G?7(A5a5ztR6jD(=YhS72k8<~N@ z1!2E|{r&x9(%ZPWEbuAEZTmZ*#Tpb@sD4{dO-;?r%@ur}0O-k3fmz`E{JgfVZpO)T zS1|52prTp{1iD>5c{R1Lc(sh$Uq6DA^+|kueB_0buGSV7>0z5ch^QJ!pPVTOo-uHC z>$x%t8j2>d*(|l((YZ%jU(QU(fQ@zY(WAFkDk{|2Ai-}8CpJLiQg+xuW>Tb`9@jgm zaY&|1w|Uob9449Xz060myS5vrhL0@&+q_f6du6^q=}>zsgoQj}(RkIaHcgf?T<4$L zn3^l7sxK@%wK#R!1fMb0UahE>#_XWU;2_CtglWFAY?>U9YcoA;H}|e= zj2_uUsiq`KsEEU3@rF)L)F$`>a%swKBM!c~$mWzr93qfT$3`u~)@hoC0M8#Z z&gQ|_X2;dJJvzzHZ@Tc*3AuS-9)7Hb>utYz>;5sSlA71c-9pUZ_)_6`Jb|_x<15ut`J>bW<+q>)&^p5>6#J#xk?BpMaQ&r z@;E$vRTzOd>bqR|n92#ni=O@V84MP53s5BW-~1yZBXceaRgEtHn{sV!eO(8jRdn>l z>6w}BYeviM@5Rsn!u*;Him_^$&gALoI4b+piNaOnaByg7RNHj-PzkzkWQ5(`gy$ir ztdG~Xj;(9*=?XF{Dg zaY7xWi7`cxbuyM$<)iAHI=(xUpC4IlYn)U^2EEwT=2sreehC6GKa!=zD*7TqK~J!9 z=kS>F1Lyg0fkfI9unfEbpQ20jPKiT22F|#)w4)hXo~5P@SK)PI8;StSSdaC$xzAFtz{JzxgUr5^)s8rXk;v^EAe zNyjm@Gw8?QR#3_1Enz_m-L?G+OvS4{#-YR$Fj}3i{w@p4&DZmjR0+e9CWiP{o(pe) zidpnm;lJq1S#^=hNmtRfJzhc!6ou}zbJLeEujoPnLx_6!?i}LiN;arB0C<^cY4<@( z?_@%GeHa-T@jWvzYqI=6O-*gUnYHrlvogF*ISX-#h|VRQD3sh4d>AV%2f*&2)H4oL zR;LYC=z4^-nL-&TD(T%!7C};U^t?I_CDtgV^7Lc+4bO*LETU82I=V?S9dQ%Rdumhm zqghKOD^|<%4iSv6>M{XU6e=yv{xR*G4Tpl-SHgy)b9+s{>nS(hU(}mk$9OYG1RJ#9z_jGOb+o8e< z8Js;AwKYrR-I1TBCgvmX(%n{KlF^MmW=RP)G;K?$7~Z0>tq|H0MB=Hv)9*l@NZ{HV zk3I}n`v5w>kɃ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

    Wm`KCKP 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 z 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

    9eBt|^){9?n$w6b!JZv?< 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 literal 0 HcmV?d00001 diff --git a/OpenStaticAnalyzer/python/demo/filter_linux.txt b/OpenStaticAnalyzer/python/demo/filter_linux.txt new file mode 100644 index 0000000..1bf9702 --- /dev/null +++ b/OpenStaticAnalyzer/python/demo/filter_linux.txt @@ -0,0 +1,2 @@ +-/tests/ +-/tests.py diff --git a/OpenStaticAnalyzer/python/demo/filter_win.txt b/OpenStaticAnalyzer/python/demo/filter_win.txt new file mode 100644 index 0000000..47c4cc6 --- /dev/null +++ b/OpenStaticAnalyzer/python/demo/filter_win.txt @@ -0,0 +1,2 @@ +-\\tests\\ +-\\tests.py diff --git a/OpenStaticAnalyzer/python/doc/usersguide/CMakeLists.txt b/OpenStaticAnalyzer/python/doc/usersguide/CMakeLists.txt new file mode 100644 index 0000000..b6cb116 --- /dev/null +++ b/OpenStaticAnalyzer/python/doc/usersguide/CMakeLists.txt @@ -0,0 +1,10 @@ + +set (UG_INPUTS + md/Main.md + md/SourceCodeMetricsRef.md + md/CodeDuplicationMetricsRef.md + md/PylintRef.md + md/Footnotes.md +) + +add_usersguide_generator (${OSA_TARGET_NAME}-UG ../../../doc/style/OpenStaticAnalyzer.css UG_INPUTS) diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/CodeDuplicationMetricsRef.md b/OpenStaticAnalyzer/python/doc/usersguide/md/CodeDuplicationMetricsRef.md new file mode 100644 index 0000000..c83d8df --- /dev/null +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/CodeDuplicationMetricsRef.md @@ -0,0 +1,152 @@ +## Reference of code duplication metrics + +Code cloning (or copy-paste programming) means the copying of an existing piece of source code, pasting it somewhere else, and typically performing smaller modifications on it. Based on the level of similarity between the copied code fragments we can define the following duplication types: + +- **Type-1**: the copied code parts are identical code fragments except for variations in whitespace, layout and comments. + +- **Type-2**: syntactically identical fragments except for variations in identifier names, literals, type references, whitespace, layout and comments. + +- **Type-3**: copied fragments with further modifications such as altered, added, or removed statements, in addition to variations in identifier names, literals, type references, whitespace, layout and comments. + +- **Type-4**: the copied code fragments are syntactically different, but they perform the same functionality, i.e. they are semantically the same. + +OpenStaticAnalyzer is capable of identifying Type-2 clones, i.e. code fragments that are structurally identical, but may differ in variable names, literals, identifiers, etc. + +Two code segments correspond to each other if they are copies of each other. This relation is an equivalence relation and we use the notion of clone classes to the classes of the relation, and the members of the classes will be referred to as clone instances. Owing to the nature of the relation, each clone class must contain at least two clone instances. + +Clones are tracked during the source code analysis of consecutive revisions of the analyzed software system. OpenStaticAnalyzer detects suspicious, inconsistently changing code copies, which are called "clone smells". The smells concerning clone classes are the following: + +- **Disappearing Clone Class (DCC):** The clone class existed in the previously analyzed revision but it does not exist anymore. + +- **Appearing Clone Class (ACC):** The clone class did not exist in the previously analyzed revision. + +The smells concerning clone instances are issued only if the containing clone class does not contain any smell. These are the following: + +- **Disappearing Clone Instance (DCI):** The clone instance existed in the previously analyzed revision but it does not exist anymore. + +- **Appearing Clone Instance (ACI):** The clone instance did not exist in the previously analyzed revision. + +- **Moving Clone Instance (MCI):** The clone instance belonged to a different clone class in the previously analyzed revision than its current class. + +The following table summarizes the code duplication metrics, their abbreviations, and their correspondence to different source code element types. + + Metric name Abbrev. Clone Instance Clone Class Method, Function Class Module Package Comp. + --------------------------------- -------- ---------------- ------------- ------------------ ------- -------- --------- ------- + Clone Age CA X X + Clone Classes CCL X X X X X + Clone Complexity CCO X X X X X X X + Clone Coverage CC X X X X X + Clone Elimination Effort CEE X X + Clone Elimination Gain CEG X X + Clone Embeddedness CE X X + Clone Instances CI X X X X X X + Clone Line Coverage CLC X X X X X + Clone Lines of Code CLLOC X X + Clone Logical Line Coverage CLLC X X X X X + Clone Risk CR X X + Clone Variability CV X X + Lines of Duplicated Code LDC X X X X X + Logical Lines of Duplicated Code LLDC X X X X X + Normalized Clone Radius NCR X X + +### Clone metrics + +#### Clone Age (CA) {#CA} + +**Clone class/clone instance:** number of previously analyzed revisions in which the clone class/clone instance was present + 1. + +#### Clone Classes (CCL) {#CCL} + +**Function/method/class/module/package:** number of clone classes having at least one clone instance in the source code element. + +**Component:** number of clone classes having at least one clone instance in the component. + +#### Clone Complexity (CCO) {#CCO} + +**Clone instance:** the McCabe complexity of the code fragment corresponding to the clone instance. + +**Clone class:** sum of CCO of clone instances in the clone class. + +**Function/method/class/module/package:** sum of CCO of clone instances in the source code element. + +**Component:** sum of CCO of clone instances in the component. + +#### Clone Coverage (CC) {#CC} + +**Function/method/class/module/package:** ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.). + +**Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). + +#### Clone Elimination Effort (CEE) {#CEE} + +**Clone class:** index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR. + +**Component:** index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. + +#### Clone Elimination Gain (CEG) {#CEG} + +**Clone class:** index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE. + +**Component:** index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. + +#### Clone Embeddedness (CE) {#CE} + +**Clone instance:** sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments. + +**Clone class:** sum of CE of the clone instances of the clone class + 1. + +#### Clone Instances (CI) {#CI} + +**Function/method/class/module/package:** number of clone instances in the source code element. + +**Component:** number of clone instances in the component. + +**Clone class:** number of clone instances in the clone class. + +#### Clone Line Coverage (CLC) {#CLC} + +**Function/method/class/module/package:** ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code. + +**Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. + +#### Clone Lines of Code (CLLOC) {#CLLOC} + +**Clone instance:** length of the clone instance expressed in terms of lines of code. + +**Clone class:** average of CLLOC of clone instances belonging to the clone class. + +#### Clone Logical Line Coverage (CLLC) {#CLLC} + +**Function/method/class/module/package:** ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines). + +**Component:** ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). + +#### Clone Risk (CR) {#CR} + +**Clone class:** risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV. + +**Component:** relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. + +#### Clone Variability (CV) {#CV} + +**Clone instance:** instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA). + +**Clone class:** instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. + +#### Lines of Duplicated Code (LDC) {#LDC} + +**Function/method/class/module/package:** number of code lines covered by code duplications in the source code element. + +**Component:** number of code lines covered by code duplications in the component. + +#### Logical Lines of Duplicated Code (LLDC) {#LLDC} + +**Function/method/class/module/package:** number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element. + +**Component:** The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. + +#### Normalized Clone Radius (NCR) {#NCR} + +**Clone class:** normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes. + +**Component:** average of NCR of the clone classes in the component. diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/Footnotes.md b/OpenStaticAnalyzer/python/doc/usersguide/md/Footnotes.md new file mode 100644 index 0000000..5a38747 --- /dev/null +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/Footnotes.md @@ -0,0 +1,10 @@ +# Footnotes + +[^2]: POSIX Extended Regular Expressions + +[^3]: For correct calculation of the TNDI metric, the user has to + specify which directories belong to the project with + the -projectBaseDir parameter. Without it, "every" directory will be + counted starting from the root, meaning that running the analysis + from directories that are at different depths will cause the value + of the TNDI metric to change. diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md b/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md new file mode 100644 index 0000000..2bef568 --- /dev/null +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/Main.md @@ -0,0 +1,389 @@ +# OpenStaticAnalyzer™ for Python + +![](../../../doc/logo/OSA_small.png) + +# Introduction + +OpenStaticAnalyzer for Python is a source code analyzer tool, which can perform deep static analysis of the source code of complex Python systems. + +The source code of a program is usually its only up-to-date documentation. At the same time, the source code is the exquisite bearer of knowledge, business processes and methodology, accumulated over a long period of time. Source code quality decrease, which happens due to many quick fixes and time pressure, results in the increase of development and testing costs, and operational risks. In spite of this, the source code usually receives hostile treatment and is merely considered as a tool. + +OpenStaticAnalyzer provides deep static analysis of source code. Using the results of the analysis, the quality of the analyzed source code can be improved and developed both in the short- and long term in a directed way. + +## Product characteristics + +The most important product characteristics of OpenStaticAnalyzer are the following: + +- Platform-independent command line tools + +- Transparent integration into build processes + +- Powerful filter management + +- Coding issue detection: + + - Metric threshold violations (MetricHunter module) + + - [Pylint] 1.8.2 coding rule violations + +- Clone detection (copy-pasted source code fragments) extended with clone tracking and "clone smells" + + - Syntax-based, so-called Type-2 clones + +- Metrics calculation at component, file, module, class, and method levels: + + - Source code metrics + + - Clone metrics + + - Coding rule violation metrics + +[Pylint]:http://www.pylint.org/ + +By continuous static analysis, the software developers can: + +- reduce the software erosion rate and this way decrease development costs; + +- coding problems can be identified before testing, so the number of test iterations and the testing costs can be reduced; + +- the number of errors in delivered software can be reduced, so the operational risks can be decreased, increasing the company's reputation. + +OpenStaticAnalyzer can analyze source code conforming to Python 2.7.x, 3.6.x and earlier versions. +It is sufficient to set the source directory of the project to be analyzed. + +With the help of the filtering mechanism it is possible to specify a certain part of the ASG to be used (or not to be used) during the analysis, hence the results can be made more focused and the usage of memory and CPU can be reduced (e.g. generated source files or test code can be filtered out). + +## Background + +During the static analysis, an Abstract Semantic Graph (ASG) is constructed from the language elements of the source code. This ASG is then processed by the different tools in the package to calculate product metrics, identify copy-pasted code (clones), coding rule violations, etc. + + +# Installation + +## Supported platforms + +OpenStaticAnalyzer supports the following x86 and x86-64 platforms: + +- Microsoft Windows 7, 8, 8.1, and 10 + +- Microsoft Windows 2008 R2 Server + +- Microsoft Windows 2012 Server + +- GNU/Linux with kernel version 2.6.18 and GNU C library 2.11 or newer + +## Requirements + +In order to use OpenStaticAnalyzer it is necessary to have Python 2.7 or 3.x installed on the computer. + +For Pylint coding rule violations Pylint 1.8.2 also must be installed. +In the case of a different version, the collected violations may be incomplete or incorrect. + +In case of Windows, the appropriate Microsoft Visual C++ 2015 Redistributable Package must be installed. It can be downloaded from the following URL: + +- [https://www.microsoft.com/en-us/download/details.aspx?id=48145] (x86/x64) + +[https://www.microsoft.com/en-us/download/details.aspx?id=48145]:https://www.microsoft.com/en-us/download/details.aspx?id=48145 + +The Linux package uses the code page conversion functions of the GNU C Library. If the conversion modules are not in the standard /usr/lib/gconv directory then the GCONV_PATH environment variable must be set according to the current installation of the GNU C Library. + +E.g.: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.bash} +export "GCONV_PATH=/usr/lib/x86_64-linux-gnu/gconv" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +## Installation package + +The OpenStaticAnalyzer installation package can be extracted into any folder and used from that location. +It can be executed with the command line program OpenStaticAnalyzerPython. + +The OpenStaticAnalyzer for Python package contains the following directories and files: + +Windows: + +| | | | +|----------------------------|------------------------------|---------------------------------------------| +| OpenStaticAnalyzer\\Python | | | +| | Demo | \# Example project directory | +| | Tools | \# ASG checker and exporter tools directory | +| | OpenStaticAnalyzerPython.exe | \# Program file to execute the analysis | +| | UsersGuide.html | \# User's guide | + +Linux: + +| | | | +|----------------------------|------------------------------|---------------------------------------------| +| OpenStaticAnalyzer/Python | | | +| | Demo | \# Example project directory | +| | Tools | \# ASG checker and exporter tools directory | +| | OpenStaticAnalyzerPython | \# Program file to execute the analysis | +| | UsersGuide.html | \# User's guide | + +# Preconditions + +It is enough to give only the directory of the source code (project directory). The only requirement is that the Python files shall be available under this directory. The results will be created regardless of the possible import errors of the Python modules. + +# Command line parameters + +OpenStaticAnalyzer can be executed with the following parameters: + +**-help** + + : It displays the detailed help and exits. + +**-resultsDir** + + : Relative or absolute path name of the directory where the results of the analysis will be stored. The directory will be created automatically if it does not exist. + +**-projectName** + + : The name of the analyzed software system. The name specified here will be used for storing the results. + +**-externalHardFilter** + + : Filter file specified with relative or absolute path, to filter out certain files from the analysis based on their path names. +Filtered files will not appear in the results. The filter file is a simple text file containing lines starting with '+' or '-' characters followed by a regular expression[^2]. Tip: you can use the \Q and \E anchors to make a substring literal, reducing the need of escaping backslashes. During the analysis, each input file will be checked for these expressions. If the first character of the last matching expression is '-', then the given file will be excluded from the analysis. If the first character of the last matching expression is '+', or there is no matching expression, then the file will be analyzed. A line starting with a different character than '-' or '+' will be ignored. On Windows the checking is case-insensitive. Example filter file content: + + # Filter out all source files starting with "test": + -test[^\.]*.py + # But test576.py is needed: + +test576.py + # Furthermore, files beginning with "test1742" are also needed: + +test1742[^\.]*.py + # Finally, test1742_b.py is not needed: + -test1742_b.py + +**-runMetricHunter** + + : This parameter turns on or off the MetricHunter module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". + +**-runDCF** + + : This parameter turns on or off the DuplicatedCodeFinder module. With this feature, OpenStaticAnalyzer identifies copy-pasted code fragments. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". + +**-runMET** + + : This parameter turns on or off the Metric module. With this feature, OpenStaticAnalyzer computes source code metrics. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". + +**-profileXML** + + : Global configuration file for OpenStaticAnalyzer. Its *tool-options* tag can be used to override the default metric thresholds for the MetricHunter tool. Furthermore, its *rule-options* tag can enable/disable or modify the priorities of multiple rules. An example profile xml file is shown below: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.xml} + + + + + + + + + + + + + + + + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**-cloneGenealogy** + + : This parameter turns on or off the tracking of code clones (copy-pasted source code fragments) through the consecutive revisions of the software system. It is required that during the analysis of the different revisions, the values set to projectName and resultsDir remain the same, so OpenStaticAnalyzer will handle them as different revisions of the same system. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "false". + +**-cloneMinLines** + + : This parameter sets the minimum required size of each duplication in lines of code. The default value is 10. + +**-csvSeparator** + + : This parameter sets the separator character in the CSV outputs. The default value is the comma (","). The character set here must be placed in quotation marks (e.g. -csvSeparator=";"). Tabulator character can be set by the special "\\t" value. + +**-csvDecimalMark** + + : This parameter sets the decimal mark character in the CSV outputs. The default is value is the dot ("."). The character set here must be placed in quotation marks (e.g. -csvDecimalMark=","). + +**-maximumThreads** + + : This parameter sets the maximum number of parallel tasks the controller can start. The default value is the number of available CPU cores on the current system. + +**-currentDate** + + : The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used. + +**-cleanResults** + + : Cleans all but the last n number of timestamped result directory of the current project. + +**-projectBaseDir** + + : Directory of the source code to be analyzed specified with relative or absolute path. + +**-pythonBinary** + + : Sets Python 2.7/3.x binary executable name (full path is required if its directory is not in PATH). + +**-pythonVersion** + + : This parameter sets the Python version (2 or 3). + +**-runPylint** + + : This parameter turns on or off the Pylint coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by Pylint. Its value can be "true" (turn this feature on) or "false" (turn this feature off). The default value is "true". + +**-pylintOptions** + + : Passes command line options to Pylint. Options with arguments can be passed with successive -pylintOptions options. For example, to filter out directories and python files named "tests", the "-pylintOptions:--ignore=tests" option must be specified. + +# Usage + +OpenStaticAnalyzer can be used by simply invoking it on a directory containing the Python source modules. +The analysis works as follows: + +- If the directory contains an \_\_init\_\_.py file, OpenStaticAnalyzer analyzes the given directory (i.e. a python package) recursively while it founds a corresponding \_\_init\_\_.py file in the appropriate sub-directories. + +- If the directory does not contain an \_\_init\_\_.py file, OpenStaticAnalyzer checks all the first level sub-directories of the given directory and analyzes each of them containing an \_\_init\_\_.py file recursively (like in the above case). + +- In order to analyze python files not forming a python package, an empty \_\_init\_\_.py file needs to be added to the analysis directory. + + +Execute the following command to analyze the source code of a software system: + + Example (Windows): + + C:\Users\UserName\OpenStaticAnalyzer\Python\OpenStaticAnalyzerPython + -projectName=MyProject + -projectBaseDir=MyProjectDir + -resultsDir=Results + + Example (Linux): + + ~$ OpenStaticAnalyzer/Python/OpenStaticAnalyzerPython + -projectName=MyProject + -projectBaseDir=MyProjectDir + -resultsDir=Results + + +# Result files + +If any problems occur in the execution of the tools of the OpenStaticAnalyzer package during the code analysis, OpenStaticAnalyzer returns with error code 1. The error code of the given tool appears on the screen (detailed information on the bug can be found in the log directory), and the analysis is stopped, but the result files created until the failure are not deleted. + +An error-free execution of OpenStaticAnalyzer produces the following files: + +- Files containing the results of the static analysis in the results directory (set by the resultsDir parameter): + + - \$(projectName)\\python\\\$(DATE)\\\$(projectName)-\*.csv + + CSV (comma separated values) files containing different metrics: Component, Folder, File, Package, Module, Class, Method, Function, and Attribute level source code metrics, rule violation counts, and clone-related metrics at CloneClass and CloneInstance level. + + - \$(projectName)\\python\\\$(DATE)\\\$(projectName)-clones.txt + + List of the code clones (copy-pasted source code fragments) in the system. + + - \$(projectName)\\python\\\$(DATE)\\\$(projectName)-MetricHunter.txt + + List of the MetricHunter metric value violations in the system. + + - \$(projectName)\\python\\\$(DATE)\\\$(projectName)-Pylint.txt + + List of the Pylint coding rule violations in the system. + + - \$(projectName)\\python\\\$(DATE)\\\$(projectName).graph + + Binary representation of the result graph containing all the metrics, code clones and coding rule violations. + + - \$(projectName)\\python\\\$(DATE)\\\$(projectName).xml + + XML representation of the result graph containing all the metrics, code clones and coding rule violations. + + - \$(projectName)\\python\\\$(projectName).gsi + + Binary data file containing information for tracking the code clones through the consecutive revisions of the analyzed software system. + +- Other files and directories created in the results directory: + + - \$(projectName)\\python\\\$(DATE)\\openstaticanalyzer + + Directory, which contains configuration, binary, ASG, log, and temporary files created during the source code analysis. + + - \$(projectName)\\python\\\$(DATE)\\openstaticanalyzer\\asg + + Directory, which contains backup copies of the ASG and LIM files, the corresponding filter files, and the GSI file. + + - \$(projectName)\\python\\\$(DATE)\\openstaticanalyzer\\graph + + Directory, which contains backup copies of the graph files. + + - \$(projectName)\\python\\\$(DATE)\\openstaticanalyzer\\log + + Directory, which contains the log files created during the code analysis. + + - \$(projectName)\\python\\\$(DATE)\\openstaticanalyzer\\temp + + Directory, which contains the temporary files created during the code analysis. + +# Coding rule violation suppression + +The warnings issued by the integrated 3^rd^ party tool (Pylint) can be suppressed with its own official warning suppression mechanisms by modifying the "[MESSAGE CONTROL]" section of the OpenStaticAnalyzer/Python/Tools/Pylint.conf configuration file. + +The warnings of the MetricHunter module cannot be suppressed at the moment. + +# Demo + +The Demo directory of the installation package contains the directory structure, the build and analyzer scripts for the analysis of an example project. +The ceilometer Open Stack Python module is included as the example project, which can also be downloaded from the following URL: + +[https://github.com/openstack/ceilometer] + +[https://github.com/openstack/ceilometer]:https://github.com/openstack/ceilometer + +To perform the source code analysis of the demo project, the analyze.bat/analyze.sh script has to be executed. + +Contents of the Demo directory: + +Windows: + +-------- ------------- -------------------------------------- + Demo\\ + ceilometer \# source code of OpenStack ceilometer + analyze.bat \# starts OpenStaticAnalyzer for Python + filter.txt \# a file to filter out the tests directory +-------- ------------- -------------------------------------- + +Linux: + +-------- ------------- -------------------------------------- + Demo/ + ceilometer \# source code of OpenStack ceilometer + analyze.sh \# starts OpenStaticAnalyzer for Python + filter.txt \# a file to filter out the tests directory +-------- ------------- -------------------------------------- + +# Error messages + +- Message: Please set the resultsDir parameter. Under this directory a new directory with the name of the analyzed project will be created, if it does not exist yet. All results will be stored there under separate directories with their names containing the date and time. + + Solution: The resultsDir parameter must be set. + +- Message: Please set the projectName parameter to the name of the analyzed software system. + + Solution: The projectName parameter must be set. + +# Known bugs and deficiencies + +Known bugs and deficiencies of OpenStaticAnalyzer for Python. + +- OpenStaticAnalyzer places the results into the directory specified by the projectName parameter. If special characters (like '\<', '\>', etc.) are used in the parameter, the analysis will probably fail. + +# FAQ + +Frequently Asked Questions regarding OpenStaticAnalyzer. + +- Problem: On Windows platforms, in case of deep directory hierarchies, it may happen that the full paths of some files exceed 259 characters. In this case some OpenStaticAnalyzer tools may have problems with opening these files; they will terminate and write appropriate messages in the logs. + + Solution: Move the files to be analyzed to a directory closer to the file system root, or use the 'subst' shell command. + +# Appendices diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/PylintRef.md b/OpenStaticAnalyzer/python/doc/usersguide/md/PylintRef.md new file mode 100644 index 0000000..48ea7f2 --- /dev/null +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/PylintRef.md @@ -0,0 +1,1247 @@ +## Reference of Pylint coding rule violations + +OpenStaticAnalyzer executes the [Pylint] tool for coding rule violation checking and imports its results. OpenStaticAnalyzer also associates the issued rule violations with source code elements (i.e. methods, functions, classes, packages, and modules), and calculates metrics for the source code elements, which represent the amount of violations of each ruleset, rule, and priority groups, respectively. + +OpenStaticAnalyzer uses Pylint "as is", without any guaranties that the results of Pylint are correct. All statements of the Pylint license apply here as well. All texts describing the rulesets and the individual rules are copied from Pylint with some minor grammatical fixes. +The list of rulesets and rules contained in each ruleset are the following: + +- **Async Rules:** Async Rules + +- **Basic Rules:** Basic Rules + +- **Class Rules:** Class Rules + +- **Design Rules:** Design Rules + +- **Exception Rules:** Exception Rules + +- **Format Rules:** Format Rules + +- **Import Rules:** Import Rules + +- **Iterable Check Rules:** Iterable Check Rules + +- **Len Rules:** Len Rules + +- **Logging Rules:** Logging Rules + +- **Miscellaneous Rules:** Miscellaneous Rules + +- **Newstyle Rules:** Newstyle Rules + +- **Python3 Rules:** Python3 Rules + +- **Refactoring Rules:** Refactoring Rules + +- **Spelling Rules:** Spelling Rules + +- **Stdlib Rules:** Stdlib Rules + +- **String Constant Rules:** String Constant Rules + +- **String Rules:** String Rules + +- **Typecheck Rules:** Typecheck Rules + +- **Variable Rules:** Variable Rules + +The following table contains the enabled rules and their priorities: + + Category Name Abbreviation Prio. + ---------------------- ------------------------------------ ------------- --------- + Async Rules Not Async Context Manager PYLINT_NACM Critical + Yield Inside Async Function PYLINT_YIAF Critical + Basic Rules Abstract Class Instantiated PYLINT_ACI Critical + Assert On Tuple PYLINT_AOT Major + Assign To New Keyword PYLINT_ATNK Major + Bad Reversed Sequence PYLINT_BRS Critical + Blacklisted Name PYLINT_BN Minor + Confusing With Statement PYLINT_CWS Major + Continue In Finally PYLINT_CIF Critical + Dangerous Default Value PYLINT_DDV Major + Deprecated Lambda PYLINT_DL Major + Duplicate Argument Name PYLINT_DAN Critical + Duplicate Key PYLINT_DK Major + Empty Docstring PYLINT_ED Minor + Eval Used PYLINT_EU Major + Exec Used PYLINT_ExU Major + Expression Not Assigned PYLINT_ENA Major + Function Redefined PYLINT_FR Critical + Init Is Generator PYLINT_IIG Critical + Invalid Name PYLINT_IN Minor + Invalid Star Assignment Target PYLINT_ISAT Critical + Literal Comparison PYLINT_LC Minor + Lost Exception PYLINT_LoE Major + Misplaced Comparison Constant PYLINT_MCC Minor + Missing Docstring PYLINT_MD Minor + Nonexistent Operator PYLINT_NO Critical + Nonlocal And Global PYLINT_NAG Critical + Nonlocal Without Binding PYLINT_NWB Critical + Not In Loop PYLINT_NIL Critical + Pointless Statement PYLINT_PS Major + Pointless String Statement PYLINT_PSS Major + Return Arg In Generator PYLINT_RAIG Critical + Return In Init PYLINT_RII Critical + Return Outside Function PYLINT_ROF Critical + Singleton Comparison PYLINT_SC Minor + Star Needs Assignment Target PYLINT_SNAT Critical + Too Many Star Expressions PYLINT_TMSE Critical + Unidiomatic Typecheck PYLINT_UT Minor + Unnecessary Lambda PYLINT_UL Major + Unnecessary Pass PYLINT_UP Major + Unneeded Not PYLINT_UN Minor + Unreachable PYLINT_U Major + Used Prior Global Declaration PYLINT_UPGD Critical + Useless Else On Loop PYLINT_UEOL Major + Using Constant Test PYLINT_UCT Major + Yield Outside Function PYLINT_YOF Critical + Class Rules Abstract Method PYLINT_AM Major + Access Member Before Definition PYLINT_AMBD Critical + Arguments Differ PYLINT_AD Major + Assigning Non Slot PYLINT_ANS Critical + Attribute Defined Outside Init PYLINT_ADOI Major + Bad Classmethod Argument PYLINT_BCA Minor + Bad Mcs Classmethod Argument PYLINT_BMCA Minor + Bad Mcs Method Argument PYLINT_BMMA Minor + Bad Staticmethod Argument PYLINT_BSA Major + Duplicate Bases PYLINT_DB Critical + Inconsistent Mro PYLINT_IM Critical + Inherit Non Class PYLINT_INC Critical + Invalid Length Returned PYLINT_ILR Critical + Invalid Slots PYLINT_InS Critical + Invalid Slots Object PYLINT_ISO Critical + Method Hidden PYLINT_MH Critical + No Classmethod Decorator PYLINT_NCD Minor + No Init PYLINT_NI Major + No Method Argument PYLINT_NMA Critical + No Self Argument PYLINT_NSA Critical + No Self Use PYLINT_NSU Minor + No Staticmethod Decorator PYLINT_NSD Minor + Non Iterator Returned PYLINT_NIR Critical + Non Parent Init Called PYLINT_NPIC Major + Protected Access PYLINT_PA Major + Signature Differs PYLINT_SD Major + Single String Used For Slots PYLINT_SSUFS Minor + Super Init Not Called PYLINT_SINC Major + Unexpected Special Method Signature PYLINT_USMS Critical + Useless Super Delegation PYLINT_USD Major + Design Rules Too Few Public Methods PYLINT_TFPM Minor + Too Many Ancestors PYLINT_TMA Minor + Too Many Arguments PYLINT_ToMA Minor + Too Many Boolean Expressions PYLINT_TMBE Minor + Too Many Branches PYLINT_TMB Minor + Too Many Instance Attributes PYLINT_TMIA Minor + Too Many Locals PYLINT_ToML Minor + Too Many Public Methods PYLINT_TMPM Minor + Too Many Return Statements PYLINT_TMRS Minor + Too Many Statements PYLINT_TMS Minor + Exception Rules Bad Except Order PYLINT_BEO Critical + Bad Exception Context PYLINT_BEC Critical + Bare Except PYLINT_BE Major + Binary Op Exception PYLINT_BOE Major + Broad Except PYLINT_BrE Major + Catching Non Exception PYLINT_CNE Critical + Duplicate Except PYLINT_DE Major + Misplaced Bare Raise PYLINT_MBR Critical + Nonstandard Exception PYLINT_NE Major + Notimplemented Raised PYLINT_NR Critical + Raising Bad Type PYLINT_RBT Critical + Raising Format Tuple PYLINT_RFT Major + Raising Non Exception PYLINT_RNE Critical + Format Rules Bad Continuation PYLINT_BC Minor + Bad Indentation PYLINT_BI Major + Bad Whitespace PYLINT_BW Minor + Line Too Long PYLINT_LTL Minor + Lowercase L Suffix PYLINT_LLS Major + Missing Final Newline PYLINT_MFN Minor + Mixed Indentation PYLINT_MI Major + Mixed Line Endings PYLINT_MLE Minor + Multiple Statements PYLINT_MS Minor + Superfluous Parens PYLINT_SP Minor + Too Many Lines PYLINT_TML Minor + Trailing Newlines PYLINT_TN Minor + Trailing Whitespace PYLINT_TW Minor + Unexpected Line Ending Format PYLINT_ULEF Minor + Unnecessary Semicolon PYLINT_US Major + Import Rules Cyclic Import PYLINT_CI Minor + Deprecated Module PYLINT_DeM Major + Import Self PYLINT_IS Major + Misplaced Future PYLINT_MF Major + Multiple Imports PYLINT_MuI Minor + Reimported PYLINT_R Major + Relative Beyond Top Level PYLINT_RBTL Critical + Relative Import PYLINT_RI Major + Ungrouped Imports PYLINT_UngI Minor + Wildcard Import PYLINT_WI Major + Wrong Import Order PYLINT_WIO Minor + Wrong Import Position PYLINT_WIP Minor + Iterable Check Rules Not A Mapping PYLINT_NAM Critical + Not An Iterable PYLINT_NoAI Critical + Len Rules Len As Condition PYLINT_LAC Minor + Logging Rules Logging Format Interpolation PYLINT_LFI Major + Logging Format Truncated PYLINT_LFT Critical + Logging Not Lazy PYLINT_LNL Major + Logging Too Few Args PYLINT_LTFA Critical + Logging Too Many Args PYLINT_LTMA Critical + Logging Unsupported Format PYLINT_LUF Critical + Miscellaneous Rules Fixme PYLINT_Fi Major + Invalid Encoded Data PYLINT_IED Major + Newstyle Rules Bad Super Call PYLINT_BSC Critical + Missing Super Argument PYLINT_MSA Critical + Old Style Class PYLINT_OSC Minor + Property On Old Class PYLINT_POOC Major + Slots On Old Class PYLINT_SOOC Critical + Super On Old Class PYLINT_SuOOC Critical + Python3 Rules Apply Builtin PYLINT_AB Major + Backtick PYLINT_B Critical + Bad Python3 Import PYLINT_BP3I Major + Basestring Builtin PYLINT_BaB Major + Buffer Builtin PYLINT_BuB Major + Cmp Builtin PYLINT_CB Major + Cmp Method PYLINT_CM Major + Coerce Builtin PYLINT_CoB Major + Coerce Method PYLINT_CoM Major + Delslice Method PYLINT_DM Major + Deprecated Itertools Function PYLINT_DIF Major + Deprecated Str Translate Call PYLINT_DSTC Major + Deprecated String Function PYLINT_DSF Major + Deprecated Types Field PYLINT_DTF Major + Dict Items Not Iterating PYLINT_DINI Major + Dict Iter Method PYLINT_DIM Major + Dict Keys Not Iterating PYLINT_DKNI Major + Dict Values Not Iterating PYLINT_DVNI Major + Dict View Method PYLINT_DVM Major + Div Method PYLINT_DiM Major + Eq Without Hash PYLINT_EWH Major + Exception Message Attribute PYLINT_EMA Major + Execfile Builtin PYLINT_EB Major + File Builtin PYLINT_FB Major + Filter Builtin Not Iterating PYLINT_FBNI Major + Getslice Method PYLINT_GM Major + Hex Method PYLINT_HM Major + Idiv Method PYLINT_IdM Major + Import Star Module Level PYLINT_ISML Critical + Indexing Exception PYLINT_InE Major + Input Builtin PYLINT_IB Major + Intern Builtin PYLINT_InB Major + Invalid Str Codec PYLINT_ISC Major + Long Builtin PYLINT_LB Major + Long Suffix PYLINT_LS Critical + Map Builtin Not Iterating PYLINT_MBNI Major + Metaclass Assignment PYLINT_MA Major + Next Method Called PYLINT_NMC Major + Next Method Defined PYLINT_NMD Major + No Absolute Import PYLINT_NAI Major + Non Ascii Bytes Literal PYLINT_NABL Critical + Nonzero Method PYLINT_NoM Major + Oct Method PYLINT_OM Major + Old Division PYLINT_OD Major + Old Ne Operator PYLINT_ONO Critical + Old Octal Literal PYLINT_OOL Critical + Old Raise Syntax PYLINT_ORS Critical + Parameter Unpacking PYLINT_PU Critical + Print Statement PYLINT_PrS Critical + Raising String PYLINT_RS Major + Range Builtin Not Iterating PYLINT_RBNI Major + Raw_input Builtin PYLINT_RB Major + Rdiv Method PYLINT_RM Major + Reduce Builtin PYLINT_RedB Major + Reload Builtin PYLINT_RelB Major + Round Builtin PYLINT_RoB Major + Setslice Method PYLINT_SM Major + Standarderror Builtin PYLINT_SB Major + Sys Max Int PYLINT_SMI Major + Unichr Builtin PYLINT_UnB Major + Unicode Builtin PYLINT_UB Major + Unpacking In Except PYLINT_UIE Critical + Using Cmp Argument PYLINT_UCA Major + Xrange Builtin PYLINT_XB Major + Zip Builtin Not Iterating PYLINT_ZBNI Major + Refactoring Rules Consider Iterating Dictionary PYLINT_CID Minor + Consider Merging Isinstance PYLINT_CMI Minor + Consider Using Enumerate PYLINT_CUE Minor + Consider Using Ternary PYLINT_CUT Minor + Inconsistent Return Statements PYLINT_IRS Minor + No Else Return PYLINT_NER Minor + Redefined Argument From Local PYLINT_RAFL Minor + Simplifiable If Statement PYLINT_SIS Minor + Simplify Boolean Expression PYLINT_SBE Minor + Stop Iteration Return PYLINT_SIR Minor + Too Many Nested Blocks PYLINT_TMNB Minor + Trailing Comma Tuple PYLINT_TCT Minor + Spelling Rules Invalid Characters In Docstring PYLINT_ICID Minor + Wrong Spelling In Comment PYLINT_WSIC Minor + Wrong Spelling In Docstring PYLINT_WSID Minor + Stdlib Rules Bad Open Mode PYLINT_BOM Major + Bad Thread Instantiation PYLINT_BTI Major + Boolean Datetime PYLINT_BD Major + Deprecated Method PYLINT_DepM Major + Redundant Unittest Assert PYLINT_RUA Major + Shallow Copy Environ PYLINT_SCE Major + String Constant Rules Anomalous Backslash In String PYLINT_ABIS Major + Anomalous Unicode Escape In String PYLINT_AUEIS Major + String Rules Bad Format Character PYLINT_BFC Critical + Bad Format String PYLINT_BFS Major + Bad Format String Key PYLINT_BFSK Major + Bad Str Strip Call PYLINT_BSSC Critical + Format Combined Specification PYLINT_FCS Major + Format Needs Mapping PYLINT_FNM Critical + Invalid Format Index PYLINT_IFI Major + Missing Format Argument Key PYLINT_MFAK Major + Missing Format Attribute PYLINT_MFA Major + Missing Format String Key PYLINT_MFSK Critical + Mixed Format String PYLINT_MFS Critical + Too Few Format Args PYLINT_TFFA Critical + Too Many Format Args PYLINT_TMFA Critical + Truncated Format String PYLINT_TFS Critical + Unused Format String Argument PYLINT_UFSA Major + Unused Format String Key PYLINT_UFSK Major + Typecheck Rules Assignment From No Return PYLINT_AFNR Critical + Assignment From None PYLINT_AFN Critical + C Extension No Member PYLINT_CENM Minor + Invalid Metaclass PYLINT_InM Critical + Invalid Sequence Index PYLINT_ISI Critical + Invalid Slice Index PYLINT_InSI Critical + Invalid Unary Operand Type PYLINT_IUOT Critical + Keyword Arg Before Vararg PYLINT_KABV Major + Missing Kwoa PYLINT_MK Critical + No Member PYLINT_NM Critical + No Value For Parameter PYLINT_NVFP Critical + Not Callable PYLINT_NC Critical + Not Context Manager PYLINT_NCM Critical + Redundant Keyword Arg PYLINT_RKA Critical + Repeated Keyword PYLINT_RK Critical + Too Many Function Args PYLINT_ToMFA Critical + Unexpected Keyword Arg PYLINT_UKA Critical + Unsubscriptable Object PYLINT_UO Critical + Unsupported Assignment Operation PYLINT_UAO Critical + Unsupported Binary Operation PYLINT_UBO Critical + Unsupported Delete Operation PYLINT_UDO Critical + Unsupported Membership Test PYLINT_UMT Critical + Variable Rules Cell Var From Loop PYLINT_CVFL Major + Global At Module Level PYLINT_GAML Major + Global Statement PYLINT_GS Major + Global Variable Not Assigned PYLINT_GVNA Major + Global Variable Undefined PYLINT_GVU Major + Invalid All Object PYLINT_IAO Critical + No Name In Module PYLINT_NNIM Critical + Redefine In Handler PYLINT_RIH Major + Redefined Builtin PYLINT_ReB Major + Redefined Outer Name PYLINT_RON Major + Unbalanced Tuple Unpacking PYLINT_UTU Critical + Undefined All Variable PYLINT_UAV Critical + Undefined Loop Variable PYLINT_ULV Major + Undefined Variable PYLINT_UV Critical + Unpacking Non Sequence PYLINT_UNS Critical + Unused Argument PYLINT_UA Major + Unused Import PYLINT_UnI Major + Unused Variable PYLINT_UnV Major + Unused Wildcard Import PYLINT_UWI Major + Used Before Assignment PYLINT_UBA Critical + +### Async Rules + +#### Not Async Context Manager {#PYLINT_NACM} +Used when an async context manager is used with an object that does not implement the async context management protocol. This message can't be emitted when using Python \< 3.5. + +#### Yield Inside Async Function {#PYLINT_YIAF} +Used when an `yield` or `yield from` statement is found inside an async function. This message can't be emitted when using Python \< 3.5. + +### Basic Rules + +#### Abstract Class Instantiated {#PYLINT_ACI} +Used when an abstract class with `abc.ABCMeta` as metaclass has abstract methods and is instantiated. + +#### Assert On Tuple {#PYLINT_AOT} +A call of assert on a tuple will always evaluate to true if the tuple is not empty, and will always evaluate to false if it is. + +#### Assign To New Keyword {#PYLINT_ATNK} +Used when assignment will become invalid in future Python release due to introducing new keyword. + +#### Bad Reversed Sequence {#PYLINT_BRS} +Used when the first argument to reversed() builtin isn't a sequence (does not implement \_\_reversed\_\_, nor \_\_getitem\_\_ and \_\_len\_\_. + +#### Blacklisted Name {#PYLINT_BN} +Used when the name is listed in the black list (unauthorized names). + +#### Confusing With Statement {#PYLINT_CWS} +Emitted when a `with` statement component returns multiple values and uses name binding with `as` only for a part of those values, as in with ctx() as a, b. This can be misleading, since it's not clear if the context manager returns a tuple or if the node without a name binding is another context manager. + +#### Continue In Finally {#PYLINT_CIF} +Emitted when the `continue` keyword is found inside a finally clause, which is a SyntaxError. + +#### Dangerous Default Value {#PYLINT_DDV} +Used when a mutable value as list or dictionary is detected in a default value for an argument. + +#### Deprecated Lambda {#PYLINT_DL} +Used when a lambda is the first argument to "map" or "filter". It could be clearer as a list comprehension or generator expression. This message can't be emitted when using Python >= 3.0. + +#### Duplicate Argument Name {#PYLINT_DAN} +Duplicate argument names in function definitions are syntax errors. + +#### Duplicate Key {#PYLINT_DK} +Used when a dictionary expression binds the same key multiple times. + +#### Empty Docstring {#PYLINT_ED} +Used when a module, function, class or method has an empty docstring (it would be too easy ;). + +#### Eval Used {#PYLINT_EU} +Used when you use the "eval" function, to discourage its usage. Consider using `ast.literal_eval` for safely evaluating strings containing Python expressions from untrusted sources. + +#### Exec Used {#PYLINT_ExU} +Used when you use the "exec" statement (function for Python 3), to discourage its usage. That doesn't mean you can not use it! + +#### Expression Not Assigned {#PYLINT_ENA} +Used when an expression that is not a function call is assigned to nothing. Probably something else was intended. + +#### Function Redefined {#PYLINT_FR} +Used when a function / class / method is redefined. + +#### Init Is Generator {#PYLINT_IIG} +Used when the special class method \_\_init\_\_ is turned into a generator by a yield in its body. + +#### Invalid Name {#PYLINT_IN} +Used when the name doesn't match the regular expression associated to its type (constant, variable, class...). + +#### Invalid Star Assignment Target {#PYLINT_ISAT} +Emitted when a star expression is used as a starred assignment target. This message can't be emitted when using Python \< 3.0. + +#### Literal Comparison {#PYLINT_LC} +Used when comparing an object to a literal, which is usually what you do not want to do, since you can compare to a different literal than what was expected altogether. + +#### Lost Exception {#PYLINT_LoE} +Used when a break or a return statement is found inside the finally clause of a try...finally block: the exceptions raised in the try clause will be silently swallowed instead of being re-raised. + +#### Misplaced Comparison Constant {#PYLINT_MCC} +Used when the constant is placed on the left sideof a comparison. It is usually clearer in intent to place it in the right hand side of the comparison. + +#### Missing Docstring {#PYLINT_MD} +Used when a module, function, class or method has no docstring.Some special methods like \_\_init\_\_ doesn't necessary require a docstring. + +#### Nonexistent Operator {#PYLINT_NO} +Used when you attempt to use the C-style pre-increment orpre-decrement operator \-\- and ++, which doesn't exist in Python. + +#### Nonlocal And Global {#PYLINT_NAG} +Emitted when a name is both nonlocal and global. This message can't be emitted when using Python \< 3.0. + +#### Nonlocal Without Binding {#PYLINT_NWB} +Emitted when a nonlocal variable does not have an attached name somewhere in the parent scopes. This message can't be emitted when using Python \< 3.0. + +#### Not In Loop {#PYLINT_NIL} +Used when break or continue keywords are used outside a loop. + +#### Pointless Statement {#PYLINT_PS} +Used when a statement doesn't have (or at least seems to) any effect. + +#### Pointless String Statement {#PYLINT_PSS} +Used when a string is used as a statement (which of course has no effect). This is a particular case of W0104 with its own message so you can easily disable it if you're using those strings as documentation, instead of comments. + +#### Return Arg In Generator {#PYLINT_RAIG} +Used when a "return" statement with an argument is found outside in a generator function or method (e.g. with some "yield" statements). This message can't be emitted when using Python >= 3.3. + +#### Return In Init {#PYLINT_RII} +Used when the special class method \_\_init\_\_ has an explicit return value. + +#### Return Outside Function {#PYLINT_ROF} +Used when a "return" statement is found outside a function or method. + +#### Singleton Comparison {#PYLINT_SC} +Used when an expression is compared to singleton values like True, False or None. + +#### Star Needs Assignment Target {#PYLINT_SNAT} +Emitted when a star expression is not used in an assignment target. This message can't be emitted when using Python \< 3.0. + +#### Too Many Star Expressions {#PYLINT_TMSE} +Emitted when there are more than one starred expressions (`*x`) in an assignment. This is a SyntaxError. This message can't be emitted when using Python \< 3.0. + +#### Unidiomatic Typecheck {#PYLINT_UT} +The idiomatic way to perform an explicit typecheck in Python is to use isinstance(x, Y) rather than type(x) == Y, type(x) is Y. Though there are unusual situations where these give different results. + +#### Unnecessary Lambda {#PYLINT_UL} +Used when the body of a lambda expression is a function call on the same argument list as the lambda itself; such lambda expressions are in all but a few cases replaceable with the function being called in the body of the lambda. + +#### Unnecessary Pass {#PYLINT_UP} +Used when a "pass" statement that can be avoided is encountered. + +#### Unneeded Not {#PYLINT_UN} +Used when a boolean expression contains an unneeded negation. + +#### Unreachable {#PYLINT_U} +Used when there is some code behind a "return" or "raise" statement, which will never be accessed. + +#### Used Prior Global Declaration {#PYLINT_UPGD} +Emitted when a name is used prior a global declaration, which results in an error since Python 3.6. This message can't be emitted when using Python \< 3.6. + +#### Useless Else On Loop {#PYLINT_UEOL} +Loops should only have an else clause if they can exit early with a break statement, otherwise the statements under else should be on the same scope as the loop itself. + +#### Using Constant Test {#PYLINT_UCT} +Emitted when a conditional statement (If or ternary if) uses a constant value for its test. This might not be what the user intended to do. + +#### Yield Outside Function {#PYLINT_YOF} +Used when a "yield" statement is found outside a function or method. + +### Class Rules + +#### Abstract Method {#PYLINT_AM} +Used when an abstract method (i.e. raise NotImplementedError) is not overridden in concrete class. + +#### Access Member Before Definition {#PYLINT_AMBD} +Used when an instance member is accessed before it's actually assigned. + +#### Arguments Differ {#PYLINT_AD} +Used when a method has a different number of arguments than in the implemented interface or in an overridden method. + +#### Assigning Non Slot {#PYLINT_ANS} +Used when assigning to an attribute not defined in the class slots. + +#### Attribute Defined Outside Init {#PYLINT_ADOI} +Used when an instance attribute is defined outside the \_\_init\_\_ method. + +#### Bad Classmethod Argument {#PYLINT_BCA} +Used when a class method has a first argument named differently than the value specified in valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from regular instance methods. + +#### Bad Mcs Classmethod Argument {#PYLINT_BMCA} +Used when a metaclass class method has a first argument named differently than the value specified in valid-metaclass-classmethod-first-arg option (default to "mcs"), recommended to easily differentiate them from regular instance methods. + +#### Bad Mcs Method Argument {#PYLINT_BMMA} +Used when a metaclass method has a first agument named differently than the value specified in valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from regular instance methods. + +#### Bad Staticmethod Argument {#PYLINT_BSA} +Used when a static method has "self" or a value specified in valid-classmethod-first-arg option or valid-metaclass-classmethod-first-arg option as first argument. + +#### Duplicate Bases {#PYLINT_DB} +Used when a class has duplicate bases. + +#### Inconsistent Mro {#PYLINT_IM} +Used when a class has an inconsistent method resolutin order. + +#### Inherit Non Class {#PYLINT_INC} +Used when a class inherits from something which is not a class. + +#### Invalid Length Returned {#PYLINT_ILR} +Used when an \_\_len\_\_ method returns something which is not a non-negative integer. + +#### Invalid Slots {#PYLINT_InS} +Used when an invalid \_\_slots\_\_ is found in class. Only a string, an iterable or a sequence is permitted. + +#### Invalid Slots Object {#PYLINT_ISO} +Used when an invalid (non-string) object occurs in \_\_slots\_\_. + +#### Method Hidden {#PYLINT_MH} +Used when a class defines a method which is hidden by an instance attribute from an ancestor class or set by some client code. + +#### No Classmethod Decorator {#PYLINT_NCD} +Used when a class method is defined without using the decorator syntax. + +#### No Init {#PYLINT_NI} +Used when a class has no \_\_init\_\_ method, neither its parent classes. + +#### No Method Argument {#PYLINT_NMA} +Used when a method which should have the bound instance as first argument has no argument defined. + +#### No Self Argument {#PYLINT_NSA} +Used when a method has an attribute different the "self" as first argument. This is considered as an error since this is a so common convention that you shouldn't break it! + +#### No Self Use {#PYLINT_NSU} +Used when a method doesn't use its bound instance, and so could be written as a function. + +#### No Staticmethod Decorator {#PYLINT_NSD} +Used when a static method is defined without using the decorator syntax. + +#### Non Iterator Returned {#PYLINT_NIR} +Used when an \_\_iter\_\_ method returns something which is not an iterable (i.e. has no `next` method). + +#### Non Parent Init Called {#PYLINT_NPIC} +Used when an \_\_init\_\_ method is called on a class which is not in the direct ancestors for the analysed class. + +#### Protected Access {#PYLINT_PA} +Used when a protected member (i.e. class member with a name beginning with an underscore) is access outside the class or a descendant of the class where it's defined. + +#### Signature Differs {#PYLINT_SD} +Used when a method signature is different than in the implemented interface or in an overridden method. + +#### Single String Used For Slots {#PYLINT_SSUFS} +Used when a class \_\_slots\_\_ is a simple string, rather than an iterable. + +#### Super Init Not Called {#PYLINT_SINC} +Used when an ancestor class method has an \_\_init\_\_ method which is not called by a derived class. + +#### Unexpected Special Method Signature {#PYLINT_USMS} +Emitted when a special method was defined with an invalid number of parameters. If it has too few or too many, it might not work at all. + +#### Useless Super Delegation {#PYLINT_USD} +Used whenever we can detect that an overridden method is useless, relying on super() delegation to do the same thing as another method from the MRO. + +### Design Rules + +#### Too Few Public Methods {#PYLINT_TFPM} +Used when class has too few public methods, so be sure it's really worth it. + +#### Too Many Ancestors {#PYLINT_TMA} +Used when class has too many parent classes, try to reduce this to get a simpler (and so easier to use) class. + +#### Too Many Arguments {#PYLINT_ToMA} +Used when a function or method takes too many arguments. + +#### Too Many Boolean Expressions {#PYLINT_TMBE} +Used when a if statement contains too many boolean expressions. + +#### Too Many Branches {#PYLINT_TMB} +Used when a function or method has too many branches, making it hard to follow. + +#### Too Many Instance Attributes {#PYLINT_TMIA} +Used when class has too many instance attributes, try to reduce this to get a simpler (and so easier to use) class. + +#### Too Many Locals {#PYLINT_ToML} +Used when a function or method has too many local variables. + +#### Too Many Public Methods {#PYLINT_TMPM} +Used when class has too many public methods, try to reduce this to get a simpler (and so easier to use) class. + +#### Too Many Return Statements {#PYLINT_TMRS} +Used when a function or method has too many return statement, making it hard to follow. + +#### Too Many Statements {#PYLINT_TMS} +Used when a function or method has too many statements. You should then split it in smaller functions / methods. + +### Exception Rules + +#### Bad Except Order {#PYLINT_BEO} +Used when except clauses are not in the correct order (from the more specific to the more generic). If you don't fix the order, some exceptions may not be catched by the most specific handler. + +#### Bad Exception Context {#PYLINT_BEC} +Used when using the syntax "raise ... from ...", where the exception context is not an exception, nor None. This message can't be emitted when using Python \< 3.0. + +#### Bare Except {#PYLINT_BE} +Used when an except clause doesn't specify exceptions type to catch. + +#### Binary Op Exception {#PYLINT_BOE} +Used when the exception to catch is of the form "except A or B:". If intending to catch multiple, rewrite as "except (A, B):". + +#### Broad Except {#PYLINT_BrE} +Used when an except catches a too general exception, possibly burying unrelated errors. + +#### Catching Non Exception {#PYLINT_CNE} +Used when a class which doesn't inherit from BaseException is used as an exception in an except clause. + +#### Duplicate Except {#PYLINT_DE} +Used when an except catches a type that was already caught by a previous handler. + +#### Misplaced Bare Raise {#PYLINT_MBR} +Used when a bare raise is not used inside an except clause. This generates an error, since there are no active exceptions to be reraised. An exception to this rule is represented by a bare raise inside a finally clause, which might work, as long as an exception is raised inside the try block, but it is nevertheless a code smell that must not be relied upon. + +#### Nonstandard Exception {#PYLINT_NE} +Used when a custom exception class is raised but doesn't inherit from the builtin "Exception" class. This message can't be emitted when using Python >= 3.0. + +#### Notimplemented Raised {#PYLINT_NR} +Used when NotImplemented is raised instead of NotImplementedError. + +#### Raising Bad Type {#PYLINT_RBT} +Used when something which is neither a class, an instance or a string is raised (i.e. a `TypeError` will be raised). + +#### Raising Format Tuple {#PYLINT_RFT} +Used when passing multiple arguments to an exception constructor, the first of them a string literal containing what appears to be placeholders intended for formatting. + +#### Raising Non Exception {#PYLINT_RNE} +Used when a new style class which doesn't inherit from BaseException is raised. + +### Format Rules + +#### Bad Continuation {#PYLINT_BC} +TODO + +#### Bad Indentation {#PYLINT_BI} +Used when an unexpected number of indentation's tabulations or spaces has been found. + +#### Bad Whitespace {#PYLINT_BW} +Used when a wrong number of spaces is used around an operator, bracket or block opener. + +#### Line Too Long {#PYLINT_LTL} +Used when a line is longer than a given number of characters. + +#### Lowercase L Suffix {#PYLINT_LLS} +Used when a lower case "l" is used to mark a long integer. You should use a upper case "L" since the letter "l" looks too much like the digit "1". This message can't be emitted when using Python >= 3.0. + +#### Missing Final Newline {#PYLINT_MFN} +Used when the last line in a file is missing a newline. + +#### Mixed Indentation {#PYLINT_MI} +Used when there are some mixed tabs and spaces in a module. + +#### Mixed Line Endings {#PYLINT_MLE} +Used when there are mixed (LF and CRLF) newline signs in a file. + +#### Multiple Statements {#PYLINT_MS} +Used when more than on statement are found on the same line. + +#### Superfluous Parens {#PYLINT_SP} +Used when a single item in parentheses follows an if, for, or other keyword. + +#### Too Many Lines {#PYLINT_TML} +Used when a module has too much lines, reducing its readability. + +#### Trailing Newlines {#PYLINT_TN} +Used when there are trailing blank lines in a file. + +#### Trailing Whitespace {#PYLINT_TW} +Used when there is whitespace between the end of a line and the newline. + +#### Unexpected Line Ending Format {#PYLINT_ULEF} +Used when there is different newline than expected. + +#### Unnecessary Semicolon {#PYLINT_US} +Used when a statement is ended by a semi-colon (";"), which isn't necessary (that's python, not C ;). + +### Import Rules + +#### Cyclic Import {#PYLINT_CI} +Used when a cyclic import between two or more modules is detected. + +#### Deprecated Module {#PYLINT_DeM} +Used a module marked as deprecated is imported. + +#### Import Self {#PYLINT_IS} +Used when a module is importing itself. + +#### Misplaced Future {#PYLINT_MF} +Python 2.5 and greater require \_\_future\_\_ import to be the first non docstring statement in the module. + +#### Multiple Imports {#PYLINT_MuI} +Used when import statement importing multiple modules is detected. + +#### Reimported {#PYLINT_R} +Used when a module is reimported multiple times. + +#### Relative Beyond Top Level {#PYLINT_RBTL} +Used when a relative import tries to access too many levels in the current package. + +#### Relative Import {#PYLINT_RI} +Used when an import relative to the package directory is detected. This message can't be emitted when using Python >= 3.0. + +#### Ungrouped Imports {#PYLINT_UngI} +Used when imports are not grouped by packages. + +#### Wildcard Import {#PYLINT_WI} +Used when `from module import *` is detected. + +#### Wrong Import Order {#PYLINT_WIO} +Used when PEP8 import order is not respected (standard imports first, then third-party libraries, then local imports). + +#### Wrong Import Position {#PYLINT_WIP} +Used when code and imports are mixed. + +### Iterable Check Rules + +#### Not A Mapping {#PYLINT_NAM} +Used when a non-mapping value is used in place wheremapping is expected. + +#### Not An Iterable {#PYLINT_NoAI} +Used when a non-iterable value is used in place whereiterable is expected. + +### Len Rules + +#### Len As Condition {#PYLINT_LAC} +Used when Pylint detects incorrect use of len(sequence) inside conditions. + +### Logging Rules + +#### Logging Format Interpolation {#PYLINT_LFI} +Used when a logging statement has a call form of "logging.\(format\_string.format(format\_args...))". Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments. + +#### Logging Format Truncated {#PYLINT_LFT} +Used when a logging statement format string terminates before the end of a conversion specifier. + +#### Logging Not Lazy {#PYLINT_LNL} +Used when a logging statement has a call form of "logging.\(format\_string % (format\_args...))". Such calls should leave string interpolation to the logging method itself and be written "logging.\(format\_string, format\_args...)" so that the program may avoid incurring the cost of the interpolation in those cases in which no message will be logged. For more, see . + +#### Logging Too Few Args {#PYLINT_LTFA} +Used when a logging format string is given too many arguments. + +#### Logging Too Many Args {#PYLINT_LTMA} +Used when a logging format string is given too few arguments. + +#### Logging Unsupported Format {#PYLINT_LUF} +Used when an unsupported format character is used in a logging statement format string. + +### Miscellaneous Rules + +#### Fixme {#PYLINT_Fi} +Used when a warning note as FIXME or XXX is detected. + +#### Invalid Encoded Data {#PYLINT_IED} +Used when a source line cannot be decoded using the specified source file encoding. This message can't be emitted when using Python >= 3.0. + +### Newstyle Rules + +#### Bad Super Call {#PYLINT_BSC} +Used when another argument than the current class is given as first argument of the super builtin. + +#### Missing Super Argument {#PYLINT_MSA} +Used when the super builtin didn't receive an argument. This message can't be emitted when using Python >= 3.0. + +#### Old Style Class {#PYLINT_OSC} +Used when a class is defined that does not inherit from anotherclass and does not inherit explicitly from "object". This message can't be emitted when using Python >= 3.0. + +#### Property On Old Class {#PYLINT_POOC} +Used when Pylint detect the use of the builtin "property" on an old style class while this is relying on new style classes features. This message can't be emitted when using Python >= 3.0. + +#### Slots On Old Class {#PYLINT_SOOC} +Used when an old style class uses the \_\_slots\_\_ attribute. This message can't be emitted when using Python >= 3.0. + +#### Super On Old Class {#PYLINT_SuOOC} +Used when an old style class uses the super builtin. This message can't be emitted when using Python >= 3.0. + +### Python3 Rules + +#### Apply Builtin {#PYLINT_AB} +Used when the apply built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Backtick {#PYLINT_B} +Used when the deprecated "``" (backtick) operator is used instead of the str() function. This message can't be emitted when using Python >= 3.0. + +#### Bad Python3 Import {#PYLINT_BP3I} +Used when importing a module that no longer exists in Python 3. This message can't be emitted when using Python >= 3.0. + +#### Basestring Builtin {#PYLINT_BaB} +Used when the basestring built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Buffer Builtin {#PYLINT_BuB} +Used when the buffer built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Cmp Builtin {#PYLINT_CB} +Used when the cmp built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Cmp Method {#PYLINT_CM} +Used when a \_\_cmp\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Coerce Builtin {#PYLINT_CoB} +Used when the coerce built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Coerce Method {#PYLINT_CoM} +Used when a \_\_coerce\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Delslice Method {#PYLINT_DM} +Used when a \_\_delslice\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Deprecated Itertools Function {#PYLINT_DIF} +Used when accessing a function on itertools that has been removed in Python 3. This message can't be emitted when using Python >= 3.0. + +#### Deprecated Str Translate Call {#PYLINT_DSTC} +Used when using the deprecated deletechars parameters from str.translate. Usere.sub to remove the desired characters. This message can't be emitted when using Python >= 3.0. + +#### Deprecated String Function {#PYLINT_DSF} +Used when accessing a string function that has been deprecated in Python 3. This message can't be emitted when using Python >= 3.0. + +#### Deprecated Types Field {#PYLINT_DTF} +Used when accessing a field on types that has been removed in Python 3. This message can't be emitted when using Python >= 3.0. + +#### Dict Items Not Iterating {#PYLINT_DINI} +Used when dict.items is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Dict Iter Method {#PYLINT_DIM} +Used for calls to dict.iterkeys(), itervalues() or iteritems() (Python 3 lacks these methods). This message can't be emitted when using Python >= 3.0. + +#### Dict Keys Not Iterating {#PYLINT_DKNI} +Used when dict.keys is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Dict Values Not Iterating {#PYLINT_DVNI} +Used when dict.values is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Dict View Method {#PYLINT_DVM} +Used for calls to dict.viewkeys(), viewvalues() or viewitems() (Python 3 lacks these methods). This message can't be emitted when using Python >= 3.0. + +#### Div Method {#PYLINT_DiM} +Used when a \_\_div\_\_ method is defined. Using `__truediv__` and setting\_\_div\_\_ = \_\_truediv\_\_ should be preferred.(method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Eq Without Hash {#PYLINT_EWH} +Used when a class implements \_\_eq\_\_ but not \_\_hash\_\_. In Python 2, objects get object.\_\_hash\_\_ as the default implementation, in Python 3 objects get None as their default \_\_hash\_\_ implementation if they also implement \_\_eq\_\_. This message can't be emitted when using Python >= 3.0. + +#### Exception Message Attribute {#PYLINT_EMA} +Used when the message attribute is accessed on an Exception. Use str(exception) instead. This message can't be emitted when using Python >= 3.0. + +#### Execfile Builtin {#PYLINT_EB} +Used when the execfile built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### File Builtin {#PYLINT_FB} +Used when the file built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Filter Builtin Not Iterating {#PYLINT_FBNI} +Used when the filter built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Getslice Method {#PYLINT_GM} +Used when a \_\_getslice\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Hex Method {#PYLINT_HM} +Used when a \_\_hex\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Idiv Method {#PYLINT_IdM} +Used when a \_\_idiv\_\_ method is defined. Using `__itruediv__` and setting\_\_idiv\_\_ = \_\_itruediv\_\_ should be preferred.(method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Import Star Module Level {#PYLINT_ISML} +Used when the import star syntax is used somewhere else than the module level. This message can't be emitted when using Python >= 3.0. + +#### Indexing Exception {#PYLINT_InE} +Indexing exceptions will not work on Python 3. Use `exception.args[index]` instead. This message can't be emitted when using Python >= 3.0. + +#### Input Builtin {#PYLINT_IB} +Used when the input built-in is referenced (backwards-incompatible semantics in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Intern Builtin {#PYLINT_InB} +Used when the intern built-in is referenced (Moved to sys.intern in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Invalid Str Codec {#PYLINT_ISC} +Used when using str.encode or str.decode with a non-text encoding. Use codecs module to handle arbitrary codecs. This message can't be emitted when using Python >= 3.0. + +#### Long Builtin {#PYLINT_LB} +Used when the long built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Long Suffix {#PYLINT_LS} +Used when "l" or "L" is used to mark a long integer. This will not work in Python 3, since `int` and `long` types have merged. This message can't be emitted when using Python >= 3.0. + +#### Map Builtin Not Iterating {#PYLINT_MBNI} +Used when the map built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Metaclass Assignment {#PYLINT_MA} +Used when a metaclass is specified by assigning to \_\_metaclass\_\_ (Python 3 specifies the metaclass as a class statement argument). This message can't be emitted when using Python >= 3.0. + +#### Next Method Called {#PYLINT_NMC} +Used when an object's next() method is called (Python 3 uses the next() built-in function). This message can't be emitted when using Python >= 3.0. + +#### Next Method Defined {#PYLINT_NMD} +Used when a next method is defined that would be an iterator in Python 2 but is treated as a normal function in Python 3. This message can't be emitted when using Python >= 3.0. + +#### No Absolute Import {#PYLINT_NAI} +Used when an import is not accompanied by ``from __future__ import absolute_import`` (default behaviour in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Non Ascii Bytes Literal {#PYLINT_NABL} +Used when non-ascii bytes literals are found in a program. They are no longer supported in Python 3. This message can't be emitted when using Python >= 3.0. + +#### Nonzero Method {#PYLINT_NoM} +Used when a \_\_nonzero\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Oct Method {#PYLINT_OM} +Used when a \_\_oct\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Old Division {#PYLINT_OD} +Used for non-floor division w/o a float literal or ``from __future__ import division`` (Python 3 returns a float for int division unconditionally). This message can't be emitted when using Python >= 3.0. + +#### Old Ne Operator {#PYLINT_ONO} +Used when the deprecated "\<>" operator is used instead of "!=". This is removed in Python 3. This message can't be emitted when using Python >= 3.0. + +#### Old Octal Literal {#PYLINT_OOL} +Usen when encountering the old octal syntax, removed in Python 3. To use the new syntax, prepend 0o on the number. This message can't be emitted when using Python >= 3.0. + +#### Old Raise Syntax {#PYLINT_ORS} +Used when the alternate raise syntax 'raise foo, bar' is used instead of 'raise foo(bar)'. This message can't be emitted when using Python >= 3.0. + +#### Parameter Unpacking {#PYLINT_PU} +Used when parameter unpacking is specified for a function(Python 3 doesn't allow it). This message can't be emitted when using Python >= 3.0. + +#### Print Statement {#PYLINT_PrS} +Used when a print statement is used (`print` is a function in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Raising String {#PYLINT_RS} +Used when a string exception is raised. This will not work on Python 3. This message can't be emitted when using Python >= 3.0. + +#### Range Builtin Not Iterating {#PYLINT_RBNI} +Used when the range built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Raw_input Builtin {#PYLINT_RB} +Used when the raw\_input built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Rdiv Method {#PYLINT_RM} +Used when a \_\_rdiv\_\_ method is defined. Using `__rtruediv__` and setting\_\_rdiv\_\_ = \_\_rtruediv\_\_ should be preferred.(method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Reduce Builtin {#PYLINT_RedB} +Used when the reduce built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Reload Builtin {#PYLINT_RelB} +Used when the reload built-in function is referenced (missing from Python 3). You can use instead imp.reload or importlib.reload. This message can't be emitted when using Python >= 3.0. + +#### Round Builtin {#PYLINT_RoB} +Used when the round built-in is referenced (backwards-incompatible semantics in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Setslice Method {#PYLINT_SM} +Used when a \_\_setslice\_\_ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + +#### Standarderror Builtin {#PYLINT_SB} +Used when the StandardError built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Sys Max Int {#PYLINT_SMI} +Used when accessing sys.maxint. Use sys.maxsize instead. This message can't be emitted when using Python >= 3.0. + +#### Unichr Builtin {#PYLINT_UnB} +Used when the unichr built-in is referenced (Use chr in Python 3). This message can't be emitted when using Python >= 3.0. + +#### Unicode Builtin {#PYLINT_UB} +Used when the unicode built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Unpacking In Except {#PYLINT_UIE} +Python3 will not allow implicit unpacking of exceptions in except clauses. See . This message can't be emitted when using Python >= 3.0. + +#### Using Cmp Argument {#PYLINT_UCA} +Using the cmp argument for list.sort or the sorted builtin should be avoided, since it was removed in Python 3. Using either `key` or `functools.cmp_to_key` should be preferred. This message can't be emitted when using Python >= 3.0. + +#### Xrange Builtin {#PYLINT_XB} +Used when the xrange built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + +#### Zip Builtin Not Iterating {#PYLINT_ZBNI} +Used when the zip built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + +### Refactoring Rules + +#### Consider Iterating Dictionary {#PYLINT_CID} +Emitted when the keys of a dictionary are iterated through the .keys() method. It is enough to just iterate through the dictionary itself, as in "for key in dictionary". + +#### Consider Merging Isinstance {#PYLINT_CMI} +Used when multiple consecutive isinstance calls can be merged into one. + +#### Consider Using Enumerate {#PYLINT_CUE} +Emitted when code that iterates with range and len is encountered. Such code can be simplified by using the enumerate builtin. + +#### Consider Using Ternary {#PYLINT_CUT} +Used when one of known pre-python 2.5 ternary syntax is used. + +#### Inconsistent Return Statements {#PYLINT_IRS} +According to PEP8, if any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable). + +#### No Else Return {#PYLINT_NER} +Used in order to highlight an unnecessary block of code following an if containing a return statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a return statement. + +#### Redefined Argument From Local {#PYLINT_RAFL} +Used when a local name is redefining an argument, which might suggest a potential error. This is taken in account only for a handful of name binding operations, such as for iteration, with statement assignment and exception handler assignment. + +#### Simplifiable If Statement {#PYLINT_SIS} +Used when an if statement can be replaced with 'bool(test)'. + +#### Simplify Boolean Expression {#PYLINT_SBE} +Emitted when redundant pre-python 2.5 ternary syntax is used. + +#### Stop Iteration Return {#PYLINT_SIR} +According to PEP479, the raise of StopIteration to end the loop of a generator may lead to hard to find bugs. This PEP specify that raise StopIteration has to be replaced by a simple return statement. This message can't be emitted when using Python \< 3.0. + +#### Too Many Nested Blocks {#PYLINT_TMNB} +Used when a function or a method has too many nested blocks. This makes the code less understandable and maintainable. + +#### Trailing Comma Tuple {#PYLINT_TCT} +In Python, a tuple is actually created by the comma symbol, not by the parentheses. Unfortunately, one can actually create a tuple by misplacing a trailing comma, which can lead to potential weird bugs in your code. You should always use parentheses explicitly for creating a tuple. This message can't be emitted when using Python \< 3.0. + +### Spelling Rules + +#### Invalid Characters In Docstring {#PYLINT_ICID} +Used when a word in docstring cannot be checked by enchant. + +#### Wrong Spelling In Comment {#PYLINT_WSIC} +Used when a word in comment is not spelled correctly. + +#### Wrong Spelling In Docstring {#PYLINT_WSID} +Used when a word in docstring is not spelled correctly. + +### Stdlib Rules + +#### Bad Open Mode {#PYLINT_BOM} +Python supports: r, w, a\[, x\] modes with b, +, and U (only with r) options. See . + +#### Bad Thread Instantiation {#PYLINT_BTI} +The warning is emitted when a threading.Thread class is instantiated without the target function being passed. By default, the first parameter is the group param, not the target param. + +#### Boolean Datetime {#PYLINT_BD} +Using datetime.time in a boolean context can hide subtle bugs when the time they represent matches midnight UTC. This behaviour was fixed in Python 3.5. See for reference. This message can't be emitted when using Python >= 3.5. + +#### Deprecated Method {#PYLINT_DepM} +The method is marked as deprecated and will be removed in a future version of Python. Consider looking for an alternative in the documentation. + +#### Redundant Unittest Assert {#PYLINT_RUA} +The first argument of assertTrue and assertFalse is a condition. If a constant is passed as parameter, that condition will be always true. In this case a warning should be emitted. + +#### Shallow Copy Environ {#PYLINT_SCE} +os.environ is not a dict object but proxy object, so shallow copy has still effects on original object. See for reference. + +### String Constant Rules + +#### Anomalous Backslash In String {#PYLINT_ABIS} +Used when a backslash is in a literal string but not as an escape. + +#### Anomalous Unicode Escape In String {#PYLINT_AUEIS} +Used when an escape like \\u is encountered in a byte string where it has no effect. + +### String Rules + +#### Bad Format Character {#PYLINT_BFC} +Used when a unsupported format character is used in a format string. + +#### Bad Format String {#PYLINT_BFS} +Used when a PEP 3101 format string is invalid. This message can't be emitted when using Python \< 2.7. + +#### Bad Format String Key {#PYLINT_BFSK} +Used when a format string that uses named conversion specifiers is used with a dictionary whose keys are not all strings. + +#### Bad Str Strip Call {#PYLINT_BSSC} +The argument to a str.\{l,r,\}strip call contains a duplicate character. + +#### Format Combined Specification {#PYLINT_FCS} +Usen when a PEP 3101 format string contains both automatic field numbering (e.g. '\{\}') and manual field specification (e.g. '\{0\}'). This message can't be emitted when using Python \< 2.7. + +#### Format Needs Mapping {#PYLINT_FNM} +Used when a format string that uses named conversion specifiers is used with an argument that is not a mapping. + +#### Invalid Format Index {#PYLINT_IFI} +Used when a PEP 3101 format string uses a lookup specifier (\{a\[1\]\}), but the argument passed for formatting doesn't contain or doesn't have that key as an attribute. This message can't be emitted when using Python \< 2.7. + +#### Missing Format Argument Key {#PYLINT_MFAK} +Used when a PEP 3101 format string that uses named fields doesn't receive one or more required keywords. This message can't be emitted when using Python \< 2.7. + +#### Missing Format Attribute {#PYLINT_MFA} +Used when a PEP 3101 format string uses an attribute specifier (\{0.length\}), but the argument passed for formatting doesn't have that attribute. This message can't be emitted when using Python \< 2.7. + +#### Missing Format String Key {#PYLINT_MFSK} +Used when a format string that uses named conversion specifiers is used with a dictionary that doesn't contain all the keys required by the format string. + +#### Mixed Format String {#PYLINT_MFS} +Used when a format string contains both named (e.g. '%(foo)d') and unnamed (e.g. '%d') conversion specifiers. This is also used when a named conversion specifier contains * for the minimum field width and/or precision. + +#### Too Few Format Args {#PYLINT_TFFA} +Used when a format string that uses unnamed conversion specifiers is given too few arguments. + +#### Too Many Format Args {#PYLINT_TMFA} +Used when a format string that uses unnamed conversion specifiers is given too many arguments. + +#### Truncated Format String {#PYLINT_TFS} +Used when a format string terminates before the end of a conversion specifier. + +#### Unused Format String Argument {#PYLINT_UFSA} +Used when a PEP 3101 format string that uses named fields is used with an argument that is not required by the format string. This message can't be emitted when using Python \< 2.7. + +#### Unused Format String Key {#PYLINT_UFSK} +Used when a format string that uses named conversion specifiers is used with a dictionary that contains keys not required by the format string. + +### Typecheck Rules + +#### Assignment From No Return {#PYLINT_AFNR} +Used when an assignment is done on a function call but the inferred function doesn't return anything. + +#### Assignment From None {#PYLINT_AFN} +Used when an assignment is done on a function call but the inferred function returns nothing but None. + +#### C Extension No Member {#PYLINT_CENM} +Used when a variable is accessed for non-existent member of C extension. Due to unavailability of source static analysis is impossible, but it may be performed by introspecting living objects in run-time. + +#### Invalid Metaclass {#PYLINT_InM} +Emitted whenever we can detect that a class is using, as a metaclass, something which might be invalid for using as a metaclass. + +#### Invalid Sequence Index {#PYLINT_ISI} +Used when a sequence type is indexed with an invalid type. Valid types are ints, slices, and objects with an \_\_index\_\_ method. + +#### Invalid Slice Index {#PYLINT_InSI} +Used when a slice index is not an integer, None, or an object with an \_\_index\_\_ method. + +#### Invalid Unary Operand Type {#PYLINT_IUOT} +Emitted when an unary operand is used on an object which does not support this type of operation. + +#### Keyword Arg Before Vararg {#PYLINT_KABV} +When defining a keyword argument before variable positional arguments, one can end up in having multiple values passed for the aforementioned parameter in case the method is called with keyword arguments. + +#### Missing Kwoa {#PYLINT_MK} +Used when a function call does not pass a mandatory keyword-only argument. This message can't be emitted when using Python \< 3.0. + +#### No Member {#PYLINT_NM} +Used when a variable is accessed for an unexistent member. + +#### No Value For Parameter {#PYLINT_NVFP} +Used when a function call passes too few arguments. + +#### Not Callable {#PYLINT_NC} +Used when an object being called has been inferred to a non callable object. + +#### Not Context Manager {#PYLINT_NCM} +Used when an instance in a with statement doesn't implement the context manager protocol(\_\_enter\_\_/\_\_exit\_\_). + +#### Redundant Keyword Arg {#PYLINT_RKA} +Used when a function call would result in assigning multiple values to a function parameter, one value from a positional argument and one from a keyword argument. + +#### Repeated Keyword {#PYLINT_RK} +Emitted when a function call got multiple values for a keyword. + +#### Too Many Function Args {#PYLINT_ToMFA} +Used when a function call passes too many positional arguments. + +#### Unexpected Keyword Arg {#PYLINT_UKA} +Used when a function call passes a keyword argument that doesn't correspond to one of the function's parameter names. + +#### Unsubscriptable Object {#PYLINT_UO} +Emitted when a subscripted value doesn't support subscription(i.e. doesn't define \_\_getitem\_\_ method). + +#### Unsupported Assignment Operation {#PYLINT_UAO} +Emitted when an object does not support item assignment (i.e. doesn't define \_\_setitem\_\_ method). + +#### Unsupported Binary Operation {#PYLINT_UBO} +Emitted when a binary arithmetic operation between two operands is not supported. + +#### Unsupported Delete Operation {#PYLINT_UDO} +Emitted when an object does not support item deletion (i.e. doesn't define \_\_delitem\_\_ method). + +#### Unsupported Membership Test {#PYLINT_UMT} +Emitted when an instance in membership test expression doesn'timplement membership protocol (\_\_contains\_\_/\_\_iter\_\_/\_\_getitem\_\_). + +### Variable Rules + +#### Cell Var From Loop {#PYLINT_CVFL} +A variable used in a closure is defined in a loop. This will result in all closures using the same value for the closed-over variable. + +#### Global At Module Level {#PYLINT_GAML} +Used when you use the "global" statement at the module level since it has no effect. + +#### Global Statement {#PYLINT_GS} +Used when you use the "global" statement to update a global variable. Pylint just try to discourage this usage. That doesn't mean you can not use it! + +#### Global Variable Not Assigned {#PYLINT_GVNA} +Used when a variable is defined through the "global" statement but no assignment to this variable is done. + +#### Global Variable Undefined {#PYLINT_GVU} +Used when a variable is defined through the "global" statement but the variable is not defined in the module scope. + +#### Invalid All Object {#PYLINT_IAO} +Used when an invalid (non-string) object occurs in \_\_all\_\_. + +#### No Name In Module {#PYLINT_NNIM} +Used when a name cannot be found in a module. + +#### Redefine In Handler {#PYLINT_RIH} +Used when an exception handler assigns the exception to an existing name. + +#### Redefined Builtin {#PYLINT_ReB} +Used when a variable or function override a built-in. + +#### Redefined Outer Name {#PYLINT_RON} +Used when a variable's name hide a name defined in the outer scope. + +#### Unbalanced Tuple Unpacking {#PYLINT_UTU} +Used when there is an unbalanced tuple unpacking in assignment. + +#### Undefined All Variable {#PYLINT_UAV} +Used when an undefined variable name is referenced in \_\_all\_\_. + +#### Undefined Loop Variable {#PYLINT_ULV} +Used when an loop variable (i.e. defined by a for loop or a list comprehension or a generator expression) is used outside the loop. + +#### Undefined Variable {#PYLINT_UV} +Used when an undefined variable is accessed. + +#### Unpacking Non Sequence {#PYLINT_UNS} +Used when something which is not a sequence is used in an unpack assignment. + +#### Unused Argument {#PYLINT_UA} +Used when a function or method argument is not used. + +#### Unused Import {#PYLINT_UnI} +Used when an imported module or variable is not used. + +#### Unused Variable {#PYLINT_UnV} +Used when a variable is defined but not used. + +#### Unused Wildcard Import {#PYLINT_UWI} +Used when an imported module or variable is not used from a `'from X import *'` style import. + +#### Used Before Assignment {#PYLINT_UBA} +Used when a local variable is accessed before it's assignment. diff --git a/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md b/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md new file mode 100644 index 0000000..3be4d4a --- /dev/null +++ b/OpenStaticAnalyzer/python/doc/usersguide/md/SourceCodeMetricsRef.md @@ -0,0 +1,357 @@ +## Reference of source code metrics + +Source code metrics are used to quantify different source code characteristics. OpenStaticAnalyzer computes source code metrics for the following source code element kinds: components (e.g. modules), source files, packages, class types, methods and functions. + +The calculated metrics are grouped into 6 categories, which are the following: + +- **Cohesion metrics:** measure to what extent the source code elements are coherent in the system. + +- **Complexity metrics:** measure the complexity of source code elements (typically algorithms). + +- **Coupling metrics:** measure the amount of interdependencies of source code elements. + +- **Documentation metrics:** measure the amount of comments and documentation of source code elements in the system. + +- **Inheritance metrics:** measure the different aspects of the inheritance hierarchy of the system. + +- **Size metrics:** measure the basic properties of the analyzed system in terms of different cardinalities (e.g. number of code lines, number of classes or methods). + +In the case of the documentation metrics all the comments found immediately before a source code element are considered as its documentation, while the comments contained inside the source code element are considered as its comments. + +The following table summarizes the metrics, their abbreviations and their correspondence to different source code element kinds: + + Category Metric name Abbrev. Method, Function Class Module Package File Comp. + ---------------------- ---------------------------------------- -------- ------------------ ------- -------- --------- ------ ------- + Cohesion metrics Lack of Cohesion in Methods 5 LCOM5 X + Complexity metrics McCabe's Cyclomatic Complexity McCC X X + Nesting Level NL X X + Nesting Level Else-If NLE X X + Weighted Methods per Class WMC X + Coupling metrics Coupling Between Object classes CBO X + Coupling Between Object classes Inverse CBOI X + Number of Incoming Invocations NII X X + Number of Outgoing Invocations NOI X X + Response set For Class RFC X + Documentation metrics Comment Density CD X X X X + Comment Lines of Code CLOC X X X X X + Documentation Lines of Code DLOC X X + Total Comment Density TCD X X X X X + Total Comment Lines of Code TCLOC X X X X X + Inheritance metrics Depth of Inheritance Tree DIT X + Number of Ancestors NOA X + Number of Children NOC X + Number of Descendants NOD X + Number of Parents NOP X + Size metrics Lines of Code LOC X X X X X + Logical Lines of Code LLOC X X X X X + Number of Attributes NA X X X + Number of Classes NCL X X + Number of Local Attributes NLA X + Number of Local Methods NLM X + Number of Methods NM X X X + Number of Packages NPKG X + Number of Parameters NUMPAR X + Number of Statements NOS X X X + Total Lines of Code TLOC X X X X X + Total Logical Lines of Code TLLOC X X X X X + Total Number of Attributes TNA X X X X + Total Number of Classes TNCL X X X + Total Number of Directories TNDI X X + Total Number of Files TNFI X X + Total Number of Local Attributes TNLA X + Total Number of Local Methods TNLM X + Total Number of Methods TNM X X X X + Total Number of Packages TNPKG X X + Total Number of Statements TNOS X X X X X + +### Cohesion metrics + +#### Lack of Cohesion in Methods 5 (LCOM5) {#LCOM5} + +**Class:** number of functionalities of the class. One of the basic principles of object-oriented programming is encapsulation, meaning that attributes belonging together and the operations that use them should be organized into one class, and one class shall implement only one functionality, i.e. its attributes and methods should be coherent. This metric measures the lack of cohesion and computes into how many coherent classes the class could be split. It is calculated by taking a non-directed graph, where the nodes are the implemented local methods of the class and there is an edge between the two nodes if and only if a common (local or inherited) attribute or abstract method is used or a method invokes another. The value of the metric is the number of connected components in the graph not counting those, which contain only constructors. + +### Complexity metrics + +#### McCabe's Cyclomatic Complexity (McCC) {#McCC} + +**Method / Function:** complexity of the method/function expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally. + +**File:** complexity of the file expressed as the number of independent control flow paths in it. It represents a lower bound for the number of possible execution paths in the source code and at the same time it is an upper bound for the minimum number of test cases needed for achieving full branch test coverage. The value of the metric is calculated as the number of the following instructions plus 1: if, for, while, except and conditional expression. Moreover, logical “and” and logical “or” expressions also add 1 to the value because their short-circuit evaluation can cause branching depending on the first operand. The following instructions are not included: else, try, finally. + +#### Nesting Level (NL) {#NL} + +**Method / Function:** complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. The following instructions are taken into account: if, else-if, else, for, while, with, try, except, finally. + +**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes. It is calculated as the maximum nesting level (NL) of its local methods. + +#### Nesting Level Else-If (NLE) {#NLE} + +**Method / Function:** complexity of the method/function expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. The following instructions are taken into account: if, else, for, while, with, try, except, finally. The following instructions do not increase the value by themselves; however, if additional embeddedness can be found in their blocks, they are considered: else-if (i.e. in the if-else-if construct the use of else-if does not increase the value of the metric). + +**Class:** complexity of the class expressed as the depth of the maximum embeddedness of its conditional, iteration and exception handling block scopes, where in the if-else-if construct only the first if instruction is considered. It is calculated as the maximum nesting level (NLE) of its local methods. + +#### Weighted Methods per Class (WMC) {#WMC} + +**Class:** complexity of the class expressed as the number of independent control flow paths in it. It is calculated as the sum of the McCabe's Cyclomatic Complexity (McCC) values of its local methods. + +### Coupling metrics + +#### Coupling Between Object classes (CBO) {#CBO} + +**Class:** number of directly used other classes (e.g. by inheritance, function call, type reference, attribute reference). Classes using many other classes highly depend on their environment, so it is difficult to test or reuse them; furthermore, they are very sensitive to the changes in the system. + +#### Coupling Between Object classes Inverse (CBOI) {#CBOI} + +**Class:** number of other classes, which directly use the class. Classes which are used by many other classes have a high impact on the behavior of the system, and should be modified very carefully and tested intensively. + +#### Number of Incoming Invocations (NII) {#NII} + +**Method / Function:** number of other methods/functions and attribute initializations which directly call the method/function. If the method/function is invoked several times from the same method/function or attribute initialization, it is counted only once. + +**Class:** number of other methods and attribute initializations which directly call the local methods of the class. If a method is invoked several times from the same method or attribute initialization, it is counted only once. + +#### Number of Outgoing Invocations (NOI) {#NOI} + +**Method / Function:** number of directly called methods/functions. If a method/function is invoked several times, it is counted only once. + +**Class:** number of directly called methods of other classes, including method invocations from attribute initializations. If a method is invoked several times, it is counted only once. + +#### Response set For Class (RFC) {#RFC} + +**Class:** number of local (i.e. not inherited) methods in the class (NLM) plus the number of directly invoked other methods by its methods or attribute initializations (NOI). + +### Documentation metrics + +#### Comment Density (CD) {#CD} + +**Method/Function:** ratio of the comment lines of the method/function (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). + +**Class:** ratio of the comment lines of the class (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). + +**Module:** ratio of the comment lines of the module (CLOC) to the sum of its comment (CLOC) and logical lines of code (LLOC). + +#### Comment Lines of Code (CLOC) {#CLOC} + +**Method/Function:** number of comment and documentation code lines of the method/function; however, its local classes are not included. + +**Class:** number of comment and documentation code lines of the class, including its local methods and attributes; however, its nested and local classes are not included. + +**Module:** number of comment and documentation code lines of the module. + +**File:** number of comment and documentation code lines in the file. + +#### Documentation Lines of Code (DLOC) {#DLOC} + +**Method/Function:** number of documentation code lines of the method/function. + +**Class:** number of documentation code lines of the class, including its local methods and attributes; however, its nested and local classes are not included. + +**Module:** number of documentation code lines of the modul. + +#### Total Comment Density (TCD) {#TCD} + +**Method/Function:** ratio of the total comment lines of the method/function (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). + +**Class:** ratio of the total comment lines of the class (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). + +**Module:** ratio of the total comment lines of the module (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). + +**Package:** ratio of the total comment lines of the package (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). + +**Component:** ratio of the total comment lines of the component (TCLOC) to the sum of its total comment (TCLOC) and total logical lines of code (TLLOC). + +#### Total Comment Lines of Code (TCLOC) {#TCLOC} + +**Method/Function:** number of comment and documentation code lines of the method/function, including its local classes. + +**Class:** number of comment and documentation code lines of the class, including its local methods and attributes, as well as its nested and local classes. + +**Module:** number of comment and documentation code lines of the module. + +**Package:** number of comment and documentation code lines of the package, including its subpackages. + +**Component:** number of comment and documentation code lines of the component, including its subcomponents. + +### Inheritance metrics + +#### Depth of Inheritance Tree (DIT) {#DIT} + +**Class:** length of the path that leads from the class to its farthest ancestor in the inheritance tree. + +#### Number of Ancestors (NOA) {#NOA} + +**Class:** number of classes from which the class is directly or indirectly inherited. + +#### Number of Children (NOC) {#NOC} + +**Class:** number of classes which are directly derived from the class. + +#### Number of Descendants (NOD) {#NOD} + +**Class:** number of classes, which are directly or indirectly derived from the class. + +#### Number of Parents (NOP) {#NOP} + +**Class:** number of classes from which the class is directly inherited. + +### Size metrics + +#### Lines of Code (LOC) {#LOC} + +**Method / Function:** number of code lines of the method/function, including empty and comment lines; however, its nested functions are not included. + +**Class:** number of code lines of the class, including empty and comment lines, as well as its local methods; however, its nested and local classes are not included. + +**Module:** number of code lines of the module, including empty and comment lines. + +**Package:** number of code lines of the package, including empty and comment lines; however, its subpackages are not included. + +**File:** number of code lines in the file, including empty and comment lines. + +#### Logical Lines of Code (LLOC) {#LLOC} + +**Method / Function:** number of non-empty and non-comment code lines of the method/function; however, its nested functions are not included. + +**Class:** number of non-empty and non-comment code lines of the class, including the non-empty and non-comment lines of its local methods; however, its nested and local classes are not included. + +**Module:** number of non-empty and non-comment code lines of the module. + +**Package:** number of non-empty and non-comment code lines of the package; however, its subpackages are not included. + +**File:** number of non-empty and non-comment code lines in the file. + +#### Number of Attributes (NA) {#NA} + +**Class:** number of attributes in the class, including the inherited ones; however, the attributes of its nested and local classes are not included. + +**Module:** number of attributes in the module. + +**Package:** number of attributes in the package; however, attributes of its subpackages are not included. + +#### Number of Classes (NCL) {#NCL} + +**Module:** number of classes in the module. + +**Package:** number of classes in the package; however, the classes of its subpackages are not included. + +#### Number of Local Attributes (NLA) {#NLA} + +**Class:** number of local (i.e. not inherited) attributes in the class; however, the attributes of nested and local classes are not included. + +#### Number of Local Methods (NLM) {#NLM} + +**Class:** number of local (i.e. not inherited) methods in the class; however, the methods of nested and local classes are not included. + +#### Number of Methods (NM) {#NM} + +**Class:** number of methods/functions in the class, including the inherited ones; however, the methods of its nested and local classes are not included. Methods that override abstract methods are not counted. + +**Module:** number of methods in the module. + +**Package:** number of methods in the package; however, methods of its subpackages are not included. + +#### Number of Packages (NPKG) {#NPKG} + +**Package:** number of directly contained subpackages of the package. + +#### Number of Parameters (NUMPAR) {#NUMPAR} + +**Method / Function:** number of the parameters of the method/function. The varargs and kwargs parameters counts as one. + +#### Number of Statements (NOS) {#NOS} + +**Method / Function:** number of statements in the method/function; however, the statements of its nested functions are not included. + +**Class:** number of statements in the class; however, the statements of its nested and local classes are not included. + +**File:** number of statements in the file. + +#### Total Lines of Code (TLOC) {#TLOC} + +**Method / Function:** number of code lines of the method/function, including empty and comment lines, as well as its nested functions. + +**Class:** number of code lines of the class, including empty and comment lines, as well as its nested and local classes. + +**Module:** number of code lines of the module, including empty and comment lines. + +**Package:** number of code lines of the package, including empty and comment lines, as well as its subpackages. + +**Component:** number of code lines of the component, including empty and comment lines, as well as its subcomponents. + +#### Total Logical Lines of Code (TLLOC) {#TLLOC} + +**Method / Function:** number of non-empty and non-comment code lines of the method/function, including the non-empty and non-comment lines of its nested functions. + +**Class:** number of non-empty and non-comment code lines of the class, including the non-empty and non-comment code lines of its nested and local classes. + +**Module:** number of non-empty and non-comment code lines of the module. + +**Package:** number of non-empty and non-comment code lines of the package, including its subpackages. + +**Component:** number of non-empty and non-comment code lines of the component, including its subcomponents. + +#### Total Number of Attributes (TNA) {#TNA} + +**Class:** number of attributes in the class, including the inherited ones, as well as the inherited and local attributes of its nested and local classes. + +**Module:** number of attributes in the module. + +**Package:** number of attributes in the package, including the attributes of its subpackages. + +**Component:** number of attributes in the component, including the attributes of its subcomponents. + +#### Total Number of Classes (TNCL) {#TNCL} + +**Module:** number of classes in the module. + +**Package:** number of classes in the package, including the classes of its subpackages. + +**Component:** number of classes in the component, including the classes of its subcomponents. + +#### Total Number of Directories[^3] (TNDI) {#TNDI} + +**Package:** number of directories that belong to the package, including the directories of its subpackages. + +**Component:** number of directories that belong to the component, including its subcomponents. + +#### Total Number of Files (TNFI) {#TNFI} + +**Package:** number of files that belong to the package, including the files of its subpackages. + +**Component:** number of files that belong to the component, including its subcomponents. + +#### Total Number of Local Attributes (TNLA) {#TNLA} + +**Class:** number of local (i.e. not inherited) attributes in the class, including the attributes of its nested and local classes. + +#### Total Number of Local Methods (TNLM) {#TNLM} + +**Class:** number of local (i.e. not inherited) methods in the class, including the local methods of its nested and local classes. + +#### Total Number of Methods (TNM) {#TNM} + +**Class:** number of methods/functions in the class, including the inherited ones, as well as the inherited and local methods of its nested and local classes. Methods that override abstract methods are not counted. + +**Package:** number of methods in the module. + +**Package:** number of methods in the package, including the methods of its subpackages. + +**Component:** number of methods in the component, including the methods of its subcomponents. + +#### Total Number of Packages (TNPKG) {#TNPKG} + +**Package:** number of subpackages in the package, including all directly or indirectly contained subpackages. + +**Component:** number of packages and subpackages that belong to the component, including its subcomponents. + +#### Total Number of Statements (TNOS) {#TNOS} + +**Method / Function:** number of statements in the method/function, including the statements of its nested functions. + +**Class**: number of statements in the class, including the statements of its nested and local classes. + +**Module:** number of statements in the module. + +**Package:** number of statements in the package, including the statements of its subpackages. + +**Component:** number of statements in the component, including the statements of its subcomponents. diff --git a/README.md b/README.md index 49feef1..0f4fffc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![](OpenStaticAnalyzer/doc/logo/OSA_small.png) # OpenStaticAnalyzer™ -Copyright (c) 2004-2017 Department of Software Engineering, University of Szeged, Hungary. +Copyright (c) 2004-2018 Department of Software Engineering, University of Szeged, Hungary. ## About @@ -20,16 +20,18 @@ The most important product characteristics of OpenStaticAnalyzer are the followi - Metric threshold violations (MetricHunter module) - Re-prioritized and carefully selected [PMD] 5.2.3 coding rule violations - [FindBugs] 3.0.0 coding rule violations + - [Pylint] 1.8.2 coding rule violations - Clone detection (copy-pasted source code fragments) extended with clone tracking and "clone smells" - Syntax-based, so-called Type-2 clones -- Metrics calculation at component, file, package, class, and method levels: +- Metrics calculation at component, file, package, class, method, and function levels: - Source code metrics - Clone metrics - Coding rule violation metrics -- Supported languages: Java (C/C++, C#, Python will be available in the near future). +- Supported languages: Java, Python (C/C++, C# will be available in the near future). [PMD]:http://pmd.sourceforge.net/ [FindBugs]:http://findbugs.sourceforge.net +[Pylint]:http://www.pylint.org/ By continuous static analysis, the software developers can: - reduce the software erosion rate and this way decrease development costs; @@ -37,7 +39,7 @@ By continuous static analysis, the software developers can: - the number of errors in delivered software can be reduced, so the operational risks can be decreased, increasing the company's reputation. ## License -OpenStaticAnalyzer 1.0 is licensed under the [European Union Public Licence](https://joinup.ec.europa.eu/software/page/eupl) (EUPL) v1.2. +OpenStaticAnalyzer 2.0 is licensed under the [European Union Public Licence](https://joinup.ec.europa.eu/software/page/eupl) (EUPL) v1.2. OpenStaticAnalyzer is free software, distributed in the hope that it will be useful, but on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE file for more details. @@ -45,7 +47,9 @@ OpenStaticAnalyzer is free software, distributed in the hope that it will be use ### User's Guide -[User's guide](OpenStaticAnalyzer/java/doc/usersguide/md/Main.md) +[Java](OpenStaticAnalyzer/java/doc/usersguide/md/Main.md) + +[Python](OpenStaticAnalyzer/python/doc/usersguide/md/Main.md) ### How to compile @@ -60,7 +64,8 @@ In order to build the OpenStaticAnalyzer software package the following tools ar - Gradle 1.6 - Apache Maven 3.2.5 - Pandoc 1.16 -- Subversion +- Python 2.7 or 3.x +- Pylint 1.8.2 Some of the 3rd party libraries are used as a submodule so either `--recursive` parameter has to be used with the `git clone` command, or they have to be initialized immediately after the cloning with the `git submodule update --init --recursive` command. OpenStaticAnalyzer uses CMake for generating the platform dependent build files. After cloning the source code into a `OpenStaticAnalyzer` directory and creating a `Build` directory next to it, it can be built by executing the following commands in the `Build` directory: diff --git a/cl/DuplicatedCodeFinder/CMakeLists.txt b/cl/DuplicatedCodeFinder/CMakeLists.txt index 2c26cf3..e7f7e1f 100644 --- a/cl/DuplicatedCodeFinder/CMakeLists.txt +++ b/cl/DuplicatedCodeFinder/CMakeLists.txt @@ -12,6 +12,7 @@ set (SOURCES src/JNodeEmbeddednessVisitor.cpp src/LanguageFactory.cpp src/main.cpp + src/PNodeEmbeddednessVisitor.cpp src/RepeatingLinesFilter.cpp src/StatementFilter.cpp @@ -20,22 +21,24 @@ set (SOURCES inc/CloneLengthFilter.h inc/CloneOccuranceFilter.h inc/ClonePositioned.h - inc/CloneVisitorBase.h inc/common.h inc/Config.h - inc/CoverageVisitorBase.h inc/dcm.h - inc/DistanceVisitor.h inc/Interval.h - inc/JCoverageVisitor.h inc/LanguageFactory.h inc/messages.h - inc/NamedVisitor.h inc/RepeatingLinesFilter.h inc/StatementFilter.h inc/types.h + inc/Visitors/CloneVisitorBase.h + inc/Visitors/CoverageVisitorBase.h + inc/Visitors/DistanceVisitor.h + inc/Visitors/JCoverageVisitor.h inc/Visitors/JNodeEmbeddednessVisitor.h + inc/Visitors/NamedVisitor.h inc/Visitors/NodeEmbeddednessVisitorBase.h + inc/Visitors/PCoverageVisitor.h + inc/Visitors/PNodeEmbeddednessVisitor.h ) function (add_language_config LANG) @@ -51,5 +54,6 @@ function (add_language_config LANG) endfunction() add_language_config(java) +add_language_config(python) diff --git a/cl/DuplicatedCodeFinder/DCF.rul b/cl/DuplicatedCodeFinder/DCF.rul index e3d09dd..a78acf4 100644 --- a/cl/DuplicatedCodeFinder/DCF.rul +++ b/cl/DuplicatedCodeFinder/DCF.rul @@ -26,12 +26,8 @@ - - - - @@ -55,34 +51,6 @@ - - true - - false - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - - - - - CloneClass - CloneInstance - - - - true - - false - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - - - - - CloneClass - CloneInstance - - true @@ -97,20 +65,6 @@ CloneInstance - - true - - false - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - - - - - CloneClass - CloneInstance - - true @@ -125,20 +79,6 @@ CloneInstance - - true - - false - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - <b>Clone class/clone instance:</b> number of previously analyzed revisions in which the clone class/clone instance was present + 1. - - - - - CloneClass - CloneInstance - - @@ -160,43 +100,6 @@ - - true - - false - <b>Method/class/package:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - <b>Method/class/package:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - - - - - Component - Structure - Union - Enum - Function - - - - true - - false - <b>Method/Function/Union/Enum/class/Structure/Namespace:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - <b>Method/Function/Union/Enum/class/Structure/Namespace:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - - - - - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - true @@ -216,23 +119,6 @@ Package - - true - - false - <b>Subroutine/procedure/program/system:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - <b>Subroutine/procedure/program/system:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - - - - - Subroutine - System - Program - Procedure - Component - - true @@ -251,25 +137,6 @@ Class - - true - - false - <b>Method/Interface/Enum/class/Structure/Namespace:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - <b>Method/Interface/Enum/class/Structure/Namespace:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of the number of syntactic entities (statements, expressions, etc.).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of the number of syntactic entities (statements, expressions, etc.). - - - - - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -291,37 +158,6 @@ - - true - - false - <b>Method:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - <b>Method:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - - - - - - - true - - false - <b>Method/class/package:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - <b>Method/class/package:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - - - - - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - true @@ -341,23 +177,6 @@ Package - - true - - false - <b>Subroutine/procedure/program/system:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - <b>Subroutine/procedure/program/system:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - - - - - Subroutine - System - Program - Procedure - Component - - true @@ -376,25 +195,6 @@ Class - - true - - false - <b>Method/class/structure/interface/namespace:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - <b>Method/class/structure/interface/namespace:</b> number of clone classes having at least one clone instance in the source code element.<br><b>Component:</b> number of clone classes having at least one clone instance in the component. - - - - - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -416,66 +216,6 @@ - - true - - false - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Function/method/class/module/package:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Function/method/class/module/package:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - - - - - CloneClass - CloneInstance - Component - Structure - Union - Enum - Function - - - - true - - false - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Function/method/class/module/package:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Function/method/class/module/package:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - - - - - CloneClass - CloneInstance - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - - - true - - false - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Subroutine/procedure/program/system:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Subroutine/procedure/program/system:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - - - - - CloneClass - CloneInstance - Subroutine - System - Program - Procedure - Component - - true @@ -517,27 +257,6 @@ Package - - true - - false - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Method/class/interface/namespace/structure:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - <b>Clone instance:</b> the McCabe complexity of the code fragment corresponding to the clone instance.<br><b>Clone class:</b> sum of CCO of clone instances in the clone class.<br><b>Method/class/interface/namespace/structure:</b> sum of CCO of clone instances in the source code element.<br><b>Component:</b> sum of CCO of clone instances in the component. - - - - - CloneClass - CloneInstance - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -559,7 +278,7 @@ - + true false @@ -573,7 +292,7 @@ CloneInstance - + true false @@ -587,170 +306,58 @@ CloneInstance - + + + true + false + true + Clone false - <b>Clone instance:</b> sum of incoming and outgoing references (subroutine calls, procedure calls, variable references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. - <b>Clone instance:</b> sum of incoming and outgoing references (subroutine calls, procedure calls, variable references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. + Clone Elimination Effort + + + - - - CloneClass - CloneInstance - + + 0 + 0 + + - + true false - <b>Clone instance:</b> sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. - <b>Clone instance:</b> sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. + <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. + <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. CloneClass - CloneInstance + Component - + true false - <b>Clone instance:</b> sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. - <b>Clone instance:</b> sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. + <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. + <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. CloneClass - CloneInstance + Component - - true - - false - <b>Clone instance:</b> sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. - <b>Clone instance:</b> sum of incoming and outgoing references (function calls, variable references, type references; different references to the same entity are counted only once) in the code fragment corresponding to the clone instance, weighted with the number of directory changes between the referenced code fragments.<br><b>Clone class:</b> sum of CE of the clone instances of the clone class + 1. - - - - - CloneClass - CloneInstance - - - - - - true - false - true - Clone - - false - Clone Elimination Effort - - - - - - - 0 - 0 - - - - - true - - false - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - <b>Clone class:</b> index of the effort required to eliminate the clone class. It is computed as the product of CI, CE, and NCR.<br><b>Component:</b> index of the effort required to eliminate all clones from the component. It is computed as the sum of CEE of the clone classes in the component. - - - - - CloneClass - Component - - - - - + + + true false true @@ -769,48 +376,6 @@ - - true - - false - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - - - - - CloneClass - Component - - true @@ -839,20 +404,6 @@ Component - - true - - false - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - <b>Clone class:</b> index of the gain resulting from eliminating the clone class. It is computed as the ratio of CR to CEE.<br><b>Component:</b> index of the gain resulting from eliminating all clones from the component. It is computed as the logistic function of the ratio of CR to CEE. - - - - - CloneClass - Component - - @@ -874,62 +425,6 @@ - - true - - false - <b>Structure/Union/Enum/Function:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - <b>Structure/Union/Enum/Function:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - - - - - CloneClass - Component - Structure - Union - Enum - Function - - - - true - - <b>Method/class/Namespace:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - <b>Method/class/package:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - - - - - CloneClass - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - - - true - - false - <b>Subroutine/procedure/program/system:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - <b>Subroutine/procedure/program/system:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - - - - - Subroutine - System - Program - Procedure - CloneClass - Component - - true @@ -969,25 +464,6 @@ Package - - true - - <b>Method/class/Namespace:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - <b>Method/class/Namespace:</b> number of clone instances in the source code element.<br><b>Component:</b> number of clone instances in the component.<br><b>Clone class:</b> number of clone instances in the clone class. - - - - - CloneClass - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -1009,60 +485,6 @@ - - true - - false - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - - - - - Component - Structure - Union - Enum - Function - - - - true - - false - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - - - - - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - - - true - - false - <b>Subroutine/procedure/program/system:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - <b>Subroutine/procedure/program/system:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - - - - - Subroutine - System - Program - Procedure - Component - - true @@ -1100,25 +522,6 @@ Package - - true - - false - <b>Method/class/interface/namespace:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - <b>Method/class/interface/namespace:</b> ratio of code covered by code duplications in the source code element to the size of the source code element, expressed in terms of lines of code.<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of lines of code. - - - - - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -1140,60 +543,6 @@ - - true - - false - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - - - - - Component - Structure - Union - Enum - Function - - - - true - - false - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - <b>Function/method/class/module/package:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - - - - - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - - - true - - false - <b>Subroutine/procedure/program/system:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - <b>Subroutine/procedure/program/system:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - - - - - Subroutine - System - Program - Procedure - Component - - true @@ -1231,25 +580,6 @@ Package - - true - - false - <b>Method/class/module/namespace:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - <b>Method/class/module/namespace:</b> ratio of code covered by code duplications in the source code element to the size of source code element, expressed in terms of logical lines of code (non-empty, non-comment lines).<br><b>Component:</b> ratio of code covered by code duplications in the component to the size of the component, expressed in terms of logical lines of code (non-empty, non-comment lines). - - - - - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -1274,34 +604,6 @@ CloneInstance - - true - - false - <b>Clone instance:</b> length of the clone instance expressed in terms of lines of code.<br><b>Clone class:</b> average of CLLOC of clone instances belonging to the clone class. - <b>Clone instance:</b> length of the clone instance expressed in terms of lines of code.<br><b>Clone class:</b> average of CLLOC of clone instances belonging to the clone class. - - - - - CloneClass - CloneInstance - - - - true - - false - <b>Clone instance:</b> length of the clone instance expressed in terms of lines of code.<br><b>Clone class:</b> average of CLLOC of clone instances belonging to the clone class. - <b>Clone instance:</b> length of the clone instance expressed in terms of lines of code.<br><b>Clone class:</b> average of CLLOC of clone instances belonging to the clone class. - - - - - CloneClass - CloneInstance - - true @@ -1327,130 +629,11 @@ CloneClass - CloneInstance - - - - true - - false - <b>Clone instance:</b> length of the clone instance expressed in terms of lines of code.<br><b>Clone class:</b> average of CLLOC of clone instances belonging to the clone class. - <b>Clone instance:</b> length of the clone instance expressed in terms of lines of code.<br><b>Clone class:</b> average of CLLOC of clone instances belonging to the clone class. - - - - - CloneClass - CloneInstance - - - - - - true - false - true - Clone - - false - Clone Risk - - - - - - - 0 - 0 - - - - - true - - false - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - - - - - CloneClass - Component + CloneInstance - + true false @@ -1458,7 +641,7 @@ Clone false - Clone Variability + Clone Risk @@ -1470,47 +653,54 @@ - + true false - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. + <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. + <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. - + CloneClass - CloneInstance + Component - + true false - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. + <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. + <b>Clone class:</b> risk index of the existence of the clone class. It is computed as the product of CLLOC, CI, CCO, NCR, and CV.<br><b>Component:</b> relative risk index of the existence of code duplications in the component. It is computed as the sum of CR of the clone classes in the component, divided by the total logical lines of code (non-empty, non-comment lines) of the component. It expresses the risk index projected to a non-empty, non-comment line of code in the component. CloneClass - CloneInstance + Component - + + + true + false + true + Clone false - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. + Clone Variability + + + - - - CloneClass - CloneInstance - + + 0 + 0 + + true @@ -1540,20 +730,6 @@ CloneInstance - - true - - false - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. - <b>Clone instance:</b> instability of the clone instance since it appeared. It is computed as the ratio of the number of previously analyzed revisions when the instance had been changed to its age (CA).<br><b>Clone class:</b> instability of the clone class since it appeared. It is computed as the ratio of the number of previously analyzed revisions when its contained instances were moved, deleted, or added, to its age (CA), plus the average CV of its clone instances. - - - - - CloneClass - CloneInstance - - @@ -1567,39 +743,6 @@ - - false - - false - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - - - - - - - false - - false - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - - - - - - - false - - false - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - - - - - false @@ -1622,17 +765,6 @@ - - false - - false - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - <b>Clone metrics:</b> measure the amount of copy-paste programming in the source code. - - - - - @@ -1654,60 +786,6 @@ - - true - - false - <b>Function/method/class/module/package:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - <b>Function/method/class/module/package:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - - - - - Component - Structure - Union - Enum - Function - - - - true - - false - <b>Function/method/class/module/package:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - <b>Function/method/class/module/package:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - - - - - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - - - true - - false - <b>Subroutine/procedure/program/system:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - <b>Subroutine/procedure/program/system:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - - - - - Subroutine - System - Program - Procedure - Component - - true @@ -1745,25 +823,6 @@ Package - - true - - false - <b>Method/class/interface/namespace:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - <b>Method/class/interface/namespace:</b> number of code lines covered by code duplications in the source code element.<br><b>Component:</b> number of code lines covered by code duplications in the component. - - - - - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -1785,60 +844,6 @@ - - true - - false - <b>Function/method/class/module/package:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - <b>Function/method/class/module/package:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - - - - - Component - Structure - Union - Enum - Function - - - - true - - false - <b>Function/method/class/module/package:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - <b>Function/method/class/module/package:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - - - - - Component - Namespace - Class - Structure - Union - Enum - Function - Method - - - - true - - false - <b>Subroutine/procedure/program/system:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - <b>Subroutine/procedure/program/system:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - - - - - Subroutine - System - Program - Procedure - Component - - true @@ -1876,25 +881,6 @@ Package - - true - - false - <b>Method/class/interface/namespace:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - <b>Method/class/interface/namespace:</b> number of logical code lines (non-empty, non-comment lines) covered by code duplications in the source code element.<br><b>Component:</b> The number of logical code lines (non-empty, non-comment lines) covered by code duplications in the component. - - - - - Component - Namespace - Class - Structure - Interface - Enum - Method - - @@ -1916,48 +902,6 @@ - - true - - false - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - - - - - CloneClass - Component - - - - true - - false - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - - - - - CloneClass - Component - - true @@ -1986,19 +930,5 @@ Component - - true - - false - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - <b>Clone class:</b> normalized average distance among clone instances belonging to the clone class, expressed in terms of number of directory changes.<br><b>Component:</b> average of NCR of the clone classes in the component. - - - - - CloneClass - Component - - diff --git a/cl/DuplicatedCodeFinder/inc/CloneVisitorBase.h b/cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h similarity index 99% rename from cl/DuplicatedCodeFinder/inc/CloneVisitorBase.h rename to cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h index fb0fd75..e198283 100644 --- a/cl/DuplicatedCodeFinder/inc/CloneVisitorBase.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/CloneVisitorBase.h @@ -21,7 +21,7 @@ #ifndef CLONE_VISITOR_BASE_H #define CLONE_VISITOR_BASE_H -#include "common.h" +#include "../common.h" #include #include #include diff --git a/cl/DuplicatedCodeFinder/inc/CoverageVisitorBase.h b/cl/DuplicatedCodeFinder/inc/Visitors/CoverageVisitorBase.h similarity index 98% rename from cl/DuplicatedCodeFinder/inc/CoverageVisitorBase.h rename to cl/DuplicatedCodeFinder/inc/Visitors/CoverageVisitorBase.h index 31ace46..eadf5d7 100644 --- a/cl/DuplicatedCodeFinder/inc/CoverageVisitorBase.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/CoverageVisitorBase.h @@ -21,8 +21,8 @@ #ifndef __COVERAGE_VISITOR_BASE_H #define __COVERAGE_VISITOR_BASE_H -#include "common.h" -#include "messages.h" +#include "../common.h" +#include "../messages.h" struct UniqueNameWithPath { std::string uniqueName; diff --git a/cl/DuplicatedCodeFinder/inc/DistanceVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/DistanceVisitor.h similarity index 100% rename from cl/DuplicatedCodeFinder/inc/DistanceVisitor.h rename to cl/DuplicatedCodeFinder/inc/Visitors/DistanceVisitor.h diff --git a/cl/DuplicatedCodeFinder/inc/JCoverageVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/JCoverageVisitor.h similarity index 96% rename from cl/DuplicatedCodeFinder/inc/JCoverageVisitor.h rename to cl/DuplicatedCodeFinder/inc/Visitors/JCoverageVisitor.h index d51f210..818fa94 100644 --- a/cl/DuplicatedCodeFinder/inc/JCoverageVisitor.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/JCoverageVisitor.h @@ -20,7 +20,8 @@ #ifndef _J_COVERAGE_VISITOR_H #define _J_COVERAGE_VISITOR_H -#include "common.h" +#ifdef SCHEMA_JAVA +#include "../common.h" class JCoverageVisitor : public CoverageVisitorBase, public columbus::java::asg::VisitorAbstractNodes { @@ -35,3 +36,4 @@ class JCoverageVisitor : public CoverageVisitorBase, public columbus::java::asg: #define COVERAGE_VISITOR JCoverageVisitor #endif +#endif diff --git a/cl/DuplicatedCodeFinder/inc/Visitors/JNodeEmbeddednessVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/JNodeEmbeddednessVisitor.h index e038fe9..6800661 100644 --- a/cl/DuplicatedCodeFinder/inc/Visitors/JNodeEmbeddednessVisitor.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/JNodeEmbeddednessVisitor.h @@ -20,6 +20,7 @@ #ifndef _DCF_CPPJNODEV_H_ #define _DCF_CPPJNODEV_H_ +#ifdef SCHEMA_JAVA #include "../common.h" #include "NodeEmbeddednessVisitorBase.h" @@ -45,4 +46,5 @@ public : }; #define NODE_EMBEDDEDNESS_VISITOR JNodeEmbeddednessVisitorBase +#endif // SCHEMA_JAVA #endif // _DCF_CPPJNODEV_H_ diff --git a/cl/DuplicatedCodeFinder/inc/NamedVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/NamedVisitor.h similarity index 79% rename from cl/DuplicatedCodeFinder/inc/NamedVisitor.h rename to cl/DuplicatedCodeFinder/inc/Visitors/NamedVisitor.h index bfd06a4..58ae6fb 100644 --- a/cl/DuplicatedCodeFinder/inc/NamedVisitor.h +++ b/cl/DuplicatedCodeFinder/inc/Visitors/NamedVisitor.h @@ -27,9 +27,24 @@ class NamedVisitor : public VisitorAbstractNodes { public: NamedVisitor() : repr("") {} virtual void visit(const Base& node, bool callVirtualBase = true) { +#if defined SCHEMA_PYTHON + std::string name; + if (node.getParent() != NULL ) { + name = AlgorithmCommon::getUniqueName(node); + } + if (!name.empty()) { + repr+=std::string("(")+name; + } +#endif repr+=std::string("#")+common::toString(node.getNodeKind()); } virtual void visitEnd(const Base& node, bool callVirtualBase = true) { +#if defined SCHEMA_PYTHON + std::string name = AlgorithmCommon::getUniqueName(node); + if (!name.empty()) { + repr+=std::string(")"); + } +#endif repr+="$"; } virtual void visit(const Named& node, bool callVirtualBase = true) { diff --git a/cl/DuplicatedCodeFinder/inc/Visitors/PCoverageVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/PCoverageVisitor.h new file mode 100644 index 0000000..f35c44e --- /dev/null +++ b/cl/DuplicatedCodeFinder/inc/Visitors/PCoverageVisitor.h @@ -0,0 +1,62 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _P_COVERAGE_VISITOR_H +#define _P_COVERAGE_VISITOR_H + +#ifdef SCHEMA_PYTHON + +#include "../common.h" + + +class PCoverageVisitor : public CoverageVisitorBase, public columbus::python::asg::VisitorAbstractNodes { + + + +public: + PCoverageVisitor(){} + virtual ~PCoverageVisitor(){} + void visit(const columbus::python::asg::base::Base& n, bool b){ visitBase(n);} + + virtual bool isIncTheComplexity( int nodeKind ) { + return columbus::python::asg::Common::getIsBaseClassKind((columbus::python::asg::NodeKind)nodeKind,columbus::python::asg::ndkIfExpression) + || columbus::python::asg::Common::getIsBaseClassKind((columbus::python::asg::NodeKind)nodeKind,columbus::python::asg::ndkFor) + || columbus::python::asg::Common::getIsBaseClassKind((columbus::python::asg::NodeKind)nodeKind,columbus::python::asg::ndkIf) + || columbus::python::asg::Common::getIsBaseClassKind((columbus::python::asg::NodeKind)nodeKind,columbus::python::asg::ndkTry) + || columbus::python::asg::Common::getIsBaseClassKind((columbus::python::asg::NodeKind)nodeKind,columbus::python::asg::ndkWhile) ; + } + + virtual bool isIncTheComplexity( const columbus::python::asg::base::Base& n ) { + + int nodeKind = n.getNodeKind(); + if (columbus::python::asg::Common::getIsBaseClassKind((columbus::python::asg::NodeKind)nodeKind,columbus::python::asg::ndkBinaryLogical) ) { + const columbus::python::asg::expression::BinaryLogical& bilogic = dynamic_cast(n); + if (bilogic.getKind() == columbus::python::asg::blkOr || bilogic.getKind() == columbus::python::asg::blkAnd) { + return true; + } + } + return isIncTheComplexity(n.getNodeKind()); + } +}; + +#define COVERAGE_VISITOR PCoverageVisitor + +#endif +#endif diff --git a/cl/DuplicatedCodeFinder/inc/Visitors/PNodeEmbeddednessVisitor.h b/cl/DuplicatedCodeFinder/inc/Visitors/PNodeEmbeddednessVisitor.h new file mode 100644 index 0000000..4d6aeb7 --- /dev/null +++ b/cl/DuplicatedCodeFinder/inc/Visitors/PNodeEmbeddednessVisitor.h @@ -0,0 +1,62 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _DCF_PNODEEV_H_ +#define _DCF_PNODEEV_H_ + +#ifdef SCHEMA_PYTHON + +#include "../common.h" +#include "NodeEmbeddednessVisitorBase.h" +#include + +namespace columbus { + + class PNodeEmbeddednessVisitorBase : public NodeEmbeddednessVisitorBase { + public : + PNodeEmbeddednessVisitorBase(ConectedEdgesMap& mapTofill,const columbus::dcf::DuplicatedCodeMiner& dcf):NodeEmbeddednessVisitorBase(mapTofill,dcf) {} + virtual ~PNodeEmbeddednessVisitorBase(){} + protected: + void visit(const columbus::python::asg::statement::Parameter& n, bool b); + + void visit( const columbus::python::asg::statement::Alias& n, bool b ); + + void visit( const columbus::python::asg::expression::Identifier& n, bool b ); + void visit( const columbus::python::asg::statement::FunctionDef& n, bool b ); + + void visit( const columbus::python::asg::expression::Call& n, bool b ); + + void visit( const columbus::python::asg::statement::ClassDef& n, bool b ); + + void visit( const columbus::python::asg::expression::Expression& n, bool b ); + + void visit( const columbus::python::asg::statement::BaseSpecifier& n, bool b ); + + //Put the node to the database + void putNode(const columbus::python::asg::base::Positioned& n1 ,const columbus::python::asg::base::Positioned& n2, bool unique); + + void addObjectReferenceToNode(const columbus::python::asg::base::Positioned& n, columbus::python::asg::module::Object* obejctRefersTo ,bool asUnique ); + void addTypeReferenceToNode(const columbus::python::asg::base::Positioned& n, columbus::python::asg::type::Type* obejctRefersTo ,bool asUnique ); + }; +} +#define NODE_EMBEDDEDNESS_VISITOR PNodeEmbeddednessVisitorBase +#endif // SCHEMA_PYTHON + +#endif // _DCF_PNODEEV_H_ diff --git a/cl/DuplicatedCodeFinder/inc/common.h b/cl/DuplicatedCodeFinder/inc/common.h index b0195a3..52d0159 100644 --- a/cl/DuplicatedCodeFinder/inc/common.h +++ b/cl/DuplicatedCodeFinder/inc/common.h @@ -36,8 +36,14 @@ #include #include -#include "java/inc/java.h" -#define LANGUAGE_NAMESPACE java::asg +#ifdef SCHEMA_JAVA + #include "java/inc/java.h" + #define LANGUAGE_NAMESPACE java::asg +#elif defined SCHEMA_PYTHON + #include "python/inc/python.h" + #define LANGUAGE_NAMESPACE python::asg +#endif + #define BASE_NAMESPACE base #define TOGRAPH columbus::lim2graph #define GET_LINE_OF_POSITIONS getPosition().getLine() @@ -59,17 +65,18 @@ #include "lim/inc/lim.h" #include "Config.h" #include "ClonePositioned.h" -#include "CloneVisitorBase.h" -#include "CoverageVisitorBase.h" -#include "JCoverageVisitor.h" -#include "NamedVisitor.h" +#include "Visitors/CloneVisitorBase.h" +#include "Visitors/CoverageVisitorBase.h" +#include "Visitors/PCoverageVisitor.h" +#include "Visitors/JCoverageVisitor.h" +#include "Visitors/NamedVisitor.h" #include "Interval.h" #include "AbstractFilter.h" #include "Aligner.h" #include "CloneLengthFilter.h" #include "RepeatingLinesFilter.h" #include "CloneOccuranceFilter.h" -#include "DistanceVisitor.h" +#include "Visitors/DistanceVisitor.h" extern Config config; diff --git a/cl/DuplicatedCodeFinder/inc/dcm.h b/cl/DuplicatedCodeFinder/inc/dcm.h index c749b37..fd4f8c6 100644 --- a/cl/DuplicatedCodeFinder/inc/dcm.h +++ b/cl/DuplicatedCodeFinder/inc/dcm.h @@ -33,7 +33,13 @@ #include #include +#ifdef SCHEMA_JAVA #include "Visitors/JNodeEmbeddednessVisitor.h" +#endif + +#ifdef SCHEMA_PYTHON +#include "Visitors/PNodeEmbeddednessVisitor.h" +#endif #include "common/inc/math/common.h" #include diff --git a/cl/DuplicatedCodeFinder/inc/types.h b/cl/DuplicatedCodeFinder/inc/types.h index 8d02971..3e1459f 100644 --- a/cl/DuplicatedCodeFinder/inc/types.h +++ b/cl/DuplicatedCodeFinder/inc/types.h @@ -40,13 +40,25 @@ typedef columbus::LANGUAGE_NAMESPACE::VisitorAbstractNodes VisitorAbstractNodes; #define LIM_FILTER_FILE_EXTENSION ".flim" #define AlgorithmCommon columbus::LANGUAGE_NAMESPACE::Common -#define FILTER_FILE_EXTENSION ".fjsi" -#define FILTER_FILE_EXTENSION_W L".fjsi" -#define LANGUAGE columbus::java::JavaLanguage -#define LANGUAGE_NS columbus::java -#define getUniqueName_v1 AlgorithmCommon::getUniqueNameForBase -#define UNIQUE_NAME_FOR_MEMBER AlgorithmCommon::getUniqueNameForBase -#define NAMED_VISITOR NamedVisitor +#if defined(SCHEMA_JAVA) + #define FILTER_FILE_EXTENSION ".fjsi" + #define FILTER_FILE_EXTENSION_W L".fjsi" + #define LANGUAGE columbus::java::JavaLanguage + #define LANGUAGE_NS columbus::java + #define getUniqueName_v1 AlgorithmCommon::getUniqueNameForBase + #define UNIQUE_NAME_FOR_MEMBER AlgorithmCommon::getUniqueNameForBase + #define NAMED_VISITOR NamedVisitor + +#elif defined(SCHEMA_PYTHON) + #define FILTER_FILE_EXTENSION ".fpsi" + #define FILTER_FILE_EXTENSION_W L".fpsi" + #define LANGUAGE columbus::python::PythonLanguage + #define LANGUAGE_NS columbus::python + #define getUniqueName_v1 AlgorithmCommon::getUniqueNameForBase + #define UNIQUE_NAME_FOR_MEMBER AlgorithmCommon::getUniqueName + #define NAMED_VISITOR NamedVisitor + +#endif #endif diff --git a/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp b/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp index dced184..15271fb 100644 --- a/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp +++ b/cl/DuplicatedCodeFinder/src/CloneVisitorBase.cpp @@ -19,7 +19,7 @@ */ #include "../inc/common.h" -#include "../inc/CloneVisitorBase.h" +#include "../inc/Visitors/CloneVisitorBase.h" using namespace columbus; using namespace common; @@ -71,7 +71,11 @@ CloneVisitorBase::~CloneVisitorBase() {} bool CloneVisitorBase::isAnalizeNode(const Base& node) { if(analizeNode) { +#if defined SCHEMA_JAVA return columbus::java::asg::Common::getIsMethodDeclaration(node); +#elif defined SCHEMA_PYTHON + return columbus::python::asg::Common::getIsFunctionDef(node); +#endif } return false; } @@ -88,11 +92,15 @@ void CloneVisitorBase::addToResultSequence(int kind) { ClonePositioned* CloneVisitorBase::createClonePositioned(const Positioned* p) { ClonePositioned* px; +#ifdef SCHEMA_JAVA if (columbus::java::asg::Common::getIsPackage(*p)) { px = new ClonePositioned("unknown", 0, 0, 0, 0, p->getNodeKind(), p->getId(), currentLimNode.empty()?currentLimComponent:currentLimNode.top(),currentLimComponent); } else { px = new ClonePositioned(p->getPosition().getPath(), p->getPosition().getWideLine(), p->getPosition().getWideCol(), p->getPosition().getWideEndLine(), p->getPosition().getWideEndCol(), p->getNodeKind(), p->getId(),currentLimNode.empty()?currentLimComponent:currentLimNode.top(),currentLimComponent); } +#elif defined SCHEMA_PYTHON + px = new ClonePositioned(p->getPosition().getPath(), p->GET_LINE_OF_POSITIONS, p->GET_COLUMN_OF_POSITIONS, p->GET_END_LINE_OF_POSITIONS, p->GET_END_COLUMN_OF_POSITIONS, p->getNodeKind(), p->getId(),currentLimNode.empty()?currentLimComponent:currentLimNode.top(),currentLimComponent); +#endif return px; } @@ -163,17 +171,25 @@ void CloneVisitorBase::blockNode(const Base& b) { std::string lPath=pos.getPosition().getPath(); LowerStringOnWindows(lPath); +#if defined(SCHEMA_JAVA) unsigned line = pos.getPosition().getWideLine(); - +#elif defined(SCHEMA_PYTHON) + unsigned line = pos.getPosition().getLine(); +#endif if ((prevPath!=lPath) && fileNamesByComponent) { assignSrcFileToComponenet(lPath,currentLimComponent); } if (logicalLines) { +#if defined(SCHEMA_JAVA) logicalLines->insert(LineIdentifier(limFactory->getStringTable().set(lPath.c_str()),pos.getPosition().getLine())); logicalLines->insert(LineIdentifier(limFactory->getStringTable().set(lPath.c_str()),pos.getPosition().getEndLine())); logicalLines->insert(LineIdentifier(limFactory->getStringTable().set(lPath.c_str()),pos.getPosition().getWideLine())); logicalLines->insert(LineIdentifier(limFactory->getStringTable().set(lPath.c_str()),pos.getPosition().getWideEndLine())); +#elif defined (SCHEMA_PYTHON) + logicalLines->insert(LineIdentifier(limFactory->getStringTable().set(lPath.c_str()),pos.getPosition().getLine())); + logicalLines->insert(LineIdentifier(limFactory->getStringTable().set(lPath.c_str()),pos.getPosition().getEndLine())); +#endif } if ((prevPath!=lPath || line!=prevLine) && lPath!="") { @@ -286,8 +302,10 @@ void CloneVisitorBase::dumpFilterRange(columbus::NodeId from,columbus::NodeId to } void CloneVisitorBase::visit(const Positioned& n,bool callVirtualParent){ +#if defined (SCHEMA_JAVA) if (n.getIsCompilerGenerated()) return; +#endif visitedNodesNumber++; evoluteLimNode(n,false); @@ -328,12 +346,14 @@ void CloneVisitorBase::visit(const Positioned& n,bool callVirtualParent){ lastIsFilteredOut = false; +#if defined(SCHEMA_JAVA) if (columbus::java::asg::Common::getIsPackage(n)) { addFileSeparator(); addPattern(n); path=""; return; } +#endif if (AlgorithmCommon::getIsPositioned(n)) { const Positioned& posNodeRef = dynamic_cast(n); @@ -354,8 +374,10 @@ void CloneVisitorBase::visit(const Positioned& n,bool callVirtualParent){ } void CloneVisitorBase::visitEnd(const Positioned& n, bool callVirtualParent) { +#if defined(SCHEMA_JAVA) if (n.getIsCompilerGenerated()) return; +#endif if ((blockNodeKind == BK_asgNodeBlock) && ( n.getId() == blockedNode )) { blockedNode = 0; diff --git a/cl/DuplicatedCodeFinder/src/CoverageVisitorBase.cpp b/cl/DuplicatedCodeFinder/src/CoverageVisitorBase.cpp index 8940180..1dd73b7 100644 --- a/cl/DuplicatedCodeFinder/src/CoverageVisitorBase.cpp +++ b/cl/DuplicatedCodeFinder/src/CoverageVisitorBase.cpp @@ -19,7 +19,7 @@ */ #include "../inc/common.h" -#include "../inc/CoverageVisitorBase.h" +#include "../inc/Visitors/CoverageVisitorBase.h" CoverageVisitorBase::CoverageVisitorBase() @@ -178,6 +178,7 @@ void CoverageVisitorBase::setLimNodeId( NodeId val ) { } void CoverageVisitorBase::insertLines( std::set* lineSet, const Base& n ) const { +#ifdef SCHEMA_JAVA if (!columbus::java::asg::Common::getIsPositioned(n)) return; const columbus::java::asg::base::Positioned& p = dynamic_cast(n); @@ -187,6 +188,7 @@ void CoverageVisitorBase::insertLines( std::set* lineSet, const lineSet->insert(LineIdentifier(p.getPosition().getPathKey(),p.getPosition().getWideLine())); lineSet->insert(LineIdentifier(p.getPosition().getPathKey(),p.getPosition().getWideEndLine())); +#endif } void CoverageVisitorBase::visitStartComponent( const columbus::lim::asg::base::Component &component ) diff --git a/cl/DuplicatedCodeFinder/src/JCoverageVisitor.cpp b/cl/DuplicatedCodeFinder/src/JCoverageVisitor.cpp index f508602..2d0fa4f 100644 --- a/cl/DuplicatedCodeFinder/src/JCoverageVisitor.cpp +++ b/cl/DuplicatedCodeFinder/src/JCoverageVisitor.cpp @@ -20,6 +20,7 @@ #include "../inc/common.h" +#ifdef SCHEMA_JAVA using namespace columbus; using namespace java; using namespace asg; @@ -47,3 +48,4 @@ bool JCoverageVisitor::isIncTheComplexity( int nodeKind ) { return false; } +#endif diff --git a/cl/DuplicatedCodeFinder/src/JNodeEmbeddednessVisitor.cpp b/cl/DuplicatedCodeFinder/src/JNodeEmbeddednessVisitor.cpp index bd66d3a..536a59e 100644 --- a/cl/DuplicatedCodeFinder/src/JNodeEmbeddednessVisitor.cpp +++ b/cl/DuplicatedCodeFinder/src/JNodeEmbeddednessVisitor.cpp @@ -18,6 +18,8 @@ * limitations under the Licence. */ +#ifdef SCHEMA_JAVA + #include "../inc/common.h" #include "../inc/Visitors/JNodeEmbeddednessVisitor.h" #include "../inc/dcm.h" @@ -108,3 +110,5 @@ void JNodeEmbeddednessVisitorBase::visit( const columbus::java::asg::expr::Expre } } } + +#endif diff --git a/cl/DuplicatedCodeFinder/src/LanguageFactory.cpp b/cl/DuplicatedCodeFinder/src/LanguageFactory.cpp index 14c4073..4882336 100644 --- a/cl/DuplicatedCodeFinder/src/LanguageFactory.cpp +++ b/cl/DuplicatedCodeFinder/src/LanguageFactory.cpp @@ -163,6 +163,7 @@ namespace columbus { namespace dcf { void LanguageFactory::fillComponentList( std::list listOfInputFile ) { +#ifdef SCHEMA_JAVA for (std::list::iterator it = listOfInputFile.begin();it != listOfInputFile.end();++it) { columbus::CsiHeader header; columbus::RefDistributorStrTable stt; @@ -178,6 +179,7 @@ namespace columbus { namespace dcf { limComponentNameFileNameMap[componentID] = *it; } +#endif } }} diff --git a/cl/DuplicatedCodeFinder/src/PNodeEmbeddednessVisitor.cpp b/cl/DuplicatedCodeFinder/src/PNodeEmbeddednessVisitor.cpp new file mode 100644 index 0000000..fef3c46 --- /dev/null +++ b/cl/DuplicatedCodeFinder/src/PNodeEmbeddednessVisitor.cpp @@ -0,0 +1,166 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifdef SCHEMA_PYTHON + +#include "../inc/common.h" +#include "../inc/Visitors/PNodeEmbeddednessVisitor.h" +#include "../inc/dcm.h" + +namespace columbus { + + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::statement::Parameter& n, bool b ) { + NodeEmbeddednessVisitorBase::visit(n,b); + columbus::python::asg::module::Object* obejctRefersTo = n.getRefersTo(); + if (obejctRefersTo) { + addObjectReferenceToNode(n, obejctRefersTo,false); + } + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::statement::Alias& n, bool b ) { + NodeEmbeddednessVisitorBase::visit(n,b); + LANGUAGE_NAMESPACE::base::Base* obejctRefersTo = n.getRefersTo(); + if (obejctRefersTo) { + if ( LANGUAGE_NAMESPACE::Common::getIsObject(*obejctRefersTo)) { + addObjectReferenceToNode(n, dynamic_cast( obejctRefersTo),false); + } else if (LANGUAGE_NAMESPACE::Common::getIsPositioned(*obejctRefersTo)) { + putNode(n,*dynamic_cast( obejctRefersTo),true); + } + } + + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::expression::Identifier& n, bool b ) { + NodeEmbeddednessVisitorBase::visit(n,b); + columbus::python::asg::module::Object* obejctRefersTo = n.getRefersTo(); + if (obejctRefersTo) { + addObjectReferenceToNode(n, obejctRefersTo,false); + } + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::statement::FunctionDef& n, bool b ) + { + NodeEmbeddednessVisitorBase::visit(n,b); + columbus::python::asg::module::Object* obejctRefersTo = n.getRefersTo(); + if (obejctRefersTo) { + addObjectReferenceToNode(n, obejctRefersTo,false); + addTypeReferenceToNode(n, n.getReturnType(),true); + } + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::expression::Call& n, bool b ) + { + NodeEmbeddednessVisitorBase::visit(n,b); + if (n.getRefersTo()){ + putNode(n,*n.getRefersTo(),false); + } + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::statement::ClassDef& n, bool b ) + { + NodeEmbeddednessVisitorBase::visit(n,b); + if (n.getRefersTo()){ + addObjectReferenceToNode(n,n.getRefersTo(),false); + } + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::expression::Expression& n, bool b ) + { + NodeEmbeddednessVisitorBase::visit(n,b); + addTypeReferenceToNode(n, n.getType(),true); + } + + void PNodeEmbeddednessVisitorBase::visit( const columbus::python::asg::statement::BaseSpecifier& n, bool b ) + { + NodeEmbeddednessVisitorBase::visit(n,b); + if (n.getDerivesFrom()){ + putNode(n,*n.getDerivesFrom(),false); + } + } + + + + + void PNodeEmbeddednessVisitorBase::putNode( const columbus::python::asg::base::Positioned& n1 ,const columbus::python::asg::base::Positioned& n2, bool unique ) + { + // test the lim filter state + if (dcf.isItFilteredInLim(limComponenetId,n2)) + return; + + NodeId limNode = dcf.getLimNodeIdByNode(limComponenetId,n1); + if (limNode) { + aliasMap[limNode] = NodeGlobalId( limComponenetId,n1.getId()); + } + + if (!aliasMode) { + alias = NodeGlobalId( limComponenetId,n1.getId()); + } + + const std::string& baseNodeFile = n1.getPosition().getPath(); + const std::string& endNodeFile = n2.getPosition().getPath(); + ConectedEdgesMap::iterator itFoundAssociation = conectedEdgesMap.find(NodeGlobalId( limComponenetId,n1.getId())); + + int distance =calculateNDC(baseNodeFile,endNodeFile) ; + if (itFoundAssociation != conectedEdgesMap.end()) { + bool found = false; + if (unique) { + std::list& listRef = conectedEdgesMap[NodeGlobalId( limComponenetId,n1.getId())]; + for (std::list< NodeWithWeight >::iterator it = listRef.begin();it != listRef.end();++it ) { + if (it->nodeUniqueId == NodeGlobalId( limComponenetId,n2.getId())) { + found = true; + } + } + } + if (!found) { + conectedEdgesMap[alias].push_front( + NodeWithWeight(NodeGlobalId( limComponenetId,n2.getId()),NdcWeight(distance,!unique)) + ); + } + } else { + std::list< NodeWithWeight > newList ; + newList.push_front(NodeWithWeight(NodeGlobalId( limComponenetId,n2.getId()),NdcWeight(distance,!unique))); + conectedEdgesMap.insert(std::make_pair(alias,newList)); + } + } + + void PNodeEmbeddednessVisitorBase::addObjectReferenceToNode( const columbus::python::asg::base::Positioned& n, columbus::python::asg::module::Object* obejctRefersTo,bool asUnique ) + { + if (obejctRefersTo != NULL) { + for (LANGUAGE_NAMESPACE::ListIterator it = obejctRefersTo->getRefersToListIteratorBegin(); + it != obejctRefersTo->getRefersToListIteratorEnd();++it) { + putNode(n,*it,asUnique); + } + } + } + + void PNodeEmbeddednessVisitorBase::addTypeReferenceToNode( const columbus::python::asg::base::Positioned& n, columbus::python::asg::type::Type* obejctRefersTo ,bool asUnique ) + { + if (obejctRefersTo && LANGUAGE_NAMESPACE::Common::getIsReferenceType(*obejctRefersTo)) { + columbus::python::asg::type::ReferenceType* refType = dynamic_cast (obejctRefersTo); + if (refType->getRefersTo()) { + putNode(n,*refType->getRefersTo(),asUnique); + } + } + } + +} + +#endif diff --git a/cl/DuplicatedCodeFinder/src/StatementFilter.cpp b/cl/DuplicatedCodeFinder/src/StatementFilter.cpp index 3f5f693..9ec4540 100644 --- a/cl/DuplicatedCodeFinder/src/StatementFilter.cpp +++ b/cl/DuplicatedCodeFinder/src/StatementFilter.cpp @@ -36,8 +36,18 @@ bool StatementFilter::isFiltered( const columbus::genealogy::CloneClass& cc ) if (position == NULL) continue; +#if defined SCHEMA_JAVA if (columbus::LANGUAGE_NAMESPACE::Common::getIsBaseClassKind((columbus::LANGUAGE_NAMESPACE::NodeKind)position->getNodeKind(),columbus::LANGUAGE_NAMESPACE::ndkStatement)) return false; + +#elif defined SCHEMA_PYTHON + if (columbus::LANGUAGE_NAMESPACE::Common::getIsBaseClassKind((columbus::LANGUAGE_NAMESPACE::NodeKind)position->getNodeKind(),columbus::LANGUAGE_NAMESPACE::ndkStatement)){ + if (!columbus::LANGUAGE_NAMESPACE::Common::getIsBaseClassKind((columbus::LANGUAGE_NAMESPACE::NodeKind)position->getNodeKind(),columbus::LANGUAGE_NAMESPACE::ndkImportStatement) && + !columbus::LANGUAGE_NAMESPACE::Common::getIsBaseClassKind((columbus::LANGUAGE_NAMESPACE::NodeKind)position->getNodeKind(),columbus::LANGUAGE_NAMESPACE::ndkAlias)) + return false; + } +#endif + } } // iterating over all the clone instances in this class return true; diff --git a/cl/DuplicatedCodeFinder/src/dcm.cpp b/cl/DuplicatedCodeFinder/src/dcm.cpp index 1400a7f..14f8e2c 100644 --- a/cl/DuplicatedCodeFinder/src/dcm.cpp +++ b/cl/DuplicatedCodeFinder/src/dcm.cpp @@ -86,18 +86,30 @@ namespace columbus { } // ========================= Computing F3 Attribute ========================================== +#if defined SCHEMA_JAVA if (AlgorithmCommon::getIsNamed(ciFirstRootNode) && AlgorithmCommon::getIsMember(ciFirstRootNode)) { Named& toP=dynamic_cast(ciFirstRootNode); - +#elif defined SCHEMA_PYTHON + if (AlgorithmCommon::getIsMemberNode(ciFirstRootNode) ) { + Base& toP=dynamic_cast(ciFirstRootNode); +#endif if (ci.getF3_HeadNodeUniqueName().empty()) { ci.setF3_HeadNodeUniqueName(UNIQUE_NAME_FOR_MEMBER(toP)); common::WriteMsg::write(WriteMsg::mlDDDDebug,"the F3 is %s for %d\n",ci.getF3_HeadNodeUniqueName().c_str(),ci.getId()); } } // ============================ Computing F4 Attribute ======================================= +#if defined SCHEMA_PYTHON + Base* namedAncestor = NULL; +#else Named* namedAncestor = NULL; +#endif if (ci.getF4_AncestorUniqueName().empty()) { +#if defined SCHEMA_JAVA namedAncestor = dynamic_cast(AlgorithmCommon::getScopeOrMethodDeclarationParent(ciFirstRootNode)); +#elif defined SCHEMA_PYTHON + namedAncestor = dynamic_cast(AlgorithmCommon::getScopeParent(ciFirstRootNode)); +#endif if (namedAncestor != NULL) { ci.setF4_AncestorUniqueName(UNIQUE_NAME_FOR_MEMBER(*namedAncestor)); @@ -778,6 +790,21 @@ namespace columbus { if (getIsNeeded("NCR")) { columbus::graphsupport::incMetricFloat(graph, classItem, "NCR", (float)cc.getNcrad() ); } + + //CLLOC * CI * CCO * NCR * CS + if (getIsNeeded("CR")) { + columbus::graphsupport::setMetricFloat(graph, classItem, "CR", cc.getRisk() ); + } + + //CI * CED * NCR + if (getIsNeeded("CEE")) { + columbus::graphsupport::setMetricFloat(graph, classItem, "CEE", cc.getEffort()); + } + + if (getIsNeeded("CEG")) { + float ceg = ((float)cc.getRisk())/cc.getEffort(); + columbus::graphsupport::setMetricFloat(graph, classItem, "CEG", ceg); + } if (getIsNeeded("CV")) { columbus::graphsupport::setMetricFloat(graph, classItem, "CV", (float)cc.getCv()); @@ -1321,6 +1348,21 @@ namespace columbus { if (getIsNeeded("NCR")){ columbus::graphsupport::setMetricFloat(graph, gaphSysNodeUUid, "NCR", (float)(collectedMetrics.sumNCR/collectedMetrics.numNCR)); } + + if (getIsNeeded("CR")) { + columbus::graphsupport::setMetricFloat(graph, gaphSysNodeUUid, "CR", collectedMetrics.sumCR/ componentNode->getTLLOC()); + } + + if (getIsNeeded("CEE")) { + columbus::graphsupport::setMetricFloat(graph, gaphSysNodeUUid, "CEE", collectedMetrics.CEE); + } + + if (getIsNeeded("CEG")) { + /* (((1 / (1+ e^(-2*CR/ln(CEE)) )*100)-50)*2) */ + double componentCR = (double)collectedMetrics.sumCR / limFact->getRoot()->getTLLOC(); + columbus::graphsupport::setMetricFloat(graph, gaphSysNodeUUid, "CEG", ((100.0 / ( 1.0 + exp(-2.0 * componentCR / log(collectedMetrics.CEE)))) - 50.0) * 2.0); + } + } } common::WriteMsg::write(CMSG_FINALIZE_DONE_IN, common::getProcessUsedTime().user - time.user); @@ -2873,7 +2915,33 @@ namespace columbus { if (leftNode.uniformPath != rightNode.uniformPath) { return (leftNode.uniformPath < rightNode.uniformPath) ; } +#if defined SCHEMA_JAVA return leftNode.node->compareByPosition(*rightNode.node) < 0; +#else + if(leftNode.node->GET_FILE_KEY_OF_POSITIONS != rightNode.node->GET_FILE_KEY_OF_POSITIONS) + return leftNode.node->GET_FILE_KEY_OF_POSITIONS < rightNode.node->GET_FILE_KEY_OF_POSITIONS; + + if(leftNode.node->GET_LINE_OF_POSITIONS != rightNode.node->GET_LINE_OF_POSITIONS) + return leftNode.node->GET_LINE_OF_POSITIONS < rightNode.node->GET_LINE_OF_POSITIONS; + + if(leftNode.node->GET_COLUMN_OF_POSITIONS != rightNode.node->GET_COLUMN_OF_POSITIONS) + return leftNode.node->GET_COLUMN_OF_POSITIONS < rightNode.node->GET_COLUMN_OF_POSITIONS; + + if(leftNode.node->GET_END_FILE_KEY_OF_POSITIONS != rightNode.node->GET_END_FILE_KEY_OF_POSITIONS) + return leftNode.node->GET_END_FILE_KEY_OF_POSITIONS > rightNode.node->GET_END_FILE_KEY_OF_POSITIONS; + + if(leftNode.node->GET_END_LINE_OF_POSITIONS != rightNode.node->GET_END_LINE_OF_POSITIONS) + return leftNode.node->GET_END_LINE_OF_POSITIONS > rightNode.node->GET_END_LINE_OF_POSITIONS; + + if(leftNode.node-> GET_END_COLUMN_OF_POSITIONS != rightNode.node-> GET_END_COLUMN_OF_POSITIONS) + return leftNode.node-> GET_END_COLUMN_OF_POSITIONS > rightNode.node-> GET_END_COLUMN_OF_POSITIONS; + + if (leftNode.node->getNodeKind() != rightNode.node->getNodeKind()) { + return leftNode.node->getNodeKind() < rightNode.node->getNodeKind(); + } + + return false; +#endif } }; diff --git a/cl/DuplicatedCodeFinder/src/main.cpp b/cl/DuplicatedCodeFinder/src/main.cpp index c004bb0..d0c6c0a 100644 --- a/cl/DuplicatedCodeFinder/src/main.cpp +++ b/cl/DuplicatedCodeFinder/src/main.cpp @@ -93,15 +93,6 @@ static bool ppGenealogy (const Option *o, char *argv[]) { config.genealogyFilename = argv[0]; return true; } - -static bool ppBackupDir (const Option *o, char *argv[]) { - config.backup = argv[0]; - return true; -} -static bool ppGraphML (const Option *o, char *argv[]) { - config.graphml = true; - return true; -} #endif static void ppFile(char *filename) { @@ -161,10 +152,9 @@ const common::Option OPTIONS_OBJ [] = { { false, "-minoccur", 1, "number", 0, OT_WC, ppOccur, NULL, "The minimum number of occurences of each kind of duplication. Default value is 2."}, #ifdef GENEALOGY - { true, "-genealogy", 1, "filename", 0, OT_WC, ppGenealogy, NULL, "The geneology while, which contains historical information about the clones."}, - { true, "-backupdir", 1, "dirname", 0, OT_WC, ppBackupDir, NULL, "The directory where all the input ASG files are copied."}, - { true, "-dumpgenealogygraphml", 0, "", 0, OT_NONE, ppGraphML, NULL, "Dump the genealogy data in graphml format."}, + { false, "-genealogy", 1, "filename", 0, OT_WC, ppGenealogy, NULL, "The geneology while, which contains historical information about the clones."}, #endif + { false, "-graph", 1, "filename", 0, OT_WC, ppGraph, NULL, "Save structured result of the clones and metrics in binary graph format."}, { false, "-patternfilterlog",1, "filename", 0, OT_WC, ppFOut, NULL, "Save the source code positions of the filtered source elements to the given file. If it is not set then the list will be written to the standard out."}, { false, "-patternfilter", 2, "number number", 0, OT_WS, ppPatternFilter,NULL, "Enable pattern filter with the given parameters. The first number is the maximum length (default value is 10) of a single pattern " @@ -193,7 +183,11 @@ void initValues() { } // create rule handler if(config.rulConfig.empty()) { +#ifdef SCHEMA_JAVA config.rulConfig = "java"; +#elif defined(SCHEMA_PYTHON) + config.rulConfig = "python"; +#endif } rulHandler=new rul::RulHandler(config.rul_str, config.rulConfig, "eng"); diff --git a/cl/FindBugs2Graph/inc/ResultConverter.h b/cl/FindBugs2Graph/inc/ResultConverter.h index 4ac4c59..ff1c3ac 100644 --- a/cl/FindBugs2Graph/inc/ResultConverter.h +++ b/cl/FindBugs2Graph/inc/ResultConverter.h @@ -46,7 +46,6 @@ class ResultConverter columbus::graph::Graph* getGraph() { return &graph; } void aggregateWarnings(bool createGroups); - void addLicenseTypeToTheGraphHeader(const std::string& toolName); protected: void writeWarningLine(const std::string& id, const std::string& warningText, std::list& sourceLinks, const std::string& path, int line, int endline, int col, int endcol); diff --git a/cl/FindBugs2Graph/src/ResultConverter.cpp b/cl/FindBugs2Graph/src/ResultConverter.cpp index 768a7b1..a7ede52 100644 --- a/cl/FindBugs2Graph/src/ResultConverter.cpp +++ b/cl/FindBugs2Graph/src/ResultConverter.cpp @@ -409,7 +409,3 @@ void ResultConverter::aggregateWarnings(bool createGroups) { if (createGroups) columbus::graphsupport::createGroupMetrics(graph, *xRulhandler); } - -void ResultConverter::addLicenseTypeToTheGraphHeader(const string& toolName) { - graph.setHeaderInfo(toolName + graphsupport::graphconstants::HEADER_MODE_KEY_SUFFIX, graphsupport::graphconstants::HEADER_MODE_VALUE_FULL ); -} diff --git a/cl/FindBugs2Graph/src/main.cpp b/cl/FindBugs2Graph/src/main.cpp index 32fd1f5..426bbef 100644 --- a/cl/FindBugs2Graph/src/main.cpp +++ b/cl/FindBugs2Graph/src/main.cpp @@ -184,7 +184,6 @@ int main(int argc, char* argv[]) { updateMemoryStat(); - rc.addLicenseTypeToTheGraphHeader(EXECUTABLE_NAME); rc.saveGraph(outGraph); // terminate xerces diff --git a/cl/LIM2Metrics/CMakeLists.txt b/cl/LIM2Metrics/CMakeLists.txt index ce8f36e..b8aa22d 100644 --- a/cl/LIM2Metrics/CMakeLists.txt +++ b/cl/LIM2Metrics/CMakeLists.txt @@ -6,18 +6,10 @@ set (SOURCES messages.h ) -function (add_language_config LANG) - add_executable(${PROGRAM_NAME}_${LANG} ${SOURCES}) - add_dependencies(${PROGRAM_NAME}_${LANG} ${COLUMBUS_GLOBAL_DEPENDENCY}) - target_link_libraries(${PROGRAM_NAME}_${LANG} graphsupport lim2graph graph limmetrics_${LANG} lim strtable common csi rul io ${COMMON_EXTERNAL_LIBRARIES}) - set_schema_language_compiler_settings(${PROGRAM_NAME}_${LANG} ${LANG}) - add_copy_next_to_the_binary_dependency (${PROGRAM_NAME}_${LANG} MET.rul) - set_visual_studio_project_folder(${PROGRAM_NAME}_${LANG} FALSE) -# Can not use atm because it tries to generate the pch for all targets -# set_target_properties(${PROGRAM_NAME}_${LANG} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${CMAKE_CURRENT_SOURCE_DIR}/inc/common.h") -# cotire (${PROGRAM_NAME}_${LANG}) -endfunction() - -add_language_config(java) +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} graphsupport lim2graph graph limmetrics lim strtable common csi rul io ${COMMON_EXTERNAL_LIBRARIES}) +add_copy_next_to_the_binary_dependency (${PROGRAM_NAME} MET.rul) +set_visual_studio_project_folder(${PROGRAM_NAME} FALSE) diff --git a/cl/MetricHunter/CMakeLists.txt b/cl/MetricHunter/CMakeLists.txt index c90186c..d3b0ea2 100644 --- a/cl/MetricHunter/CMakeLists.txt +++ b/cl/MetricHunter/CMakeLists.txt @@ -25,3 +25,4 @@ function (add_language_config LANG) endfunction() add_language_config(java) +add_language_config(python) diff --git a/cl/MetricHunter/MetricHunter_PYTHON.threshold b/cl/MetricHunter/MetricHunter_PYTHON.threshold new file mode 100644 index 0000000..76f87c3 --- /dev/null +++ b/cl/MetricHunter/MetricHunter_PYTHON.threshold @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/cl/OpenStaticAnalyzerJava/inc/Properties.h b/cl/OpenStaticAnalyzerJava/inc/Properties.h index fcbb228..dc4a22e 100644 --- a/cl/OpenStaticAnalyzerJava/inc/Properties.h +++ b/cl/OpenStaticAnalyzerJava/inc/Properties.h @@ -72,7 +72,6 @@ struct Properties : public columbus::controller::BaseProperties boost::filesystem::path columbusWrapperTmpDirName; // Name of the directory where the wrapper is assembled (osaDir / temp / wrapper) boost::filesystem::path externalHardFilter; // Absolute path of the external hardfilter file boost::filesystem::path externalSoftFilter; // Absolute path of the external softfilter file - boost::filesystem::path metricThreshold; // Absolute path of the metric threshold file boost::filesystem::path profileXML; boost::filesystem::path rulesCSV; @@ -98,7 +97,6 @@ struct Properties : public columbus::controller::BaseProperties bool runDCF; // Run DCF. bool runLimMetrics; // Run Lim2Metrics. bool runMetricHunter; // Run MetricHunter. - bool runChangeTracker; // Run ChangeTracker. std::string analysisOutputDir; // The name of the output directory (.columbus_java) }; diff --git a/cl/OpenStaticAnalyzerJava/inc/Task.h b/cl/OpenStaticAnalyzerJava/inc/Task.h index e49956a..ea5cd70 100644 --- a/cl/OpenStaticAnalyzerJava/inc/Task.h +++ b/cl/OpenStaticAnalyzerJava/inc/Task.h @@ -29,24 +29,17 @@ DEFINETASK(CleanProjectTask) DEFINETASK(DirectoryBasedAnalysisTask) DEFINETASK(RemoveWrapperBinsTask) DEFINETASK(CheckASGListTask) -DEFINETASK(JAN2ChangePathTask) -DEFINETASK(ASGBackupTask) DEFINETASK(JANFilterTask) DEFINETASK(SuperlinkTask) DEFINETASK(JAN2limTask) DEFINETASK(ProfileTask) -DEFINETASK(FaultHunterTask) -DEFINETASK(VulnerabilityHunterTask) -DEFINETASK(AndroidHunterTask) DEFINETASK(DcfTask) DEFINETASK(PMD2GraphTask) DEFINETASK(FindBugsTask) DEFINETASK(Lim2metricsTask) -DEFINETASK(RTEHunterTask) DEFINETASK(GraphMergeTask) DEFINETASK(GraphDumpTask) DEFINETASK(MetricHunterTask) -DEFINETASK(ChangeTrackerTask) class WrapperBasedAnalysisTask : public columbus::controller::Task { @@ -64,17 +57,4 @@ class WrapperBasedAnalysisTask : public columbus::controller::Task } }; -class AddLicenceTask : public columbus::controller::Task -{ -private: - std::list inactives; -public: - const static std::string name; - AddLicenceTask(std::list inactives, const Properties& properties); - virtual ExecutionResult execute(); - virtual const std::string& getName() const { - return name; - } -}; - #endif diff --git a/cl/OpenStaticAnalyzerJava/rules_java.csv b/cl/OpenStaticAnalyzerJava/rules_java.csv index 154382e..9a5d7ac 100644 --- a/cl/OpenStaticAnalyzerJava/rules_java.csv +++ b/cl/OpenStaticAnalyzerJava/rules_java.csv @@ -2,7 +2,6 @@ toolId;FB;PMD AAA;-;1 AAAI;-;1 AAL;-;1 -AbCWAM;-;1 ABSALIL;-;1 ACEJFE;1;- ACEZFE;1;- @@ -10,47 +9,48 @@ ACF;1;2 ACG;-;1 ACGE;-;1 ACI;-;1 -ACNPE;-;2 -ACT;-;2 +ACNPE;-;1 +ACT;-;1 ACWAM;-;1 ACWC;-;1 ADL;-;1 ADLIBDC;1;2 -ADNIS;-;2 +ADNIS;-;1 ADS;-;1 AEAI;-;1 -AES;-;2 +AES;-;1 AFLV;-;1 AFNMMN;-;1 AFNMTN;-;1 -AICICC;-;2 -AIO;-;2 +AICICC;-;1 +AIO;-;1 AIOIL;-;1 -AISD;-;2 +AISD;-;1 ALEI;-;1 ALIIC;-;1 -ALOC;-;2 +ALOC;-;1 AMUO;-;1 AN;-;1 AOSOCA;1;- APFIFC;1;2 APMIFCNE;-;1 APMP;-;1 -APST;-;2 -ARE;-;2 +APST;-;1 +ARE;-;1 ARP;-;1 ASAML;-;1 ASBF;-;1 ATG;-;1 ATNFS;-;1 ATNIOSE;-;1 -ATNPE;-;2 -ATRET;-;2 +ATNPE;-;1 +ATRET;-;1 AUHCIP;-;1 AUNC;-;1 AUOV;-;1 AUST;-;1 AUV;-;1 +AbCWAM;-;1 BA;1;- BAOSB;1;- BAZ;1;- @@ -61,18 +61,15 @@ BBIU;1;- BBIUTPC;1;- BBOA;1;- BC;1;2 -BcII;1;- BEMSWFAO;1;- -BGMN;-;2 -BI;-;2 +BGMN;-;1 +BI;-;1 BIC;1;- BID;1;- -BII;-;2 -BiI;1;- +BII;-;1 BIOSB;1;- BMSS;-;1 BNC;-;1 -BoI;-;1 BSC;1;- BSCHB;1;- BUACFTO;1;- @@ -80,38 +77,39 @@ BUC;1;- BUCORV;1;- BUIR;1;- BVI;1;- -ByI;-;2 +BcII;1;- +BiI;1;- +BoI;-;1 +ByI;-;1 CAS;1;- CASR;-;1 CBO;-;1 -CC;-;2 +CC;-;1 CCD;1;- -CCE;-;- CCEWTA;1;2 CCOM;-;1 CCRMV;1;- -CI;-;- CICBNC;1;- CIS;-;1 CLA;-;1 -ClMMIC;1;2 -ClR;-;2 CMMIC;-;1 CNC;1;2 -CoC;-;1 -COWE;-;2 +COWE;-;1 CR;-;1 CRCV;1;- CRS;-;1 -CT;-;1 -CTCNSE;-;1 -CWOPCSBF;-;1 CS;-;1 -CSF;-;2 +CSF;-;1 CSIC;-;1 -CSL;-;2 +CSL;-;1 CSNO;1;- CSR;-;1 +CT;-;1 +CTCNSE;-;1 +CWOPCSBF;-;1 +ClMMIC;1;2 +ClR;-;1 +CoC;-;1 DAA;-;1 DAINVTR;1;- DAWO;1;- @@ -120,14 +118,13 @@ DBM;1;- DBMOU;1;- DBPFP;1;- DBPT;1;- -DBZ;-;- DCCIDP;1;- DCDP;1;- DCL;1;2 DCNFH;1;- DCOU;1;- -DCTR;1;2 DCSNCT;1;- +DCTR;1;2 DDB;1;- DDE;1;- DDIDP;1;- @@ -149,24 +146,16 @@ DIS;-;1 DITOA;1;- DITOAA;1;- DLBTDIOI;1;- -DLNLISS;2;3 +DLNLISS;1;2 DMD;1;- -DmD;1;- DMI;1;- DMWOC;1;- DNCGCE;1;2 -DNCRE;-;- DNCSE;1;2 -DNCTIEJB;-;- DNEJLE;-;1 -DNHCSDC;-;2 -DNODICP;-;- +DNHCSDC;-;1 DNOW;1;- -DNSBF;-;- DNTEIF;-;1 -DNULFIEJB;-;- -DNUNQA;-;- -DNUSIEJB;-;- DNUT;1;2 DNVN;1;- DOI;1;- @@ -187,64 +176,63 @@ DUS;1;- DUT;1;- DVCTEM;1;- DVSCC;1;- +DmD;1;- EAAN;1;- EAF;1;- EAFC;-;1 EAS;1;- EAT;1;- EBAC;1;- -ECB;-;2 +ECB;-;1 ECCN;1;- ECFONCWT;1;- ECL;-;1 ECPSWE;1;- -ECUOE;1;- ECSWE;1;- +ECUOE;1;- EDDEFE;1;- EDOE;1;- EER;1;- EESR;1;- EF;1;2 -EFB;-;2 +EFB;-;1 EGACC;1;- EI;-;1 EIAC;1;- -EiER;1;- -EIS;-;2 -EmI;-;1 +EIS;-;1 EMIACSBA;-;1 -EML;-;2 -EMRC;-;- -EmSB;-;1 +EML;-;1 EN;-;1 ENA;1;- EO;-;1 -EOB;-;- EOENS;1;- EONO;1;- EOUO;1;- EPC;-;1 EPL;-;1 -ESB;2;3 +ESB;1;2 ESI;-;1 ESNIL;-;1 ESNO;1;- -ESS;-;2 +ESS;-;1 ESUO;1;- -ETB;-;2 +ETB;-;1 EU;1;- EUCAI;1;- EUI;1;- EUT;1;- EUTUPE;1;- -EWS;-;2 +EWS;-;1 +EiER;1;- +EmI;-;1 +EmSB;-;1 FDNCSF;1;2 FDSBASOC;-;1 FFCBS;-;1 FFNF;1;- FFONF;1;- FFPE;1;- -FLMUB;-;2 +FLMUB;-;1 FLSBWL;-;1 FMEW;1;- FMUFP;1;- @@ -263,7 +251,6 @@ GUT;1;- GUTIGC;1;- HENH;1;- HEUH;1;- -HF;-;- HHNE;1;- HHSSC;1;- HHUOE;1;- @@ -271,7 +258,6 @@ HIEUH;1;- HRPTC;1;- HRPTHH;1;- HSDHOUC;1;- -HTTPRS;-;- HUOUC;1;- IACCO;1;- IAIOIOOM;1;- @@ -287,11 +273,11 @@ IBSM;1;- ICATI;1;- IDCI;1;- IESC;-;1 -IESMUB;-;2 +IESMUB;-;1 IF;-;1 IFNG;1;- IFSP;-;1 -II;-;2 +II;-;1 II2LAI;1;- IIC;1;- IICTD;1;- @@ -305,18 +291,14 @@ IIMCTL;1;- IIRL;1;- IIS;1;- IISC;1;- -IL;-;- IMROI;1;- INSE;1;- INT;1;- IO;-;1 -IOB;-;- IPIDBO;1;- IQURS;1;- ISB;-;1 ISBD;-;1 -ISC;-;- -ISCF;-;- ISMUB;-;1 ISNS;1;- ISUSDI;1;- @@ -341,7 +323,6 @@ JUTCTMA;-;1 JUTSIA;-;1 JUUE;-;1 LC;-;1 -LDAPI;-;- LHNC;-;1 LI;-;1 LINSF;-;1 @@ -349,19 +330,18 @@ LISNC;-;1 LLIS;1;- LLIUS;1;- LLLDTWR;1;- -LoC;-;2 LOD;-;1 -LoI;-;2 LPC;-;1 LV;-;1 -LVCBF;-;2 +LVCBF;-;1 +LoC;-;1 +LoI;-;1 MACBF;-;1 -MBIS;2;3 +MBIS;1;2 MCBF;1;- MCC;-;1 MCMF;1;- MDBASBNC;-;1 -MeNC;2;3 MFP;1;- MMA;1;- MMH;1;- @@ -370,11 +350,9 @@ MMN;1;- MMSF;1;- MMW;1;- MNC;-;1 -MNCTS;-;- MOP;1;- MP;1;- MRIA;1;2 -MRU;-;- MSBF;1;- MSBRTBF;1;- MSMINIC;-;1 @@ -383,15 +361,14 @@ MSOUF;1;- MSSIF;1;- MSVUID;1;2 MTOL;-;1 -MtSSIF;1;- -MURIA;-;- MVN;-;1 -MWSNAEC;2;3 +MWSNAEC;1;2 +MeNC;1;2 +MtSSIF;1;- NA;-;1 NAMBN;1;- NAN;1;- NANE;1;- -NAS;-;- NBE;1;- NBRN;1;- NC;1;- @@ -404,7 +381,6 @@ NDORV;1;- NFKUAI;1;- NFKUAMI;1;- NFNC;1;- -NFSVMBSB;-;- NGD;1;- NGDOEP;1;- NIDOR;1;- @@ -429,8 +405,7 @@ NNRV;1;- NNSC;1;- NORN;1;- NP;-;1 -NPC;-;2 -NPE;-;- +NPC;-;1 NPMBNBMAN;1;- NSANCF;1;- NSI;-;1 @@ -462,13 +437,12 @@ PCI;1;2 PD;-;1 PDREOII;1;- PL;-;1 -PLFIC;-;2 -PLFICIC;-;2 +PLFIC;-;1 +PLFICIC;-;1 PPS;1;- PPZLA;1;- PRPT;1;- -PST;-;2 -PT;-;- +PST;-;1 QQBA;1;- QQFL;1;- R0TI;1;- @@ -478,7 +452,6 @@ RBSFRE;1;- RCCFSRV;1;- RCE;1;- RCFPI;1;- -RcRNONV;1;- RCUFSARE;1;- RDJNCR;1;- REARTN;1;2 @@ -486,7 +459,7 @@ RENT;1;- REWI;-;1 RFFB;-;1 RFI;-;1 -RHWM;-;2 +RHWM;-;1 RINC;-;1 RNC;1;- RNROC;1;- @@ -498,7 +471,6 @@ RRCONANV;1;- RRCT;1;- RRCTNV;1;- RRI;1;- -RRITWP;-;- RRNONV;1;- RRNWHBAN;1;- RROH;1;- @@ -509,9 +481,8 @@ RRVIBP;1;- RRVII;1;- RRVOPI;1;- RSINC;-;1 -RVWL;-;2 -SaFSC;1;- -SaLSC;1;- +RVWL;-;1 +RcRNONV;1;- SBA;-;1 SBE;-;1 SBF;1;- @@ -521,30 +492,27 @@ SBIWC;-;1 SBPSA;1;- SBR;-;1 SBRA;1;- -SC;-;2 +SC;-;1 SCC;-;1 SCFN;-;1 SCN;-;1 -SCTB;1;- SCSBS;1;- +SCTB;1;- SD;-;1 -SDFNL;-;2 +SDFNL;-;1 SDSDTSF;1;- SDSDTSFTT;1;- SDTE;-;1 SEJBFSBF;-;1 SEMN;-;1 -SeNoS;1;- -SeNS;1;- SF;-;1 SFDA;1;- SFSA;1;- SFSC;1;- -SHMN;2;3 -SI;-;2 +SHMN;1;2 +SI;-;1 SIBFA;1;- SIC;1;- -SiDTE;-;1 SIOC;1;- SIOSCI;1;- SIOSDFI;1;- @@ -557,17 +525,16 @@ SLSA;1;- SLSAIOF;1;- SLSC;1;- SMMBP;1;- -SMN;-;2 +SMN;-;1 SNC;1;- SNS;1;- SNSC;1;- SNSCFE;1;- SNSPTE;1;- SOE;-;1 -SP;-;2 +SP;-;1 SPRRNI;1;- SPSGFNS;1;- -SQLI;-;- SRRIS;1;- SRRMRO;1;- SSBS;1;- @@ -577,16 +544,21 @@ SSIC;1;- SSMIIST;1;- SSOF;1;- SSSDFI;1;- -SSSHD;-;2 +SSSHD;-;1 SSW;-;1 SSWLH;1;- STDE;1;- STFNR;1;- STFONC;1;- -StI;-;1 STS;1;2 SV;-;1 SWTSFIM;1;- +SaFSC;1;- +SaLSC;1;- +SeNS;1;- +SeNoS;1;- +SiDTE;-;1 +StI;-;1 TAVUWNR;1;- TCVWITQ;1;- TCWTC;-;1 @@ -594,8 +566,7 @@ TEUSVRAS;1;- TEUSVRNS;1;- TFBFASS;-;1 TMF;-;1 -TMM;-;2 -TMR;-;- +TMM;-;1 TMSI;-;1 TMSVRAS;1;- TMSVRNS;1;- @@ -604,7 +575,7 @@ TTLW;1;- TUVUWASR;1;- UAAL;-;1 UAEIOAT;-;1 -UALIOV;-;2 +UALIOV;-;1 UANIOAT;-;1 UASIOAT;-;1 UATIOAE;-;1 @@ -616,8 +587,8 @@ UCHM;-;1 UCIE;-;1 UCT;-;1 UEC;-;1 -UEM;-;2 -UETCS;-;2 +UEM;-;1 +UETCS;-;1 UFM;-;1 UFNIIC;1;- UFP;-;1 @@ -626,26 +597,24 @@ UI;-;1 UIOC;-;1 UIS;-;1 UIUG;1;- -ULBR;-;2 -ULV;-;2 -ULWCC;2;3 +ULBR;-;1 +ULV;-;1 +ULWCC;1;2 UM;-;1 UNAION;-;1 UNCIE;1;2 UNF;1;- -UnI;-;2 UOFCAPI;-;1 -UOM;-;2 +UOM;-;1 UOOI;-;1 UP;-;1 UPCL;-;1 -UPF;2;3 -UPM;-;2 +UPF;1;2 +UPM;-;1 UR;-;1 -USBFSA;2;3 +USBFSA;1;2 USBL;-;1 USDF;-;1 -UsP;-;2 USSUG;1;- USVO;-;1 UUAM;1;- @@ -662,11 +631,13 @@ UUPOPF;1;- UUR;1;- UURCFSC;1;- UUSM;1;- -UuUF;1;- -UuUPOPF;1;- UUW;1;- UV;-;1 UWOC;1;2 +UnI;-;1 +UsP;-;1 +UuUF;1;- +UuUPOPF;1;- UwUF;1;- UwUPOPF;1;- VFSBA;1;- @@ -685,7 +656,7 @@ VUR;1;- VVI;1;- VVRTA;1;- WANIL;1;- -WLMUB;-;2 +WLMUB;-;1 WNIL;1;- WUGRTCL;1;- WWMI;1;- @@ -693,5 +664,4 @@ WWS;1;- XRPTJW;1;- XRPTSE;1;- XRPTSW;1;- -XSS;-;- XXFB;1;- diff --git a/cl/OpenStaticAnalyzerJava/src/Task.cpp b/cl/OpenStaticAnalyzerJava/src/Task.cpp index 8ee8a44..9c17f08 100644 --- a/cl/OpenStaticAnalyzerJava/src/Task.cpp +++ b/cl/OpenStaticAnalyzerJava/src/Task.cpp @@ -338,11 +338,11 @@ Task::ExecutionResult WrapperBasedAnalysisTask::execute() string files[13] = { "JAN.jar", "JColumbusAntWrapper.jar", - "OpenStaticAnalyzerAgent-8.2.jar", - "OpenStaticAnalyzer-maven-plugin-8.2.jar", - "OpenStaticAnalyzer-maven-plugin-8.2-V2.pom", - "OpenStaticAnalyzer-maven-plugin-8.2-V3.pom", - "OpenStaticAnalyzer-maven-plugin-8.2-V31.pom", + "OpenStaticAnalyzerAgent-2.0.jar", + "OpenStaticAnalyzer-maven-plugin-2.0.jar", + "OpenStaticAnalyzer-maven-plugin-2.0-V2.pom", + "OpenStaticAnalyzer-maven-plugin-2.0-V3.pom", + "OpenStaticAnalyzer-maven-plugin-2.0-V31.pom", "OpenStaticAnalyzer-Maven-plugin-mojo-executer-2.2.1.jar", "OpenStaticAnalyzer-Maven-plugin-mojo-executer-2.2.1.pom", "OpenStaticAnalyzer-Maven-plugin-mojo-executer-3.0.jar", @@ -366,7 +366,7 @@ Task::ExecutionResult WrapperBasedAnalysisTask::execute() SafeEnvironmentModifier we_env("WRAPPER_ENVIRONMENT", props.tempDir, logger); SafeEnvironmentModifier wwdn_env("WRAPPER_WORK_DIR_NAME", props.columbusWrapperTmpDirName, logger); - SafeEnvironmentModifier mo_env("MAVEN_OPTS", "-javaagent:" + (props.wrapperToolsDir / "OpenStaticAnalyzerAgent-8.2.jar").string(), logger); + SafeEnvironmentModifier mo_env("MAVEN_OPTS", "-javaagent:" + (props.wrapperToolsDir / "OpenStaticAnalyzerAgent-2.0.jar").string(), logger); SafeEnvironmentModifier ssll_env("OSA_SUPERLINKLIST", props.superLinkList.string(), logger); SafeEnvironmentModifier sspmdll_env("OSA_SUPERPMDLIST", props.pmdXmlList.string(), logger); @@ -953,10 +953,7 @@ Task::ExecutionResult MetricHunterTask::execute() sv.push_back("-graph:" + graphFile); sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-MetricHunter.txt")).string()); - if (!props.metricThreshold.empty()) - sv.push_back("-thresholds:" + props.metricThreshold.string()); - else - sv.push_back("-thresholds:" + (props.tempDir / "MetricHunter.threshold").string()); + sv.push_back("-thresholds:" + (props.tempDir / "MetricHunter.threshold").string()); sv.push_back("-exportrul"); sv.push_back(graphFile); diff --git a/cl/OpenStaticAnalyzerJava/src/main.cpp b/cl/OpenStaticAnalyzerJava/src/main.cpp index a98b5b9..64eb030 100644 --- a/cl/OpenStaticAnalyzerJava/src/main.cpp +++ b/cl/OpenStaticAnalyzerJava/src/main.cpp @@ -109,11 +109,6 @@ bool ppBaseDir(const common::Option *o, char *argv[]) { return true; } -bool ppMetricThreshold(const common::Option *o, char *argv[]) { - props.metricThreshold = argv[0]; - return true; -} - bool ppJavacOptions(const common::Option *o, char *argv[]) { props.javacOptions = argv[0]; return true; @@ -286,7 +281,6 @@ void dumpProperties() { DUMP_PROPERTY_PATH(columbusWrapperTmpDir); DUMP_PROPERTY_PATH(externalHardFilter); DUMP_PROPERTY_PATH(externalSoftFilter); - DUMP_PROPERTY_PATH(metricThreshold); DUMP_PROPERTY_STRING(projectName); DUMP_PROPERTY_INT(cloneGenealogy); DUMP_PROPERTY_INT(maxThreads); @@ -354,7 +348,7 @@ void checkUserProperties() props.projectBaseDir = canonical(props.projectBaseDir).make_preferred(); if (props.currentDate.empty()) - props.currentDate = common::getCurrentTimeAndDate("%Y-%m-%d-%H-%M-%S"); // pattern="yyyy-MM-dd_HH-mm-ss" + props.currentDate = common::getCurrentTimeAndDate("%Y-%m-%d-%H-%M-%S"); // pattern="yyyy-MM-dd-HH-mm-ss" props.projectResultDir = props.resultsDir / props.projectName / "java"; props.projectTimedResultDir = props.projectResultDir / props.currentDate; @@ -372,8 +366,6 @@ void checkUserProperties() props.externalHardFilter = system_complete(props.externalHardFilter); if ( !props.externalSoftFilter.empty() ) props.externalSoftFilter = system_complete(props.externalSoftFilter); - if ( !props.metricThreshold.empty() ) - props.metricThreshold = system_complete(props.metricThreshold); if (props.maxThreads == 0) props.maxThreads = columbus::thread::ThreadPool::getNumberOfCores(); diff --git a/cl/OpenStaticAnalyzerPython/CMakeLists.txt b/cl/OpenStaticAnalyzerPython/CMakeLists.txt new file mode 100644 index 0000000..6208476 --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/CMakeLists.txt @@ -0,0 +1,16 @@ +set (PROGRAM_NAME OpenStaticAnalyzerPython) + +set (SOURCES + src/Task.cpp + src/main.cpp + + inc/messages.h + inc/Properties.h + inc/Task.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} lim controller graph graphsupport threadpool rul strtable common csi io ${COMMON_EXTERNAL_LIBRARIES}) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} rules_python.csv) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/OpenStaticAnalyzerPython/inc/Properties.h b/cl/OpenStaticAnalyzerPython/inc/Properties.h new file mode 100644 index 0000000..105fc35 --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/inc/Properties.h @@ -0,0 +1,79 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _OSAPY_PROP_H_ +#define _OSAPY_PROP_H_ + +#include +#include +#include +#include + +struct Properties : public columbus::controller::BaseProperties +{ + Properties() + : cloneGenealogy(false) + , csvSeparator(',') + , csvDecimalmark('.') + , cleanResults(-1) + , cloneMinLines(-1) + , runDCF(true) + , runPylint(true) + , runMetricHunter(true) + , runLimMetrics(true) + {} + + bool cloneGenealogy; // Create clone genealogy or no. + + std::string projectName; // The name of the project which is given by the user + + boost::filesystem::path startCurrentDir; // Absolute path of the current directory when the CAC was started + boost::filesystem::path toolchainDir; // Absolute path of the directory of the CA toolchain + boost::filesystem::path toolsDir; // Absolute path of the directory of the tools inside the CA package + + boost::filesystem::path profileXML; + boost::filesystem::path rulesCSV; + + boost::filesystem::path resultsDir; // Absolute path of the result directory given by the user + boost::filesystem::path currentDate; // The current date + boost::filesystem::path projectResultDir; // resultsDir / projectName / + boost::filesystem::path projectTimedResultDir; // projectResultDir / currentDate + boost::filesystem::path projectBaseDir; // Absolute path of the base directory given by the user + boost::filesystem::path tempDir; // Absolute path of the directory of the temporary files + boost::filesystem::path asgDir; // Absolute path of the directory of the asg files + boost::filesystem::path graphDir; // Absolute path of the directory of the graph files + boost::filesystem::path externalHardFilter; // Absolute path of the external hardfilter file + boost::filesystem::path pythonBinary; // Path of the Python 2.7/3.x binary + std::string pythonVersion; // Python version (2 or 3) + std::list pylintOptions; // Options passed to Pylint + char csvSeparator; // Column separator character of the csv outputs. + char csvDecimalmark; // Decimal mark character in the csv outputs. + int cleanResults; // Keep the last 'cleanResults' number of timestamped directory of the project in the results. + int cloneMinLines; // Minimum number of lines of clone instances. + + bool runDCF; // Run DCF. + bool runPylint; // Run Pylint2Graph + bool runMetricHunter; // Run MetricHunter. + bool runLimMetrics; // Run Lim2Metrics. +}; + +extern Properties props; + +#endif diff --git a/cl/OpenStaticAnalyzerPython/inc/Task.h b/cl/OpenStaticAnalyzerPython/inc/Task.h new file mode 100644 index 0000000..9774536 --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/inc/Task.h @@ -0,0 +1,44 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _OSAPY_TASK_H_ +#define _OSAPY_TASK_H_ + +#include +#include +#include + +#include +#include +#include "Properties.h" + +DEFINETASK(PANTask) +DEFINETASK(PAN2LimTask) +DEFINETASK(ProfileTask) +DEFINETASK(LIM2MetricsTask) +DEFINETASK(DcfTask) +DEFINETASK(PylintTask) +DEFINETASK(Pylint2GraphTask) +DEFINETASK(GraphMergeTask); +DEFINETASK(MetricHunterTask); +DEFINETASK(GraphDumpTask); +DEFINETASK(CleanResultsTask); + +#endif diff --git a/cl/OpenStaticAnalyzerPython/inc/messages.h b/cl/OpenStaticAnalyzerPython/inc/messages.h new file mode 100644 index 0000000..81ee4f1 --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/inc/messages.h @@ -0,0 +1,31 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _OSAPY_M_H_ +#define _OSAPY_M_H_ + +#define CMSG_ERROR_CREATE_DIR "ERROR: Can't create %s dir.\n" +#define CMSG_ERROR_EXECUTION_FAILURE "ERROR: Execution failure! Exit:%d\n" +#define CMSG_ERROR_ENVSET_FAILURE "ERROR: Failed to set '%s' environment variable!\n" +#define CMSG_WARNING_ENVSET_OVERWRITE "WARNING: Overwriting '%s' environment variable!\n" +#define CMSG_ERROR_DELETE_DIR "ERROR: Can't delete %s dir. %s.\n" +#define CMSG_PYTHON_BIN_ERROR WriteMsg::mlError, "Error: Python 2.7/3.x binary is not found on PATH nor specified with '-pythonBinary' option correctly.\n" + +#endif \ No newline at end of file diff --git a/cl/OpenStaticAnalyzerPython/rules_python.csv b/cl/OpenStaticAnalyzerPython/rules_python.csv new file mode 100644 index 0000000..7489286 --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/rules_python.csv @@ -0,0 +1,292 @@ +toolId;PYLINT +AB;1 +ABIS;1 +ACI;1 +AD;1 +ADOI;1 +AE;1 +AFN;1 +AFNR;1 +AM;1 +AMBD;1 +ANS;1 +AOT;1 +ATNK;1 +AUEIS;1 +B;1 +BC;1 +BCA;1 +BD;1 +BE;1 +BEC;1 +BEO;1 +BFC;1 +BFS;1 +BFSK;1 +BI;1 +BIO;1 +BMCA;1 +BMMA;1 +BN;1 +BOE;1 +BOM;1 +BOV;1 +BP3I;1 +BRS;1 +BSA;1 +BSC;1 +BSSC;1 +BW;1 +BaB;1 +BrE;1 +BuB;1 +CB;1 +CI;1 +CID;1 +CIF;1 +CM;1 +CMI;1 +CNE;1 +CUE;1 +CUT;1 +CVFL;1 +CWS;1 +CoB;1 +CoM;1 +DAN;1 +DB;1 +DC;1 +DDV;1 +DE;1 +DIM;1 +DK;1 +DL;1 +DM;1 +DP;1 +DSF;1 +DSTC;1 +DVM;1 +DeM;1 +DepM;1 +DiM;1 +EB;1 +ED;1 +EMA;1 +ENA;1 +EU;1 +EWH;1 +ExU;1 +F;1 +FB;1 +FBNI;1 +FCS;1 +FI;1 +FNM;1 +FR;1 +Fi;1 +GAML;1 +GM;1 +GS;1 +GVNA;1 +GVU;1 +HM;1 +IAO;1 +IB;1 +ICID;1 +IE;1 +IED;1 +IFI;1 +IIG;1 +ILR;1 +IM;1 +IN;1 +INC;1 +IS;1 +ISAT;1 +ISC;1 +ISI;1 +ISML;1 +ISO;1 +IUOT;1 +IdM;1 +InB;1 +InE;1 +InM;1 +InS;1 +InSI;1 +LAC;1 +LB;1 +LC;1 +LD;1 +LE;1 +LFI;1 +LFT;1 +LLS;1 +LNL;1 +LS;1 +LTFA;1 +LTL;1 +LTMA;1 +LUF;1 +LoE;1 +MA;1 +MBNI;1 +MBR;1 +MCC;1 +MCF;1 +MD;1 +MF;1 +MFA;1 +MFAK;1 +MFN;1 +MFS;1 +MFSK;1 +MH;1 +MI;1 +MK;1 +MLE;1 +MS;1 +MSA;1 +MuI;1 +NACM;1 +NAG;1 +NAI;1 +NAM;1 +NC;1 +NCD;1 +NCM;1 +NE;1 +NER;1 +NI;1 +NIL;1 +NIR;1 +NM;1 +NMA;1 +NMC;1 +NNIM;1 +NO;1 +NPIC;1 +NR;1 +NSA;1 +NSD;1 +NSU;1 +NVFP;1 +NWB;1 +NoAI;1 +NoM;1 +OD;1 +OM;1 +ONO;1 +OOL;1 +ORS;1 +OSC;1 +PA;1 +PE;1 +POOC;1 +PS;1 +PSS;1 +PU;1 +PrS;1 +R;1 +RAFL;1 +RAIG;1 +RB;1 +RBNI;1 +RBT;1 +RBTL;1 +RCF;1 +RI;1 +RIH;1 +RII;1 +RK;1 +RKA;1 +RM;1 +RNE;1 +ROF;1 +RON;1 +RS;1 +RUA;1 +ReB;1 +RedB;1 +RelB;1 +RoB;1 +SB;1 +SC;1 +SD;1 +SE;1 +SINC;1 +SIS;1 +SM;1 +SMI;1 +SNAT;1 +SOOC;1 +SP;1 +SSUFS;1 +SuM;1 +SuOOC;1 +TCT;1 +TFFA;1 +TFPM;1 +TFS;1 +TMA;1 +TMB;1 +TMBE;1 +TMFA;1 +TMIA;1 +TML;1 +TMNB;1 +TMPM;1 +TMRS;1 +TMS;1 +TMSE;1 +TN;1 +TW;1 +ToMA;1 +ToMFA;1 +ToML;1 +U;1 +UA;1 +UAO;1 +UAV;1 +UB;1 +UBA;1 +UBO;1 +UCA;1 +UCT;1 +UDO;1 +UEOL;1 +UFSA;1 +UFSK;1 +UIE;1 +UIO;1 +UKA;1 +UL;1 +ULEF;1 +ULV;1 +UMT;1 +UN;1 +UNS;1 +UO;1 +UP;1 +UPGD;1 +US;1 +USD;1 +USMS;1 +UT;1 +UTU;1 +UV;1 +UWI;1 +UnB;1 +UnI;1 +UnV;1 +UngI;1 +UsS;1 +WI;1 +WIO;1 +WIP;1 +WSIC;1 +WSID;1 +XB;1 +YIAF;1 +YOF;1 +ZBNI;1 diff --git a/cl/OpenStaticAnalyzerPython/src/Task.cpp b/cl/OpenStaticAnalyzerPython/src/Task.cpp new file mode 100644 index 0000000..a0abc7c --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/src/Task.cpp @@ -0,0 +1,459 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../inc/Task.h" +#include "../inc/messages.h" +#include "../inc/Properties.h" + + +#define TASK_NAME_DEF(_NAME) const string _NAME::name(#_NAME) +#define TOOL_RUL_CONFIG(_TOOL_NAME) _TOOL_NAME##_rulconfig +#define TOOL_RUL_CONFIG_DEF(_TOOL_NAME, _CONFIG) const string TOOL_RUL_CONFIG(_TOOL_NAME)(#_CONFIG) + +using namespace std; +using namespace columbus; +using namespace columbus::controller; +using namespace common; +using namespace boost::filesystem; +using namespace boost; + +TASK_NAME_DEF(PANTask); + +Task::ExecutionResult PANTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back("-out:" + (props.asgDir / (props.projectName + ".psi")).string()); + sv.push_back((props.projectBaseDir).string()); + + sv.push_back("-analyzepackages"); + + if (!props.externalHardFilter.empty()) + sv.push_back("-fltp:" + props.externalHardFilter.string()); + + sv.push_back("-pythonBinary:" + props.pythonBinary.string()); + + if (props.pythonVersion == "2") + checkedExec(props.toolsDir / "PAN2", sv, logger); + else + checkedExec(props.toolsDir / "PAN3", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +PANTask::PANTask(const Properties& properties) : Task(properties) +{ + // there is no dependency +} + +TASK_NAME_DEF(PAN2LimTask); + +Task::ExecutionResult PAN2LimTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back((props.asgDir / (props.projectName + ".psi")).string()); + sv.push_back("-out:" + (props.asgDir / (props.projectName + ".lim")).string()); + + checkedExec(props.toolsDir / "PAN2Lim", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +PAN2LimTask::PAN2LimTask(const Properties& properties) : Task(properties) +{ + addDependsOn(PANTask::name); +} + + +TASK_NAME_DEF(LIM2MetricsTask); +TOOL_RUL_CONFIG_DEF(LIM2Metrics, python); + +Task::ExecutionResult LIM2MetricsTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back("-graph:" + (props.graphDir / (props.projectName + "-metrics.graph")).string()); + sv.push_back("-rul:" + (props.toolsDir / "MET.rul").string()); + sv.push_back("-rulconfig:" + TOOL_RUL_CONFIG(LIM2Metrics)); + sv.push_back("-exportrul"); + sv.push_back((props.asgDir / (props.projectName + ".lim")).string()); + + checkedExec(props.toolsDir / "LIM2Metrics", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +LIM2MetricsTask::LIM2MetricsTask(const Properties& properties) : Task(properties) +{ + addDependsOn(PANTask::name); + addDependsOn(PAN2LimTask::name); +} + +TASK_NAME_DEF(DcfTask); +TOOL_RUL_CONFIG_DEF(Dcf, python); + +Task::ExecutionResult DcfTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + + vector sv; + addMessageLevel(sv); + + sv.push_back((props.asgDir / (props.projectName + ".psi")).string()); + sv.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); + sv.push_back("-graph:" + (props.graphDir / (props.projectName + "-DCF.graph")).string()); + sv.push_back("-metrics"); + sv.push_back("-multipleasgroot"); + sv.push_back("-onlyfunctionclone"); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-clones.txt")).string()); + sv.push_back("-patternfilter"); + sv.push_back("10"); + sv.push_back("100"); + sv.push_back("-rul:" + (props.toolsDir / "DCF.rul").string()); + sv.push_back("-rulconfig:" + TOOL_RUL_CONFIG(Dcf)); + sv.push_back("-exportrul"); + + if (props.cloneGenealogy){ + sv.push_back("-genealogy:" + (props.projectResultDir / (props.projectName + ".gsi")).string()); + } + + if (props.cloneMinLines != -1) + sv.push_back("-minlines:" + common::toString(props.cloneMinLines)); + + checkedExec(props.toolsDir / "DuplicatedCodeFinder", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +DcfTask::DcfTask(const Properties& properties) : Task(properties) +{ + addDependsOn(PANTask::name); + addDependsOn(PAN2LimTask::name); +} + + +TASK_NAME_DEF(PylintTask); + +Task::ExecutionResult PylintTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back("-runpylint"); + sv.push_back("-pythonBinary:" + props.pythonBinary.string()); + sv.push_back("-pylintdir:" + (props.toolsDir / "python").string()); + sv.push_back("-pylintrc:" + (props.toolsDir / "Pylint.conf").string()); + sv.push_back("-projectbasedir:" + props.projectBaseDir.string()); + sv.push_back("-pylintout:" + (props.tempDir / (props.projectName + "-Pylint-result.txt")).string()); + for (const string& s : props.pylintOptions) + sv.push_back("-pylintOptions:" + s); + + checkedExec(props.toolsDir / "Pylint2Graph", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +PylintTask::PylintTask(const Properties& properties) : Task(properties) +{ + // there is no dependency +} + + +TASK_NAME_DEF(Pylint2GraphTask); +TOOL_RUL_CONFIG_DEF(Pylint2Graph, Default); + +Task::ExecutionResult Pylint2GraphTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back((props.tempDir / (props.projectName + "-Pylint-result.txt")).string()); + sv.push_back("-lim:" + (props.asgDir / (props.projectName + ".lim")).string()); + sv.push_back("-graph:" + (props.graphDir / (props.projectName + "-Pylint.graph")).string()); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-Pylint.txt")).string()); + sv.push_back("-rul:" + (props.tempDir / "Pylint.rul").string()); + sv.push_back("-rulconfig:" + TOOL_RUL_CONFIG(Pylint2Graph)); + sv.push_back("-exportrul"); + + checkedExec(props.toolsDir / "Pylint2Graph", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +Pylint2GraphTask::Pylint2GraphTask(const Properties& properties) : Task(properties) +{ + addDependsOn(PAN2LimTask::name); + addDependsOn(PylintTask::name); + addDependsOn(ProfileTask::name); +} + +TASK_NAME_DEF(GraphMergeTask); + +Task::ExecutionResult GraphMergeTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + vector sv; + addMessageLevel(sv); + + directory_iterator end; + + for (directory_iterator fileIterator(props.graphDir); fileIterator != end; ++fileIterator) { + sv.push_back(fileIterator->path().string()); + } + sort(sv.begin(), sv.end()); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + ".graph")).string()); + + checkedExec(props.toolsDir / "GraphMerge", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +GraphMergeTask::GraphMergeTask(const Properties& properties) : Task(properties) +{ + addDependsOn(PANTask::name); + addDependsOn(LIM2MetricsTask::name); + addDependsOn(DcfTask::name); + addDependsOn(Pylint2GraphTask::name); +} + + +TASK_NAME_DEF(MetricHunterTask); + +Task::ExecutionResult MetricHunterTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + sv.push_back((props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-thresholds:" + (props.tempDir / "MetricHunter.threshold").string()); + + sv.push_back("-graph:" + (props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-out:" + (props.projectTimedResultDir / (props.projectName + "-MetricHunter.txt")).string()); + sv.push_back("-exportrul"); + + checkedExec(props.toolsDir / "MetricHunter", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +MetricHunterTask::MetricHunterTask(const Properties& properties) : Task(properties) +{ + addDependsOn(GraphMergeTask::name); +} + + +TASK_NAME_DEF(GraphDumpTask); + +Task::ExecutionResult GraphDumpTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + + try { + vector sv; + addMessageLevel(sv); + + sv.push_back((props.projectTimedResultDir / (props.projectName + ".graph")).string()); + sv.push_back("-csv"); + sv.push_back("-xml"); + sv.push_back("-csvseparator:" + string(1, props.csvSeparator)); + sv.push_back("-csvdecimalmark:" + string(1, props.csvDecimalmark)); + + checkedExec(props.toolsDir / "GraphDump", sv, logger); + + } HANDLE_TASK_EXCEPTIONS + + return result; +} + +GraphDumpTask::GraphDumpTask(const Properties& properties) : Task(properties) +{ + addDependsOn(GraphMergeTask::name); + addDependsOn(MetricHunterTask::name); +} + + +TASK_NAME_DEF(CleanResultsTask); + +Task::ExecutionResult CleanResultsTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + set directoryList; + directory_iterator end; + directory_iterator begin(props.projectResultDir); + for( directory_iterator iter = begin; iter != end; ++iter ) { + if (is_directory(iter->path())) { + static const regex dateFormatRegexpr("\\d{4}(-\\d{2}){5}"); + if (regex_match(iter->path().filename().string(), dateFormatRegexpr)) + directoryList.insert(*iter); + } + } + + set::const_iterator dirIt = directoryList.begin(); + int toBeDeletedCounter = (int)directoryList.size() - props.cleanResults - 1; + for (int dirCounter = 0; dirCounter < toBeDeletedCounter; ++dirCounter) { + logstream << "Removing directory:" << dirIt->string() << "\n"; + remove_all(*dirIt); + ++dirIt; + } + + if (props.cleanResults == 0) { + path genealogyFile = props.projectResultDir / (props.projectName + ".gsi"); + logstream << "Removing genealogy file:" << genealogyFile.string() << "\n"; + logger.warningIfFail(remove(genealogyFile), "Failed to remove the genealogy file:%s\n", genealogyFile.string().c_str()); + } + + } HANDLE_TASK_EXCEPTIONS + + return result; + +} + +CleanResultsTask::CleanResultsTask(const Properties& properties) : Task(properties) +{ + // there is no dependency +} + + +TASK_NAME_DEF(ProfileTask); + +Task::ExecutionResult ProfileTask::execute() +{ + ExecutionResult result; + ExecutionLogger logger(this, result); + try { + + // original rul files + path PylintRulFileOrig = props.toolsDir / "Pylint.rul"; + + // temp rul files + path PylintRulFile = props.tempDir / "Pylint.rul"; + + // copy original rul files into temp + if (exists(PylintRulFileOrig)) + copy_file(PylintRulFileOrig, PylintRulFile); + + // data + ProfileHandler profile; + map rulHandlers; // for rul files + map runTool; // running tools + + // load profile + if(!props.profileXML.empty()) + profile.parseXML(props.profileXML.string()); + + // load rul files + rul::RulHandler pylintrh(PylintRulFile.string(), "Default", "eng"); + + rulHandlers.insert(make_pair("PYLINT", &pylintrh)); + + // set running tools + runTool.insert(make_pair("PYLINT", props.runPylint)); + + //process rules csv + profileProcessRulesCSV(profile, rulHandlers, runTool, props.rulesCSV.string()); + + path MetricHunterThresholdsFileOrig = props.toolsDir / "MetricHunter.threshold"; + path MetricHunterThresholdsFile = props.tempDir / "MetricHunter.threshold"; + + //process thresholds + profileProcessToolThresholds(profile, "MetricHunter", MetricHunterThresholdsFileOrig.string(), MetricHunterThresholdsFile.string()); + + } HANDLE_TASK_EXCEPTIONS + return result; +} + +ProfileTask::ProfileTask(const Properties& properties) : Task(properties) +{ + addDependsOn(PAN2LimTask::name); +} diff --git a/cl/OpenStaticAnalyzerPython/src/main.cpp b/cl/OpenStaticAnalyzerPython/src/main.cpp new file mode 100644 index 0000000..07b2d8b --- /dev/null +++ b/cl/OpenStaticAnalyzerPython/src/main.cpp @@ -0,0 +1,490 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../inc/messages.h" +#include "../inc/Properties.h" +#include "../inc/Task.h" +#include + +#define PROGRAM_NAME "OpenStaticAnalyzer for Python" +#define EXECUTABLE_NAME "OpenStaticAnalyzerPython" + +#include "MainCommon.h" + +using namespace std; +using namespace common; +using namespace boost::filesystem; +using namespace columbus::controller; + +Properties props; + +static void ppFile(char *str) { +} + +bool ppProjectBaseDir(const common::Option *o, char *argv[]) { + props.projectBaseDir = argv[0]; + return true; +} + +bool ppResultsDir(const common::Option *o, char *argv[]) { + props.resultsDir = argv[0]; + return true; +} + +bool ppProjectName(const common::Option *o, char *argv[]) { + props.projectName = argv[0]; + return true; +} + +bool ppExternalHardFilter(const common::Option *o, char *argv[]) { + props.externalHardFilter = argv[0]; + return true; +} + +bool ppMaxThreads(const common::Option *o, char *argv[]) { + props.maxThreads = common::str2int(argv[0]); + return true; +} + +bool ppCurrentDate(const common::Option *o, char *argv[]) { + props.currentDate = argv[0]; + return true; +} + +bool ppCleanResults(const common::Option *o, char *argv[]) { + props.cleanResults = common::str2int(argv[0]); + return true; +} + +bool ppCloneMinLines(const common::Option *o, char *argv[]) { + props.cloneMinLines = common::str2int(argv[0]); + return true; +} + +bool ppCsvSeparator(const common::Option *o, char *argv[]) { + if (strcmp(argv[0], "\\t") == 0) + props.csvSeparator = '\t'; + else if (argv[0] != 0) + props.csvSeparator = argv[0][0]; + return true; +} + +bool ppCsvDecimalMark(const common::Option *o, char *argv[]) { + if (argv[0][0] != 0) + props.csvDecimalmark = argv[0][0]; + return true; +} + +bool ppPythonBinary(const common::Option *o, char *argv[]) { + props.pythonBinary = argv[0]; + return true; +} + +bool ppPythonVersion(const common::Option *o, char *argv[]) { + props.pythonVersion = argv[0]; + return true; +} + +bool ppPylintOptions(const common::Option *o, char *argv[]) { + props.pylintOptions.push_back(argv[0]); + return true; +} + +bool ppCloneGenealogy (const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.cloneGenealogy = true; + else + props.cloneGenealogy = false; + return true; +} + +bool ppRunMetricHunter (const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runMetricHunter = true; + else + props.runMetricHunter = false; + return true; +} + +bool ppPylint(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runPylint = true; + else + props.runPylint = false; + return true; +} + +bool ppRunDCF(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runDCF = true; + else + props.runDCF = false; + return true; +} + +bool ppRunMET(const common::Option *o, char *argv[]) { + if(strcmp(argv[0], "true") == 0) + props.runLimMetrics = true; + else + props.runLimMetrics = false; + return true; +} + +bool ppProfileXML(const common::Option *o, char *argv[]) { + props.profileXML = argv[0]; + return true; +} + +bool ppVerbose(const common::Option *o, char *argv[]) { + WriteMsg::setMessageLevel(WriteMsg::mlDebug); + props.verbose = true; + return true; +} + +const Option OPTIONS_OBJ [] = { + { false, "-projectBaseDir", 1, CL_KIND_DIR, 1, OT_WE | OT_WC, ppProjectBaseDir, NULL, "Directory of the source code to be analyzed specified with relative or absolute path."}, + { false, "-resultsDir", 1, CL_KIND_DIR, 2, OT_WE | OT_WC, ppResultsDir, NULL, "Relative or absolute path name of the directory where the results of the analysis will be stored. The directory will be created automatically if it does not exist."}, + { false, "-projectName", 1, CL_KIND_STRING, 3, OT_WE | OT_WC, ppProjectName, NULL, "The name of the analyzed software system. The name specified here will be used for storing the results."}, + { false, "-externalHardFilter", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppExternalHardFilter, NULL, "Filter file specified with relative or absolute path, to filter out certain files from the analysis based on their path names. Filtered files will not appear in the results. The filter file is a simple text file containing lines starting with '+' or '-' characters followed by a regular expression. During the analysis, each input file will be checked for these expressions. If the first character of the last matching expression is '-', then the given file will be excluded from the analysis. If the first character of the last matching expression is '+', or there is no matching expression, then the file will be analyzed. A line starting with a different character than '-' or '+' will be ignored."}, + { false, "-cloneGenealogy", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppCloneGenealogy, NULL, "This parameter turns on or off the tracking of code clones (copy-pasted source code fragments) through the consecutive revisions of the software system. It is required that during the analysis of the different revisions, the values set to projectName and resultsDir remain the same, so OpenStaticAnalyzer will handle them as different revisions of the same system. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"false\"."}, + { false, "-cloneMinLines", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCloneMinLines, NULL, "This parameter sets the minimum required size of each duplication in lines of code. The default value is 10."}, + { false, "-csvSeparator", 1, CL_KIND_CHAR, 0, OT_WE | OT_WC, ppCsvSeparator, NULL, "This parameter sets the separator character in the CSV outputs. The default value is the comma (\",\"). The character set here must be placed in quotation marks (e.g. -csvSeparator=\";\"). Tabulator character can be set by the special \"\\t\" value."}, + { false, "-csvDecimalMark", 1, CL_KIND_CHAR, 0, OT_WE | OT_WC, ppCsvDecimalMark, NULL, "This parameter sets the decimal mark character in the CSV outputs. The default is value is the dot (\".\"). The character set here must be placed in quotation marks (e.g. -csvDecimalMark=\",\")."}, + { false, "-currentDate", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppCurrentDate, NULL, "The name of the directory with date inside the result directory of the project. If it is not set, then the current date is used."}, + { false, "-maximumThreads", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppMaxThreads, NULL, "This parameter sets the maximum number of parallel tasks the controller can start. The default value is the number of available CPU cores on the current system."}, + { false, "-pythonBinary", 1, CL_KIND_FILE, 5, OT_WE | OT_WC, ppPythonBinary, NULL, "Sets Python 2.7/3.x binary executable name (full path is required if its directory is not in PATH)."}, + { false, "-pythonVersion", 1, CL_KIND_STRING, 4, OT_WE | OT_WC, ppPythonVersion, NULL, "This parameter sets the Python version (2 or 3)." }, + { false, "-pylintOptions", 1, CL_KIND_STRING, 0, OT_WE | OT_WC, ppPylintOptions, NULL, "Passes command line options to Pylint. Options with arguments can be passed with successive -pylintOptions options."}, + { false, "-cleanResults", 1, CL_KIND_NUMBER, 0, OT_WE | OT_WC, ppCleanResults, NULL, "Cleans all but the last n number of timestamped result directory of the current project."}, + { false, "-runMetricHunter", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunMetricHunter, NULL, "This parameter turns on or off the MetricHunter module. With this feature, OpenStaticAnalyzer lists metric threshold violations. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-runPylint", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppPylint, NULL, "This parameter turns on or off the Pylint coding rule violation checking. With this feature, OpenStaticAnalyzer lists coding rule violations detected by Pylint. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\"."}, + { false, "-runDCF", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunDCF, NULL, "This parameter turns on or off the DuplicatedCodeFinder module. With this feature, OpenStaticAnalyzer identifies copy-pasted code fragments. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-runMET", 1, CL_KIND_BOOL, 0, OT_WE | OT_WC, ppRunMET, NULL, "This parameter turns on or off the Metric module. With this feature, OpenStaticAnalyzer computes source code metrics. Its value can be \"true\" (turn this feature on) or \"false\" (turn this feature off). The default value is \"true\""}, + { false, "-profileXML", 1, CL_KIND_FILE, 0, OT_WE | OT_WC, ppProfileXML, NULL, "Global configuration file for OpenStaticAnalyzer. Its 'tool-options' tag can be used to override the default metric thresholds for the MetricHunter tool. Furthermore, its 'rule-options' tag can enable/disable or modify the priorities of multiple rules."}, + CL_VERBOSE + CL_MESSAGELEVEL + CL_HELP + CL_VERSION + CL_LAST +}; + +#define DUMP_PROPERTY_PATH(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=[%s]\n", props.name.string().c_str()) +#define DUMP_PROPERTY_STRING(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=[%s]\n", props.name.c_str()) +#define DUMP_PROPERTY_INT(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=%d\n", props.name) +#define DUMP_PROPERTY_CHAR(name) WriteMsg::write(WriteMsg::mlDebug, " " #name "=%c\n", props.name) +#define DUMP_PROPERTY_STRING_LIST(name) { string val; for (const string& s : props.name) val += "[" + s + "]"; WriteMsg::write(WriteMsg::mlDebug, " " #name "=[%s]\n", val.c_str()); } + +void dumpProperties() { + DUMP_PROPERTY_PATH(startCurrentDir); + DUMP_PROPERTY_PATH(toolchainDir); + DUMP_PROPERTY_PATH(toolsDir); + DUMP_PROPERTY_PATH(resultsDir); + DUMP_PROPERTY_PATH(projectBaseDir); + DUMP_PROPERTY_PATH(currentDate); + DUMP_PROPERTY_PATH(projectResultDir); + DUMP_PROPERTY_PATH(projectTimedResultDir); + DUMP_PROPERTY_PATH(logDir); + DUMP_PROPERTY_PATH(tempDir); + DUMP_PROPERTY_PATH(asgDir); + DUMP_PROPERTY_PATH(externalHardFilter); + DUMP_PROPERTY_STRING(projectName); + DUMP_PROPERTY_INT(cloneGenealogy); + DUMP_PROPERTY_INT(maxThreads); + DUMP_PROPERTY_CHAR(csvSeparator); + DUMP_PROPERTY_CHAR(csvDecimalmark); + DUMP_PROPERTY_INT(cloneMinLines); + DUMP_PROPERTY_INT(cleanResults); + DUMP_PROPERTY_PATH(pythonBinary); + DUMP_PROPERTY_STRING(pythonVersion); + DUMP_PROPERTY_STRING_LIST(pylintOptions); + DUMP_PROPERTY_PATH(profileXML); + DUMP_PROPERTY_PATH(rulesCSV); + DUMP_PROPERTY_INT(runDCF); + DUMP_PROPERTY_INT(runPylint); + DUMP_PROPERTY_INT(runMetricHunter); + DUMP_PROPERTY_INT(runLimMetrics); +} + +bool checkIfBinaryInPackage(const string& toolName) { + return exists(props.toolsDir / (toolName + BINARYEXT)); +} + +void checkPython() { + if (props.pythonVersion.empty()) { + WriteMsg::write(WriteMsg::mlError, "Please set the python version of the analyzed software. Allowed values are: 2 and 3.\n"); + clError(); + } else if (props.pythonVersion != "2" && props.pythonVersion != "3") { + WriteMsg::write(WriteMsg::mlError, "Invalid Python version: %s. Allowed values are: 2 and 3. Please set it with the '-pythonVersion' option.\n", props.pythonVersion.c_str()); + clError(); + } + + if (props.pythonBinary.empty()) { + WriteMsg::write(WriteMsg::mlError, "Please set the python 2.7/3.x binary with '-pythonBinary' option.\n"); + clError(); + } + + string pyBin = props.pythonBinary.string(); + vector sv; + sv.push_back("--version"); + stringstream ss; + int ret = common::run(pyBin, sv, ss); + string outStr = ss.str(); + + if (ret != 0) { + WriteMsg::write(CMSG_PYTHON_BIN_ERROR); + exit(EXIT_FAILURE); + } + + { + static const boost::regex versionRegex("Python (\\d+)\\.(\\d+)"); + boost::smatch match; + + if (boost::regex_search(outStr, match, versionRegex)) { + string pythonReleaseVersion = match[1].str() + "." + match[2].str(); + + if (match[1].str() != props.pythonVersion) { + WriteMsg::write(WriteMsg::mlError, "The specified python version (%s) is not compatible with the python executable (%s).\n", props.pythonVersion.c_str(), pythonReleaseVersion.c_str()); + exit(EXIT_FAILURE); + } + + int pyMajor = common::str2int(match[1].str()); + int pyMinor = common::str2int(match[2].str()); + + if (!((pyMajor == 2 && pyMinor == 7) || pyMajor == 3)) { + WriteMsg::write(WriteMsg::mlError, "Required minimum python versions are 2.7 and 3.x.\n"); + exit(EXIT_FAILURE); + } + } + } +} + +void checkPylint() { + static const string OSA_PYLINT_VERSION = "1.8.2"; + + vector sv; + sv.push_back("-c"); + sv.push_back("import pylint; print(pylint.__version__);"); + stringstream ss; + + int ret = common::run(props.pythonBinary.string(), sv, ss); + if (ret != 0) { + WriteMsg::write(WriteMsg::mlWarning, "Warning: Failed to retrieve version of Pylint. The Pylint checker will not be executed.\n"); + props.runPylint = false; + return; + } + + string ver = ss.str(); + common::trim(ver); + + if (ver != OSA_PYLINT_VERSION) + WriteMsg::write(WriteMsg::mlWarning, "Warning: Expected version of Pylint is %s, found %s. Pylint results may be incomplete or incorrect.\n", OSA_PYLINT_VERSION.c_str(), ver.c_str()); +} + +void checkUserProperties() +{ + if(props.resultsDir.empty()) + { + WriteMsg::write(WriteMsg::mlError, "Please set the resultsDir parameter. Under this directory a new directory with the name of the analyzed project will be created, if it does not exist yet. All results will be stored there under separate directories with their names containing the date and time.\n"); + clError(); + } + + if(props.projectName.empty()) + { + WriteMsg::write(WriteMsg::mlError, "Please set the projectName parameter to the name of the analyzed software system.\n"); + clError(); + } + + if(props.projectBaseDir.empty()) + { + WriteMsg::write(WriteMsg::mlError, "Please set the projectBaseDir parameter. This is the directory that contains the source files you analyze.\n"); + clError(); + } + + if (!boost::filesystem::exists(props.projectBaseDir)) + { + WriteMsg::write(WriteMsg::mlError, "The directory given in the projectBaseDir parameter does not exist.\n"); + clError(); + } + + if (!is_directory(props.projectBaseDir)) + { + WriteMsg::write(WriteMsg::mlError, "The projectBaseDir parameter must be a directory.\n"); + clError(); + } + + checkPython(); + + if (props.runPylint) + checkPylint(); + + props.resultsDir = system_complete(props.resultsDir); + props.projectBaseDir = canonical(props.projectBaseDir).make_preferred(); + + if (props.currentDate.empty()) + props.currentDate = common::getCurrentTimeAndDate("%Y-%m-%d-%H-%M-%S"); // pattern="yyyy-MM-dd-HH-mm-ss" + + props.projectResultDir = props.resultsDir / props.projectName / "python"; + props.projectTimedResultDir = props.projectResultDir / props.currentDate; + + const path osaDir = "openstaticanalyzer"; + + props.logDir = props.projectTimedResultDir / osaDir / "log"; + props.tempDir = props.projectTimedResultDir / osaDir / "temp"; + props.asgDir = props.projectTimedResultDir / osaDir / "asg"; + props.graphDir = props.projectTimedResultDir / osaDir / "graph"; + + if ( !props.externalHardFilter.empty() ) + props.externalHardFilter = system_complete(props.externalHardFilter); + + if (props.maxThreads == 0) + props.maxThreads = columbus::thread::ThreadPool::getNumberOfCores(); + + if (props.cleanResults < -1) + props.cleanResults = -1; + + if (props.rulesCSV.empty()) + props.rulesCSV = props.toolsDir / "rules_python.csv"; + + props.runPylint = props.runPylint && checkIfBinaryInPackage("Pylint2Graph"); + props.runLimMetrics = props.runLimMetrics && checkIfBinaryInPackage("LIM2Metrics"); + props.runDCF = props.runDCF && checkIfBinaryInPackage("DuplicatedCodeFinder"); + props.runMetricHunter = props.runMetricHunter && checkIfBinaryInPackage("MetricHunter"); +} + + +void initializeProperties() { + props.startCurrentDir = current_path(); + + char* baseDir = std::getenv("CODE_ANALIZER_BASE_DIR"); + if ( baseDir ) { + props.toolchainDir = path(baseDir); + } else { + props.toolchainDir = path(common::getExecutableProgramDir()); + } + + props.toolsDir = props.toolchainDir / "Tools"; +} + +void makedirs() +{ + boost::system::error_code errorcode; + remove_all(props.projectTimedResultDir, errorcode); + if(errorcode.value() != boost::system::errc::success){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_DELETE_DIR, props.projectTimedResultDir.string().c_str(), errorcode.message().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.projectTimedResultDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.projectTimedResultDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.logDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.logDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.tempDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.tempDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.asgDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.asgDir.string().c_str()); + exit(EXIT_FAILURE); + } + if(!create_directories(props.graphDir)){ + WriteMsg::write(WriteMsg::mlError, CMSG_ERROR_CREATE_DIR, props.graphDir.string().c_str()); + exit(EXIT_FAILURE); + } +} + +int runAnalyzeMode() +{ + Controller ctrl(props); + + ctrl.addTask(new PANTask(props)); + ctrl.addTask(new PAN2LimTask(props)); + ctrl.addTask(new ProfileTask(props)); + + list inactives; + + if (props.runLimMetrics) + ctrl.addTask(new LIM2MetricsTask(props)); + else + inactives.push_back("LIM2Metrics"); + + if (props.runDCF) + ctrl.addTask(new DcfTask(props)); + else + inactives.push_back("DuplicatedCodeFinder"); + + if (props.runMetricHunter) + ctrl.addTask(new MetricHunterTask(props)); + else + inactives.push_back("MetricHunter"); + + if (props.runPylint) { + ctrl.addTask(new PylintTask(props)); + ctrl.addTask(new Pylint2GraphTask(props)); + } else + inactives.push_back("Pylint2Graph"); + + ctrl.addTask(new GraphMergeTask(props)); + + ctrl.addTask(new GraphDumpTask(props)); + + if (props.cleanResults != -1) + ctrl.addTask(new CleanResultsTask(props)); + + return ctrl.executeTasks(Controller::EM_FAIL_ON_ANY_ERROR); +} + + +int main(int argc, char* argv[]) +{ + int ret = 0; + MAIN_BEGIN + + WriteMsg::setAutomaticFlush(true); + + MainInit(argc, argv, "-"); + + initializeProperties(); + + checkUserProperties(); + dumpProperties(); + + makedirs(); + + ret = runAnalyzeMode(); + + MAIN_END + + return ret; +} + diff --git a/cl/PAN/CMakeLists.txt b/cl/PAN/CMakeLists.txt new file mode 100644 index 0000000..ec127b1 --- /dev/null +++ b/cl/PAN/CMakeLists.txt @@ -0,0 +1,43 @@ +set (PROGRAM_NAME PAN) + +set (SOURCES + src/main.cpp + src/PBuilder.cpp + src/plloc.cpp + src/PVisitor.cpp + src/VisitorImport.cpp + src/VisitorType.cpp + + inc/messages.h + inc/PBuilder.h + inc/PlLOC.h + inc/PVisitor.h + inc/VisitorImport.h + inc/VisitorType.h +) + + + +function (add_version_config VERSION) + string (FIND ${VERSION} "." DOT_POSITION) + string (SUBSTRING ${VERSION} 0 ${DOT_POSITION} PROGRAM_VERSION) + set (VERSIONED_PROGRAM_NAME ${PROGRAM_NAME}${PROGRAM_VERSION}) + add_executable(${VERSIONED_PROGRAM_NAME} ${SOURCES}) + add_dependencies(${VERSIONED_PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) + target_link_libraries(${VERSIONED_PROGRAM_NAME} python python${VERSION} common strtable csi io ${COMMON_EXTERNAL_LIBRARIES}) + target_compile_definitions(${VERSIONED_PROGRAM_NAME} PUBLIC Py_NO_ENABLE_SHARED ${ARGN}) + + if (CMAKE_SYSTEM_NAME STREQUAL Linux) + target_link_libraries(${VERSIONED_PROGRAM_NAME} pthread util dl rt) + elseif (CMAKE_SYSTEM_NAME STREQUAL Windows) + if (${PROGRAM_VERSION} STREQUAL "3") + target_link_libraries(${VERSIONED_PROGRAM_NAME} ${CMAKE_SOURCE_DIR}/3rdparty/python${PROGRAM_VERSION}/PC/external/${CMAKE_VS_PLATFORM_TOOLSET}/${PYTHON_PLATFORM_NAME}/Microsoft.VisualStudio.Setup.Configuration.Native.lib) + endif () + target_link_libraries(${VERSIONED_PROGRAM_NAME} version ws2_32) + endif () + + set_visual_studio_project_folder(${VERSIONED_PROGRAM_NAME} FALSE) +endfunction() + +add_version_config(2.7) +add_version_config(3.6 PY3) diff --git a/cl/PAN/inc/PBuilder.h b/cl/PAN/inc/PBuilder.h new file mode 100644 index 0000000..ec905e8 --- /dev/null +++ b/cl/PAN/inc/PBuilder.h @@ -0,0 +1,123 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __PBUILDER_H_ +#define __PBUILDER_H_ + +#include + +using namespace columbus; +using namespace columbus::python::asg; + +namespace columbus { + +class PBuilder { +private: + Factory* factory; + std::string path; + bool package_build; + +public: + + PBuilder(Factory* factory, bool package_build); + Factory* getFactory(); + + void setPath(std::string& path); + void setPosition(NodeId node, unsigned line, unsigned col, unsigned endline, unsigned endcol); + void setIncreasedPosition(NodeId node, unsigned line, unsigned col, unsigned endline, unsigned endcol); + + NodeId AddModule( NodeId module, NodeId package ); + void AddObjectRef( NodeId object, NodeId ref ); + NodeId findPackage( std::string name ); + + NodeId buildPackage( std::string name, std::vector& package ); + NodeId buildPackage( std::string name, NodeId parent = 0 ); + NodeId buildSuite( std::vector& body ); + NodeId buildModule( std::string name, NodeId docstring, std::vector& body, std::vector& object, int lloc ); + NodeId buildObject( std::string& name ); + NodeId buildBaseSpecifier( NodeId name ); + NodeId buildBreak( ); + NodeId buildTargetList( std::vector& list ); + NodeId buildRaise( NodeId type, NodeId value, NodeId traceback ); + NodeId buildParameter( std::string name, NodeId obj, ParameterKind kind ); + NodeId buildPrint( bool nl, NodeId dest, NodeId expression_list ); + NodeId buildPass( ); + NodeId buildAssert( NodeId test, NodeId msg ); + NodeId buildExec( NodeId expression, NodeId globals, NodeId locals ); + NodeId buildReturn( NodeId expression ); + NodeId buildIf( NodeId test, NodeId body, NodeId else_body ); + NodeId buildImportStatement( std::vector& names ); + NodeId buildImportFrom( std::vector& names, std::string module_name, int level ); + NodeId buildHandler( NodeId type, NodeId name, NodeId body ); + NodeId buildContinue( ); + NodeId buildDelete( NodeId list ); + NodeId buildAssign( NodeId list, NodeId expression ); + NodeId buildFunctionDef( std::string name, NodeId docstring, NodeId body, std::vector& parameter_list, std::vector& decorator_list, std::vector& local_object, NodeId object, int lloc ); + NodeId buildGlobal( std::vector& identifier ); + NodeId buildWith( NodeId body, NodeId target, NodeId expression ); + NodeId buildWhile( NodeId test, NodeId body, NodeId else_body ); + NodeId buildTryFinal( NodeId body, NodeId finally_body ); + NodeId buildAugAssign( NodeId target_list, NodeId expression, AssignmentKind kind ); + NodeId buildClassDef( std::string name, NodeId docstring, NodeId body, std::vector& base, std::vector& decorator_list, std::vector& local_object, NodeId object, int lloc ); + NodeId buildTryExcept( std::vector& handlerl, NodeId body, NodeId else_body ); + NodeId buildFor( NodeId target_list, NodeId body, NodeId else_body, NodeId expression_list ); + NodeId buildAlias( std::string name, std::string alias ); + NodeId buildKeyValue( NodeId key, NodeId value ); + NodeId buildIfExpression( NodeId test, NodeId body, NodeId else_body ); + NodeId buildExpressionList( std::vector& list, bool yield ); + NodeId buildStringLiteral( std::string value ); + NodeId buildDocstring( std::string value ); + NodeId buildComment( std::string value ); + NodeId buildKeyword( NodeId identifier, NodeId keyword ); + NodeId buildListComp( NodeId expression, std::vector& generators ); + NodeId buildIdentifier( std::string name, NodeId object ); + NodeId buildLambda( std::vector& parameter_list, std::vector& object_list, NodeId expression); + NodeId buildFloatNumber( float value ); + NodeId buildImagNumber( double im, double real ); + NodeId buildGeneratorExpression( NodeId expr, std::vector& generators ); + NodeId buildAttributeRef( NodeId identifier, NodeId primary ); + NodeId buildIntegerLiteral( int value ); + NodeId buildBinaryLogical( std::vector& operands, BinaryLogicalKind kind ); + NodeId buildSlice( NodeId upper_bound, NodeId lower_bound, NodeId stride ); + NodeId buildLongInteger( int value ); + NodeId buildCall( NodeId argument_list, NodeId primary ); + NodeId buildSubscription( NodeId slicing, NodeId primary ); + NodeId buildList( std::vector& expression_list, bool isTuple ); + NodeId buildBinaryArithmetic( NodeId left, NodeId right, BinaryArithmeticKind kind ); + NodeId buildUnaryOperation( NodeId expr, UnaryKind kind ); + NodeId buildExtSlice( std::vector& slice_item, NodeId primary ); + NodeId buildCompare( NodeId left, std::vector& operands, std::vector& kinds ); + NodeId buildStringConversion( NodeId expression_list ); + NodeId buildYield( NodeId expression_list ); + NodeId buildDictionary( std::vector& key_value_list ); + NodeId buildGenerator( NodeId identifier, NodeId iter, std::vector& ifexp ); + NodeId buildEllipsis( ); + NodeId buildIndex( NodeId value ); + NodeId buildArgumentList( NodeId list, std::vector& keyword_arg, NodeId dictionary_arg, NodeId tuple_arg ); + + // python 2.7 features + NodeId buildSet( std::vector& expression_list ); + NodeId buildSetComp( NodeId expression, std::vector& generators ); + NodeId buildDictComp( NodeId key_value, std::vector& generators ); + +}; +} + +#endif \ No newline at end of file diff --git a/cl/PAN/inc/PVisitor.h b/cl/PAN/inc/PVisitor.h new file mode 100644 index 0000000..702684c --- /dev/null +++ b/cl/PAN/inc/PVisitor.h @@ -0,0 +1,148 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __ASTVISITOR_H_ +#define __ASTVISITOR_H_ + +#ifdef PY3 +#include +#else +#include +#endif +#include "PBuilder.h" +#ifdef PY3 +#include +#else +#include +#endif +#include +#include +#include +#ifdef PY3 +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include "PlLOC.h" +#include +#include +#include + +using namespace columbus; +using namespace columbus::python::asg; + +namespace columbus { + +class ASTVisitor { + +private: + PBuilder& pBuilder; + std::vector logical_lines; + std::map assignment_map; + std::map arithmetic_map; + std::map comp_map; + std::map unary_map; + std::map<_boolop, BinaryLogicalKind> boolop_map; + + std::string path; + std::map object_map; + std::list< std::pair< std::map* , NodeKind > > objects; + std::list< std::multimap* > temp_objects; + std::list< std::map* > reverse_edge_objects; // decides if we should set a reverse edge from object to id + std::list< std::set* > global_list; + bool build_object; + bool collect_objects; + + std::map commentHolderCandidates; + +public: + ASTVisitor(PBuilder& pBuilder); + + Factory* Visit(std::string path_name, std::string modul_name, mod_ty root, std::vector& logical_lines, + std::map& commentMap ); + + std::map& getObjectMap(); + + PBuilder& getBuilder(); + +private: + + inline std::string getFunctionName(expr_ty name); + + inline std::vector visitStmtAsdl(asdl_seq* ch_list, NodeId docstring = 0); + + inline std::vector visitExceptHandlerAsdl(asdl_seq* ch_list); + + inline std::vector visitExprAsdl(asdl_seq* ch_list); + + inline std::vector visitIdentifierAsdl(asdl_seq* ch_list); + + inline std::vector visitBaseSpecifierAsdl(asdl_seq* ch_list); + + inline std::vector visitParameterListAsdl(arguments_ty arguments); + + inline std::vector visitAliasAsdl(asdl_seq* ch_list, stmt_ty parent); + + inline std::vector visitKeywordAsdl(asdl_seq* ch_list); + + inline std::vector visitComprehensionAsdl(asdl_seq* ch_list); + + inline std::vector< BinaryLogicalKind > visitCompAsdl(asdl_int_seq* ch_list); + + inline std::vector visitSliceAsdl(asdl_seq* ch_list); + + void buildLocalObjects(); + + NodeId visitMod(std::string modul_name, mod_ty parent); + + NodeId visitStmt(stmt_ty parent); + + NodeId visitExceptHandler(excepthandler_ty parent); + + NodeId visitExpr(expr_ty parent); + + NodeId visitSlice(slice_ty parent); + + NodeId createParamAndObject(std::string name, python::asg::ParameterKind kind, NodeId lastParam = 0); + + int getLLOC(int first_line, int last_line, std::vector logical_lines); + + NodeId getDocstring(asdl_seq* ch_list); + + void getOuterNodeInLine(NodeId id, int forcedLine = 0); + +}; +} + +#endif diff --git a/cl/PAN/inc/PlLOC.h b/cl/PAN/inc/PlLOC.h new file mode 100644 index 0000000..4ff38db --- /dev/null +++ b/cl/PAN/inc/PlLOC.h @@ -0,0 +1,54 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef LLOC_H +#define LLOC_H + +#include +#include +#include +#include +#include "PBuilder.h" + +namespace columbus { +class PlLOC { + +private: + int strreplace( std::string &str, const std::string &find_what, const std::string &replace_with); + std::string modifyEscapedChar( std::string str); + int findFirst( const std::string& line, std::vector what, std::string& significantChar, int from); + int strcount( std::string &str, const std::string &find_what, int endPos); + + std::string leftrim(std::string str); + + std::map commentMap; + +public: + PlLOC(){}; + + // return the logical lines of the file, process comments + std::vector processLines (const std::string &file, PBuilder& builder); + + std::map& getCommentMap(); + +}; +} + +#endif diff --git a/cl/PAN/inc/VisitorImport.h b/cl/PAN/inc/VisitorImport.h new file mode 100644 index 0000000..35e0e7d --- /dev/null +++ b/cl/PAN/inc/VisitorImport.h @@ -0,0 +1,82 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __VISITORIMPORT_H_ +#define __VISITORIMPORT_H_ + +#include +#include "VisitorType.h" +#include +#include +#include +#include + +using namespace columbus; +using namespace columbus::python::asg; + +namespace columbus { + +class VisitorImport : public VisitorAbstractNodes { +private: + Factory* factory; + NodeId import_scope; + NodeId package_id; + std::list< NodeId > scope; + std::list< NodeId > import_tree; + std::map< NodeId, std::set< std::pair< NodeId, std::string > > > import_graph; + std::map< NodeId, std::set< NodeId > >& type_set; + std::set< NodeId >& import_resolved; + +public: + + VisitorImport(Factory* factory, std::list< NodeId > import_tree, std::map< NodeId, std::set< NodeId > >& type_set, std::set< NodeId >& import_resolved): factory(factory), import_tree(import_tree), type_set(type_set), import_resolved(import_resolved){}; + +protected: + + void setType(module::Object& obj, type::Type& type); + + NodeId findModule(module::Package& package, std::string name); + NodeId getAssignValue(expression::Expression& target_list, expression::Expression& value, NodeId target); + std::set getAll(module::Module& module); + NodeId getObject(base::Base& current_scope, std::string name, bool create_object = false); + NodeId findObject(const std::string& name, ListIterator lit, ListIterator litEnd); + + void visit (const statement::ClassDef& n, bool); + void visitEnd(const statement::ClassDef& n, bool); + + void visit (const statement::FunctionDef& n, bool); + void visitEnd(const statement::FunctionDef& n, bool); + + void visit (const statement::ImportFrom& node, bool); + void visitEnd(const statement::ImportFrom& node, bool); + + void visit (const statement::ImportStatement& node, bool); + void visitEnd(const statement::ImportStatement& node, bool); + + void visit (const statement::Alias& n, bool); + void visitEnd(const statement::Alias& n, bool); + + void visit (const module::Module& n, bool); + void visitEnd(const module::Module& n, bool); + +}; +} + +#endif \ No newline at end of file diff --git a/cl/PAN/inc/VisitorType.h b/cl/PAN/inc/VisitorType.h new file mode 100644 index 0000000..f3bc3c1 --- /dev/null +++ b/cl/PAN/inc/VisitorType.h @@ -0,0 +1,175 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef __VISITORTYPE_H_ +#define __VISITORTYPE_H_ + +#include + +using namespace columbus; +using namespace columbus::python::asg; + +namespace columbus { +enum VisitedType{ + ExpressionsAndInit = 0, + Assignments = 1, + ExprAndAtrRef = 2, + ReturnAndBaseSpec = 3 +}; + +class VisitorType : public VisitorAbstractNodes { +private: + static std::map< NodeId, std::set > type_set; + + Factory* factory; + std::list< NodeId > module_scope; + std::list< NodeId > scope; + std::string attribute; + NodeId currentObject; + VisitedType filter; + std::set< NodeId > import_resolved; + +public: + VisitorType(Factory* factory, VisitedType filter): factory(factory), filter(filter) { + }; + +protected: + + void setType(module::Object& obj, type::Type& type); + void setType(expression::Expression& obj, type::Type& type); + void ListAssign(expression::List& target, expression::Expression& value); + void setAttributeType(const expression::AttributeRef& node, NodeId leftNodeId); + NodeId getObject(base::Base& current_scope, std::string name, bool create_object = false); + NodeId findObject(base::Base& base_scope, std::string name, bool top_level_only = false); + NodeId findObject(const std::string& name, ListIterator lit, ListIterator litEnd); + + void visit(const module::Module& node, bool); + void visitEnd(const module::Module& node, bool); + + void visit(const module::Package& node, bool); + void visitEnd(const module::Package& node, bool); + + void visit(const module::Object& node, bool); + void visitEnd(const module::Object& node, bool); + + void visit(const statement::ClassDef& node, bool); + void visitEnd(const statement::ClassDef& node, bool); + + void visit(const statement::FunctionDef& node, bool); + void visitEnd(const statement::FunctionDef& node, bool); + + void visit(const statement::BaseSpecifier& node, bool); + void visitEnd(const statement::BaseSpecifier& node, bool); + + void visit(const statement::Assign& node, bool); + void visitEnd(const statement::Assign& node, bool); + + void visit(const statement::Return& node, bool); + void visitEnd(const statement::Return& node, bool); + + void visit(const statement::TargetList& node, bool); + void visitEnd(const statement::TargetList& node, bool); + + void visit(const expression::List& node, bool); + void visitEnd(const expression::List& node, bool); + + void visit(const expression::KeyValue& node, bool); + void visitEnd(const expression::KeyValue& node, bool); + + void visit(const expression::Generator& node, bool); + void visitEnd(const expression::Generator& node, bool); + + void visit(const expression::GeneratorExpression& node, bool); + void visitEnd(const expression::GeneratorExpression& node, bool); + + void visit(const expression::Lambda& node, bool); + void visitEnd(const expression::Lambda& node, bool); + + void visit(const expression::Keyword& node, bool); + void visitEnd(const expression::Keyword& node, bool); + + void visit(const expression::BinaryLogical& node, bool); + void visitEnd(const expression::BinaryLogical& node, bool); + + void visit(const expression::IfExpression& node, bool); + void visitEnd(const expression::IfExpression& node, bool); + + void visit(const expression::ArgumentList& node, bool); + void visitEnd(const expression::ArgumentList& node, bool); + + void visit(const expression::StringConversion& node, bool); + void visitEnd(const expression::StringConversion& node, bool); + + void visit(const expression::UnaryOperation& node, bool); + void visitEnd(const expression::UnaryOperation& node, bool); + + void visit(const expression::AttributeRef& node, bool); + void visitEnd(const expression::AttributeRef& node, bool); + + void visit(const expression::Dictionary& node, bool); + void visitEnd(const expression::Dictionary& node, bool); + + void visit(const expression::Slicing& node, bool); + void visitEnd(const expression::Slicing& node, bool); + + void visit(const expression::Slice& node, bool); + void visitEnd(const expression::Slice& node, bool); + + void visit(const expression::BinaryArithmetic& node, bool); + void visitEnd(const expression::BinaryArithmetic& node, bool); + + void visit(const expression::Identifier& node, bool); + void visitEnd(const expression::Identifier& node, bool); + + void visit(const expression::ListComp& node, bool); + void visitEnd(const expression::ListComp& node, bool); + + void visit(const expression::ExpressionList& node, bool); + void visitEnd(const expression::ExpressionList& node, bool); + + void visit(const expression::Ellipsis& node, bool); + void visitEnd(const expression::Ellipsis& node, bool); + + void visit(const expression::ExtSlice& node, bool); + void visitEnd(const expression::ExtSlice& node, bool); + + void visit(const expression::Subscription& node, bool); + void visitEnd(const expression::Subscription& node, bool); + + void visit(const expression::Call& node, bool); + void visitEnd(const expression::Call& node, bool); + + void visit(const expression::Index& node, bool); + void visitEnd(const expression::Index& node, bool); + + void visit(const expression::LongInteger& node, bool); + + void visit(const expression::IntegerLiteral& node, bool); + + void visit(const expression::ImagNumber& node, bool); + + void visit(const expression::FloatNumber& node, bool); + + void visit(const expression::StringLiteral& node, bool); + +}; +} + +#endif \ No newline at end of file diff --git a/cl/PAN/inc/messages.h b/cl/PAN/inc/messages.h new file mode 100644 index 0000000..fcdb28e --- /dev/null +++ b/cl/PAN/inc/messages.h @@ -0,0 +1,81 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PAN_MESSAGE_H +#define _PAN_MESSAGE_H + +//main messages +#define CLARG_LST "List file for additional inputs" +#define CLARG_OUT "Output file" +#define CLARG_XML "Generate PML (XML) output" +#define CLARG_PREFIX "Remove the basepath prefix from all paths" +#define CLARG_PKG "Build packages according to directory structure." +#define CLARG_ANALYZE_PKG "Analyze python packages." +#define CLARG_IGNORE "List of file and directory names separated by colon which will be ignored during the analysis. Default: tests." +#define CLARG_PYBIN "Sets Python 2.7/3.x binary executable name (full path is required if its directory is not in PATH)." + +#define CMSG_NO_INPUT_FILES WriteMsg::mlWarning, "Warning: No input files\n" +#define CMSG_ONE_INPUT_REQ WriteMsg::mlError, "Error: Exactly 1 input directory is required, when analyzing packages\n" +#define CMSG_CANNOT_OPEN_LIST WriteMsg::mlError, "ERROR: Cannot open list file: \"%s\"\n" +#define CMSG_CANNOT_OPEN_FILE WriteMsg::mlError, "ERROR: Cannot open file: \"%s\"\n" +#define CMSG_PARSE_ERROR WriteMsg::mlError, "ERROR: Parser error.\n" +#define CMSG_NOT_PSI_EXTENSION WriteMsg::mlWarning, "WARNING: Extension of the output file is not '.psi': \"%s\"\n" +#define CMSG_WRONG_PATH_PREFIX WriteMsg::mlWarning, "WARNING: Wrong path prefix.\n" +#define CMSG_PARSING WriteMsg::mlNormal, "Parsing file: %s\n" +#define PATH_DOES_NOT_EXIST WriteMsg::mlWarning, "Warning: Path does not exist: %s\n" +#define ERROR_WHILE_COLLECTING_FILES WriteMsg::mlError, "Error: Error while collecting input files: %s\n" +#define CMSG_SAVING_ASG WriteMsg::mlNormal, "Saving ASG file: \"%s\"\n" +#define CMSG_CREATING_PML WriteMsg::mlNormal, "Creating pml dump: \"%s\"\n" +#define CMSG_FILTERED_FILE WriteMsg::mlDebug, "Debug: Filtered file: %s\n" +#define CMSG_PYTHON_BIN_UNSPEC WriteMsg::mlError, "Error: Python binary is not specified.\n" +#define CMSG_PYTHON_BIN_ERROR WriteMsg::mlError, "Error: Python 2.7/3.x binary is not found on PATH nor specified with '-pythonBinary' option correctly.\n" +#define CMSG_PY_PREFIX_ERROR WriteMsg::mlError, "Error: Failed to get prefix and exec_prefix values from python.\n" +#define CMSG_PAN_PY_COMPAT_ERROR WriteMsg::mlError, "Error: PAN python version (%s) is not compatible with the python executable (%s).\n" +#define CMSG_PY_LIB_NOT_FOUND WriteMsg::mlError, "Error: Couldn't found the python lib directory.\n" +#define CMSG_ERROR_ENVSET_FAILURE WriteMsg::mlError, "Error: Failed to set '%s' environment variable!\n" + +//PBuilder messages +#define CMSG_EX_WRONG_NUM_OP_OR_OP "Wrong number of operands or operators" +#define CMSG_EX_WRONG_NUM_OP "Wrong number of operands" + +//PVisitor messages +#define CMSG_EXCEPTION_AT WriteMsg::mlError, "Exception occurred at %s\n" +#define CMSG_POS WriteMsg::mlError, " %s (line:%d, col:%d)\n" +#define CMSG_ERROR WriteMsg::mlError, "ERROR: %s : %s\n" +#define CMSG_UNKNOWN_EXCEPTION WriteMsg::mlError, "Unknown exception at %s\n" + +//VisitorImport messages +#define CMSG_WRONG_PKG_LEVEL WriteMsg::mlDebug, "Debug: Wrong package level (%d) at ImportFrom node (%u).\n" +#define CMSG_IMPORT_MODULE WriteMsg::mlDDDebug, "\timport \"%s\" module.\n" + +//VisitorType messages +#define CMSG_EX_REDEFINITION(id) "Redefinition node type (node id:" + id + ")." + +#define CMSG_VISITING WriteMsg::mlDDDebug, "Visiting \"%s\" module.\n" + +#define CMSG_STATISTICS common::WriteMsg::mlNormal, "\nStatistics:\n\ +\tParsing time : %10.2fs\n\ +\tSaving asg time : %10.2fs\n\ +\tDumping pml time : %10.2fs\n\ +\tTotal time : %10.2fs\n\ +\tPeak memory usage : %10luMB\n\ +\tNumber of parser errors : %10d\n\n" + +#endif diff --git a/cl/PAN/src/PBuilder.cpp b/cl/PAN/src/PBuilder.cpp new file mode 100644 index 0000000..f4a95b1 --- /dev/null +++ b/cl/PAN/src/PBuilder.cpp @@ -0,0 +1,778 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/PBuilder.h" +#include "../inc/messages.h" +#include +#include + +using namespace std; + +PBuilder::PBuilder(Factory* factory, bool package_build): factory(factory), package_build(package_build){ +} + +Factory* PBuilder::getFactory(){ + return factory; +} + +void PBuilder::setPath(std::string& path) { + this->path = path; +} + +void PBuilder::setIncreasedPosition(NodeId id, unsigned line, unsigned col, unsigned endline, unsigned endcol){ + setPosition(id, line, col+1, endline, endcol); +} + +void PBuilder::setPosition(NodeId id, unsigned line, unsigned col, unsigned endline, unsigned endcol){ + base::Positioned& node = dynamic_cast(factory->getRef(id)); + node.setPosition(Range(factory->getStringTable(), path, line, col, endline, endcol)); +} + +NodeId PBuilder::findPackage( std::string name ){ + NodeId return_id = 0; + NodeId node_id = factory->getRoot()->getId(); + while(name.find_first_of("\\/") != std::string::npos){ + module::Package& package = dynamic_cast(factory->getRef(node_id)); + std::string pname = name.substr(0, name.find_first_of("\\/")); + if(pname.length() == 0){ + name = ""; + break; + } + ListIterator lit = package.getPackageListIteratorBegin(); + + bool find = false; + for(; lit != package.getPackageListIteratorEnd(); ++lit){ + const module::Package& chpackage = *lit; + if(pname.compare(chpackage.getName()) == 0){ + node_id = chpackage.getId(); + find = true; + break; + } + } + if(!find) + break; + size_t size = name.find_first_of("\\/")+1; + name = name.substr(size, name.length()-size); + } + if(name.find_first_of("\\/") == std::string::npos) + return_id = node_id; + + return return_id; +} + +NodeId PBuilder::buildPackage( std::string name, std::vector& packages ){ + NodeId node_id = factory->getRoot()->getId(); + std::string path; + while(name.find_first_of("\\/") != std::string::npos){ + module::Package& package = dynamic_cast(factory->getRef(node_id)); + std::string pname = name.substr(0, name.find_first_of("\\/")); + if(pname.length() == 0) + break; + + if (path.size() != 0) { + path += "/"; + } + path += pname; + std::string init_path = path + "/__init__.py"; + ifstream init(init_path.c_str()); + if(init.is_open() || package_build){ + ListIterator lit = package.getPackageListIteratorBegin(); + + bool build = true; + for(; lit != package.getPackageListIteratorEnd(); ++lit){ + const module::Package& chpackage = *lit; + if(pname.compare(chpackage.getName()) == 0){ + node_id = chpackage.getId(); + build = false; + break; + } + } + + if(build){ + module::Package& new_package = dynamic_cast(*factory->createNode(ndkPackage)); + + new_package.setName(pname); + package.addPackage(new_package.getId()); + node_id = new_package.getId(); + } + } + size_t size = name.find_first_of("\\/")+1; + name = name.substr(size, name.length()-size); + } + + module::Package& package = dynamic_cast(factory->getRef(node_id)); + for(vector::iterator it = packages.begin(); it != packages.end(); it++){ + package.addPackage(*it); + } + + return node_id; +} + +NodeId PBuilder::buildPackage( std::string name, NodeId parent ){ + module::Package& node = dynamic_cast(*factory->createNode(ndkPackage)); + node.setName(name); + if(parent != 0){ + module::Package& parnode = dynamic_cast(factory->getRef(parent)); + parnode.addPackage(node.getId()); + } + + return node.getId(); +} + +NodeId PBuilder::AddModule( NodeId module, NodeId package ){ + module::Package& node = dynamic_cast(factory->getRef(package)); + node.addModule(module); + return node.getId(); +} + +void PBuilder::AddObjectRef( NodeId object, NodeId ref ){ + module::Object& node = dynamic_cast(factory->getRef(object)); + node.addRefersTo(ref); +} + +NodeId PBuilder::buildSuite( std::vector& body ){ + statement::Suite& node = dynamic_cast(*factory->createNode(ndkSuite)); + + for(vector::iterator it = body.begin(); it != body.end(); it++){ + node.addStatement(*it); + } + + if (!body.empty()) { + base::Positioned& first = dynamic_cast(factory->getRef(body.front())); + base::Positioned& last = dynamic_cast(factory->getRef(body.back())); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + return node.getId(); +} + +NodeId PBuilder::buildModule( std::string name, NodeId docstring, std::vector& body, std::vector& object, int lloc ){ + module::Module& node = dynamic_cast(*factory->createNode(ndkModule)); + node.setName(name); + if (docstring){ + node.setDocstring(docstring); + } + for(vector::iterator it = body.begin(); it != body.end(); it++){ + node.addStatement(*it); + } + for(vector::iterator it = object.begin(); it != object.end(); it++){ + node.addObject(*it); + } + + node.setLloc(lloc); + + return node.getId(); +} + +NodeId PBuilder::buildObject( std::string& name ){ + module::Object& node = dynamic_cast(*factory->createNode(ndkObject)); + node.setName(name); + return node.getId(); +} + +NodeId PBuilder::buildBaseSpecifier( NodeId name ){ + statement::BaseSpecifier& node = dynamic_cast(*factory->createNode(ndkBaseSpecifier)); + if (name != 0) { + node.setName(name); + } + return node.getId(); +} + +NodeId PBuilder::buildBreak( ){ + statement::Break& node = dynamic_cast(*factory->createNode(ndkBreak)); + return node.getId(); +} + +NodeId PBuilder::buildTargetList( std::vector& list ){ + statement::TargetList& node = dynamic_cast(*factory->createNode(ndkTargetList)); + for(vector::iterator it = list.begin(); it != list.end(); it++){ + node.addTarget(*it); + } + + if (!list.empty()) { + base::Positioned& first = dynamic_cast(factory->getRef(list.front())); + base::Positioned& last = dynamic_cast(factory->getRef(list.back())); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + return node.getId(); +} + +NodeId PBuilder::buildRaise( NodeId type, NodeId value, NodeId traceback ){ + statement::Raise& node = dynamic_cast(*factory->createNode(ndkRaise)); + node.setTypeExpression(type); + node.setValueExpression(value); + node.setTracebackExpression(traceback); + return node.getId(); +} + +NodeId PBuilder::buildParameter( std::string name, NodeId obj, ParameterKind kind ){ + statement::Parameter& node = dynamic_cast(*factory->createNode(ndkParameter)); + node.setName(name); + node.setKind(kind); + if(obj != 0) node.setRefersTo(obj); + return node.getId(); +} + +NodeId PBuilder::buildPrint( bool nl, NodeId dest, NodeId expression_list ){ + statement::Print& node = dynamic_cast(*factory->createNode(ndkPrint)); + node.setNl(nl); + node.setExpressionList(expression_list); + node.setDestination(dest); + return node.getId(); +} + +NodeId PBuilder::buildPass( ){ + statement::Pass& node = dynamic_cast(*factory->createNode(ndkPass)); + return node.getId(); +} + +NodeId PBuilder::buildAssert( NodeId test, NodeId msg ){ + statement::Assert& node = dynamic_cast(*factory->createNode(ndkAssert)); + node.setTestExpression(test); + node.setMsgExpression(msg); + return node.getId(); +} + +NodeId PBuilder::buildExec( NodeId expression, NodeId globals, NodeId locals ){ + statement::Exec& node = dynamic_cast(*factory->createNode(ndkExec)); + node.setExpression(expression); + if(globals != 0) node.setGlobals(globals); + if(locals != 0) node.setLocals(locals); + return node.getId(); +} + +NodeId PBuilder::buildReturn( NodeId expression ){ + statement::Return& node = dynamic_cast(*factory->createNode(ndkReturn)); + node.setExpression(expression); + return node.getId(); +} + +NodeId PBuilder::buildIf( NodeId test, NodeId body, NodeId else_body ){ + statement::If& node = dynamic_cast(*factory->createNode(ndkIf)); + node.setBody(body); + if(else_body != 0) node.setElseBody(else_body); + node.setTestExpression(test); + return node.getId(); +} + +NodeId PBuilder::buildImportStatement( std::vector& names ){ + statement::ImportStatement& node = dynamic_cast(*factory->createNode(ndkImportStatement)); + for(vector::iterator it = names.begin(); it != names.end(); it++){ + node.addAlias(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildImportFrom( std::vector& names, std::string module_name, int level ){ + statement::ImportFrom& node = dynamic_cast(*factory->createNode(ndkImportFrom)); + for(vector::iterator it = names.begin(); it != names.end(); it++){ + node.addAlias(*it); + } + node.setModulname(module_name); + node.setLevel(level); + return node.getId(); +} + +NodeId PBuilder::buildHandler( NodeId type, NodeId name, NodeId body ){ + statement::Handler& node = dynamic_cast(*factory->createNode(ndkHandler)); + node.setExceptBody(body); + if(type != 0) node.setType(type); + if (name != 0) node.setName(name); + + return node.getId(); +} + +NodeId PBuilder::buildContinue( ){ + statement::Continue& node = dynamic_cast(*factory->createNode(ndkContinue)); + return node.getId(); +} + +NodeId PBuilder::buildDelete( NodeId list ){ + statement::Delete& node = dynamic_cast(*factory->createNode(ndkDelete)); + node.setTargetList(list); + return node.getId(); +} + +NodeId PBuilder::buildAssign( NodeId list, NodeId expression ){ + statement::Assign& node = dynamic_cast(*factory->createNode(ndkAssign)); + node.setTargetList(list); + node.setExpression(expression); + return node.getId(); +} + +NodeId PBuilder::buildFunctionDef( std::string name, NodeId docstring, NodeId body, std::vector& parameter_list, std::vector& decorator_list, std::vector& local_object, NodeId object, int lloc ){ + statement::FunctionDef& node = dynamic_cast(*factory->createNode(ndkFunctionDef)); + node.setBody(body); + node.setName(name); + if (docstring){ + node.setDocstring(docstring); + } + for(vector::iterator it = parameter_list.begin(); it != parameter_list.end(); it++){ + node.addParameter(*it); + } + for(vector::iterator it = decorator_list.begin(); it != decorator_list.end(); it++){ + node.addDecorator(*it); + } + for(vector::iterator it = local_object.begin(); it != local_object.end(); it++){ + node.addObject(*it); + } + + node.setLloc(lloc); + + node.setRefersTo(object); + + return node.getId(); +} + +NodeId PBuilder::buildGlobal( std::vector& identifier ){ + statement::Global& node = dynamic_cast(*factory->createNode(ndkGlobal)); + for(vector::iterator it = identifier.begin(); it != identifier.end(); it++){ + node.addIdentifier(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildWith( NodeId body, NodeId target, NodeId expression ){ + statement::With& node = dynamic_cast(*factory->createNode(ndkWith)); + node.setBody(body); + + vector targets; + if (target) targets.push_back(target); + node.setTargetList(buildTargetList(targets)); + + node.setExpression(expression); + return node.getId(); +} + +NodeId PBuilder::buildWhile( NodeId test, NodeId body, NodeId else_body ){ + statement::While& node = dynamic_cast(*factory->createNode(ndkWhile)); + node.setTestExpression(test); + node.setBody(body); + if(else_body != 0) node.setElseBody(else_body); + return node.getId(); +} + +NodeId PBuilder::buildTryFinal( NodeId body, NodeId finally_body ){ + statement::TryFinal& node = dynamic_cast(*factory->createNode(ndkTryFinal)); + node.setBody(body); + if(finally_body != 0) node.setFinallyBody(finally_body); + return node.getId(); +} + +NodeId PBuilder::buildAugAssign( NodeId target_list, NodeId expression, AssignmentKind kind ){ + statement::AugAssign& node = dynamic_cast(*factory->createNode(ndkAugAssign)); + node.setTargetList(target_list); + node.setExpression(expression); + node.setKind(kind); + return node.getId(); +} + +NodeId PBuilder::buildClassDef( std::string name, NodeId docstring, NodeId body, std::vector& base, std::vector& decorator_list, std::vector& local_object, NodeId object, int lloc ){ + statement::ClassDef& node = dynamic_cast(*factory->createNode(ndkClassDef)); + node.setBody(body); + node.setName(name); + if (docstring){ + node.setDocstring(docstring); + } + for(vector::iterator it = base.begin(); it != base.end(); it++){ + node.addBaseSpecifier(*it); + } + for(vector::iterator it = decorator_list.begin(); it != decorator_list.end(); it++){ + node.addDecorator(*it); + } + for(vector::iterator it = local_object.begin(); it != local_object.end(); it++){ + node.addObject(*it); + } + + node.setLloc(lloc); + + node.setRefersTo(object); + return node.getId(); +} + +NodeId PBuilder::buildTryExcept( std::vector& handlerl, NodeId body, NodeId else_body ){ + statement::TryExcept& node = dynamic_cast(*factory->createNode(ndkTryExcept)); + + for(vector::iterator it = handlerl.begin(); it != handlerl.end(); it++){ + node.addHandler(*it); + } + + if(body != 0) node.setBody(body); + if(else_body != 0) node.setElseBody(else_body); + return node.getId(); +} + +NodeId PBuilder::buildFor(NodeId target_list, NodeId body, NodeId else_body, NodeId expression_list ){ + statement::For& node = dynamic_cast(*factory->createNode(ndkFor)); + node.setBody(body); + if(else_body != 0) node.setElseBody(else_body); + node.setTargetList(target_list); + node.setExpressionList(expression_list); + return node.getId(); +} + +NodeId PBuilder::buildAlias( std::string name, std::string alias ){ + statement::Alias& node = dynamic_cast(*factory->createNode(ndkAlias)); + node.setName(name); + node.setAlias(alias); + return node.getId(); +} + +NodeId PBuilder::buildKeyValue( NodeId key, NodeId value ){ + expression::KeyValue& node = dynamic_cast(*factory->createNode(ndkKeyValue)); + node.setKey(key); + node.setValue(value); + + if (key != 0) + { + base::Positioned& first = dynamic_cast(factory->getRef(key)); + base::Positioned& last = dynamic_cast(factory->getRef(value)); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + return node.getId(); +} + +NodeId PBuilder::buildIfExpression( NodeId test, NodeId body, NodeId else_body ){ + expression::IfExpression& node = dynamic_cast(*factory->createNode(ndkIfExpression)); + node.setTest(test); + node.setBody(body); + node.setElseBody(else_body); + return node.getId(); +} + +NodeId PBuilder::buildExpressionList( std::vector& list, bool yield ){ + expression::ExpressionList& node = dynamic_cast(*factory->createNode(ndkExpressionList)); + node.setIsYieldExpression(yield); + for(vector::iterator it = list.begin(); it != list.end(); it++){ + node.addExpression(*it); + } + + if (!list.empty()) { + expression::Expression& first = dynamic_cast(factory->getRef(list.front())); + expression::Expression& last = dynamic_cast(factory->getRef(list.back())); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + return node.getId(); +} + +NodeId PBuilder::buildArgumentList( NodeId list, std::vector& keyword_arg, NodeId dictionary_arg, NodeId tuple_arg ){ + expression::ArgumentList& node = dynamic_cast(*factory->createNode(ndkArgumentList)); + if(list != 0) node.setPositionalArguments(list); + if(dictionary_arg != 0) node.setDictionary(dictionary_arg); + for(vector::iterator it = keyword_arg.begin(); it != keyword_arg.end(); it++){ + node.addKeyword(*it); + } + if(tuple_arg != 0) node.setTuple(tuple_arg); + + return node.getId(); +} + +NodeId PBuilder::buildStringLiteral( std::string value ){ + expression::StringLiteral& node = dynamic_cast(*factory->createNode(ndkStringLiteral)); + node.setValue(value); + return node.getId(); +} + +NodeId PBuilder::buildDocstring( std::string value ){ + base::Docstring& node = factory->createDocstring(); + node.setText(value); + return node.getId(); +} + +NodeId PBuilder::buildComment( std::string value ){ + base::Comment& node = dynamic_cast(factory->createComment()); + node.setText(value); + return node.getId(); +} + +NodeId PBuilder::buildKeyword( NodeId identifier, NodeId keyword ){ + expression::Keyword& node = dynamic_cast(*factory->createNode(ndkKeyword)); + node.setKey(identifier); + node.setValue(keyword); + return node.getId(); +} + +NodeId PBuilder::buildListComp( NodeId expression, std::vector& generators ){ + expression::ListComp& node = dynamic_cast(*factory->createNode(ndkListComp)); + node.setExpression(expression); + for(vector::iterator it = generators.begin(); it != generators.end(); it++){ + node.addGenerator(*it); + } + + if (!generators.empty()) { + base::Positioned& first = dynamic_cast(factory->getRef(generators.front())); + base::Positioned& last = dynamic_cast(factory->getRef(generators.back())); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + return node.getId(); +} + +NodeId PBuilder::buildIdentifier( std::string name, NodeId object ){ + expression::Identifier& node = dynamic_cast(*factory->createNode(ndkIdentifier)); + node.setName(name); + if(object != 0) + node.setRefersTo(object); + return node.getId(); +} + + +NodeId PBuilder::buildLambda( std::vector& parameter_list, std::vector& object_list, NodeId expression ){ + expression::Lambda& node = dynamic_cast(*factory->createNode(ndkLambda)); + if (Common::getIsExpression(factory->getRef(expression))) + node.setExpression(expression); + for(vector::iterator it = parameter_list.begin(); it != parameter_list.end(); it++){ + node.addParameter(*it); + } + for(vector::iterator it = object_list.begin(); it != object_list.end(); it++){ + node.addObject(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildFloatNumber( float value ){ + expression::FloatNumber& node = dynamic_cast(*factory->createNode(ndkFloatNumber)); + node.setValue(value); + return node.getId(); +} + +NodeId PBuilder::buildImagNumber( double im, double real ){ + expression::ImagNumber& node = dynamic_cast(*factory->createNode(ndkImagNumber)); + node.setIm(im); + node.setReal(real); + return node.getId(); +} + +NodeId PBuilder::buildGeneratorExpression( NodeId expr, std::vector& generators ){ + expression::GeneratorExpression& node = dynamic_cast(*factory->createNode(ndkGeneratorExpression)); + node.setExpression(expr); + for(vector::iterator it = generators.begin(); it != generators.end(); it++){ + node.addGenerator(*it); + } + + if (!generators.empty()) { + base::Positioned& first = dynamic_cast(factory->getRef(generators.front())); + base::Positioned& last = dynamic_cast(factory->getRef(generators.back())); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + return node.getId(); +} + +NodeId PBuilder::buildAttributeRef( NodeId identifier, NodeId primary ){ + expression::AttributeRef& node = dynamic_cast(*factory->createNode(ndkAttributeRef)); + node.setRightExpression(identifier); + if(primary != 0) node.setLeftExpression(primary); + return node.getId(); +} + +NodeId PBuilder::buildIntegerLiteral( int value ){ + expression::IntegerLiteral& node = dynamic_cast(*factory->createNode(ndkIntegerLiteral)); + node.setValue(value); + return node.getId(); +} + +NodeId PBuilder::buildBinaryLogical( std::vector& operands, BinaryLogicalKind kind ){ + size_t numOperands = operands.size(); + if (numOperands < 2) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_WRONG_NUM_OP); + + expression::BinaryLogical *expr = NULL; + expression::BinaryLogical *tmp = NULL; + for (size_t i = 1; i < numOperands; ++i) { + expr = dynamic_cast(factory->createNode(ndkBinaryLogical)); + if (tmp) + expr->setLeftExpression(tmp->getId()); + else + expr->setLeftExpression(operands[i-1]); + expr->setRightExpression(operands[i]); + expr->setKind(kind); + tmp = expr; + } + return expr->getId(); +} + +NodeId PBuilder::buildSlice( NodeId upper_bound, NodeId lower_bound, NodeId stride ){ + expression::Slice& node = dynamic_cast(*factory->createNode(ndkSlice)); + if(upper_bound != 0) node.setUpperBound(upper_bound); + if(lower_bound != 0) node.setLowerBound(lower_bound); + if(stride != 0) node.setStride(stride); + return node.getId(); +} + +NodeId PBuilder::buildLongInteger( int value ){ + expression::LongInteger& node = dynamic_cast(*factory->createNode(ndkLongInteger)); + node.setValue(value); + return node.getId(); +} + +NodeId PBuilder::buildCall( NodeId argument_list, NodeId primary ){ + expression::Call& node = dynamic_cast(*factory->createNode(ndkCall)); + node.setArgumentList(argument_list); + if(primary != 0) node.setExpression(primary); + return node.getId(); +} + +NodeId PBuilder::buildSubscription( NodeId slice, NodeId value ){ + expression::Subscription& node = dynamic_cast(*factory->createNode(ndkSubscription)); + node.setSlicing(slice); + if(value != 0) node.setExpression(value); + return node.getId(); +} + +NodeId PBuilder::buildList( vector& expression_list, bool isTuple ){ + expression::List& node = dynamic_cast(*factory->createNode(ndkList)); + node.setIsTuple(isTuple); + for(vector::iterator it = expression_list.begin(); it != expression_list.end(); it++){ + node.addExpression(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildBinaryArithmetic( NodeId left, NodeId right, BinaryArithmeticKind kind ){ + expression::BinaryArithmetic& node = dynamic_cast(*factory->createNode(ndkBinaryArithmetic)); + node.setLeftExpression(left); + node.setRightExpression(right); + node.setKind(kind); + return node.getId(); +} + +NodeId PBuilder::buildUnaryOperation( NodeId expr, UnaryKind kind ){ + expression::UnaryOperation& node = dynamic_cast(*factory->createNode(ndkUnaryOperation)); + node.setExpression(expr); + node.setKind(kind); + return node.getId(); +} + +NodeId PBuilder::buildExtSlice( vector& slice_item, NodeId primary ){ + expression::ExtSlice& node = dynamic_cast(*factory->createNode(ndkExtSlice)); + for(vector::iterator it = slice_item.begin(); it != slice_item.end(); it++){ + node.addItem(*it); + } + + if (!slice_item.empty()) { + base::Positioned& first = dynamic_cast(factory->getRef(slice_item.front())); + base::Positioned& last = dynamic_cast(factory->getRef(slice_item.back())); + + setPosition(node.getId(), first.getPosition().getLine(), first.getPosition().getCol(), last.getPosition().getEndLine(), last.getPosition().getEndCol()); + } + + if(primary != 0) node.setExpression(primary); + return node.getId(); +} + +NodeId PBuilder::buildCompare( NodeId left, std::vector& operands, std::vector& kinds ){ + size_t numOperands = operands.size(); + size_t numOps = kinds.size(); + if (numOperands == 0 || numOperands != numOps) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_WRONG_NUM_OP_OR_OP); + + expression::BinaryLogical *expr = NULL; + expression::BinaryLogical *tmp = NULL; + for (size_t i = 0; i < numOperands; ++i) { + expr = dynamic_cast(factory->createNode(ndkBinaryLogical)); + if (tmp) + expr->setLeftExpression(tmp->getId()); + else + expr->setLeftExpression(left); + expr->setRightExpression(operands[i]); + expr->setKind(kinds[i]); + tmp = expr; + } + return expr->getId(); +} + +NodeId PBuilder::buildStringConversion( NodeId expression_list ){ + expression::StringConversion& node = dynamic_cast(*factory->createNode(ndkStringConversion)); + node.setExpressionList(expression_list); + return node.getId(); +} + +NodeId PBuilder::buildYield( NodeId expression_list ){ + expression::YieldExpression& node = dynamic_cast(*factory->createNode(ndkYieldExpression)); + node.setYieldExpression(expression_list); + return node.getId(); +} + +NodeId PBuilder::buildDictionary( std::vector& key_value_list ){ + expression::Dictionary& node = dynamic_cast(*factory->createNode(ndkDictionary)); + for(vector::iterator it = key_value_list.begin(); it != key_value_list.end(); it++){ + node.addKeyValue(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildGenerator( NodeId identifier, NodeId iter, std::vector& ifexp ){ + expression::Generator& node = dynamic_cast(*factory->createNode(ndkGenerator)); + node.setTarget(identifier); + node.setIter(iter); + for(vector::iterator it = ifexp.begin(); it != ifexp.end(); it++){ + node.addCondition(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildEllipsis( ){ + expression::Ellipsis& node = dynamic_cast(*factory->createNode(ndkEllipsis)); + return node.getId(); +} + +NodeId PBuilder::buildIndex( NodeId value ){ + expression::Index& node = dynamic_cast(*factory->createNode(ndkIndex)); + node.setExpression(value); + return node.getId(); +} + +NodeId PBuilder::buildSet( std::vector& expression_list ) { + expression::Set& node = dynamic_cast(*factory->createNode(ndkSet)); + for (vector::iterator it = expression_list.begin(); it != expression_list.end(); ++it) { + node.addExpression(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildSetComp( NodeId expression, std::vector& generators ) { + expression::SetComp& node = dynamic_cast(*factory->createNode(ndkSetComp)); + if (expression) node.setExpression(expression); + for (vector::iterator it = generators.begin(); it != generators.end(); ++it) { + node.addGenerator(*it); + } + return node.getId(); +} + +NodeId PBuilder::buildDictComp( NodeId key_value, std::vector& generators ) { + expression::DictComp& node = dynamic_cast(*factory->createNode(ndkDictComp)); + if (key_value) node.setKeyValue(key_value); + for (vector::iterator it = generators.begin(); it != generators.end(); ++it) { + node.addGenerator(*it); + } + return node.getId(); +} + + diff --git a/cl/PAN/src/PVisitor.cpp b/cl/PAN/src/PVisitor.cpp new file mode 100644 index 0000000..6734e8f --- /dev/null +++ b/cl/PAN/src/PVisitor.cpp @@ -0,0 +1,1638 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/PVisitor.h" +#include "../inc/messages.h" +#include +#include +#include + +using namespace std; +using namespace common; + +#ifdef PY3 +#define PyString_AS_STRING PyUnicode_AsUTF8 +#endif + +#ifndef _DEBUG + +#define EXCEPTION_LOC_BEGIN \ + try { +#define EXCEPTION_LOC_END(location) \ +} catch (Exception e) { \ + WriteMsg::write(CMSG_EXCEPTION_AT, location); \ + WriteMsg::write(CMSG_POS, path.c_str(), parent->lineno, parent->col_offset); \ + WriteMsg::write(CMSG_ERROR, e.getLocation().c_str(), e.getMessage().c_str()); \ + exit(1); \ +} catch (...) { \ + WriteMsg::write(CMSG_UNKNOWN_EXCEPTION, location); \ + WriteMsg::write(CMSG_POS, path.c_str(), parent->lineno, parent->col_offset); \ + exit(1); \ +} \ + +#else + +#define EXCEPTION_LOC_BEGIN +#define EXCEPTION_LOC_END(location) + +#endif + + +ASTVisitor::ASTVisitor(PBuilder& pBuilder): pBuilder(pBuilder){ + assignment_map[Add] = askAdd; + assignment_map[Sub] = askSub; + assignment_map[Mult] = askMult; + assignment_map[Div] = askDiv; + assignment_map[Mod] = askMod; + assignment_map[Pow] = askPow; + assignment_map[LShift] = askLShift; + assignment_map[RShift] = askRShift; + assignment_map[BitOr] = askBitOr; + assignment_map[BitXor] = askBitXor; + assignment_map[BitAnd] = askBitAnd; + assignment_map[FloorDiv] = askFloorDiv; + + arithmetic_map[Add] = bakAddition; + arithmetic_map[Sub] = bakSubtraction; + arithmetic_map[Mult] = bakMultiplication; + arithmetic_map[Div] = bakDivision; + arithmetic_map[Mod] = bakModulo; + arithmetic_map[Pow] = bakPow; + arithmetic_map[LShift] = bakLShift; + arithmetic_map[RShift] = bakRShift; + arithmetic_map[BitOr] = bakBitOr; + arithmetic_map[BitXor] = bakBitXor; + arithmetic_map[BitAnd] = bakBitAnd; + arithmetic_map[FloorDiv] = bakFloorDivision; + + comp_map[Eq] = blkEq; + comp_map[NotEq] = blkNotEq; + comp_map[Lt] = blkLt; + comp_map[LtE] = blkLtE; + comp_map[Gt] = blkGt; + comp_map[GtE] = blkGtE; + comp_map[Is] = blkIs; + comp_map[IsNot] = blkIsNot; + comp_map[In] = blkIn; + comp_map[NotIn] = blkNotIn; + + boolop_map[And] = blkAnd; + boolop_map[Or] = blkOr; + + unary_map[Invert] = unkInvert; + unary_map[Not] = unkNot; + unary_map[UAdd] = unkPlus; + unary_map[USub] = unkMinus; + + build_object = false; + collect_objects = false; +} + +std::map& ASTVisitor::getObjectMap() { + return object_map; +} + +PBuilder& ASTVisitor::getBuilder() { + return pBuilder; +} + +std::string ASTVisitor::getFunctionName(expr_ty name) { + std::string ret; + + while(name->kind == Attribute_kind){ + if(ret.length() > 0) ret = std::string(PyString_AS_STRING(name->v.Attribute.attr)) + "." + ret; + else ret = std::string(PyString_AS_STRING(name->v.Attribute.attr)); + name = name->v.Attribute.value; + } + if(name->kind == Name_kind){ + if(ret.length() > 0) ret = "." + ret; + ret = std::string(PyString_AS_STRING(name->v.Name.id)) + ret; + } + + return ret; +} + +vector ASTVisitor::visitStmtAsdl(asdl_seq* ch_list, NodeId docstring) { + vector body; + int i = 0; + if (docstring) { + i++; + } + + if (ch_list != 0) { + for (; i < (ch_list->size); i++) { + body.push_back(visitStmt(static_cast(ch_list->elements[i]))); + } + } + return body; +} + +vector ASTVisitor::visitExceptHandlerAsdl(asdl_seq* ch_list) { + vector body; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + body.push_back(visitExceptHandler(static_cast(ch_list->elements[i]))); + } + } + return body; +} + +vector ASTVisitor::visitIdentifierAsdl(asdl_seq* ch_list) { + vector body; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + std::string str(PyString_AS_STRING(static_cast(ch_list->elements[i]))); + global_list.back()->insert(str); + body.push_back(pBuilder.buildIdentifier(str, 0)); // TODO:setPosition + } + } + return body; +} + +vector ASTVisitor::visitBaseSpecifierAsdl(asdl_seq* ch_list) { + vector bases; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + expr_ty expr = static_cast(ch_list->elements[i]); + + std::string str(""); + NodeId name = 0; + + if (expr->kind == Name_kind) { + name = visitExpr(expr); + str = std::string(PyString_AS_STRING(expr->v.Name.id)); + } else if (expr->kind == Attribute_kind) { + name = visitExpr(expr); + str = std::string(PyString_AS_STRING(expr->v.Attribute.attr)); // should build the whole attributeref structure - if needed at all + } else if (expr->kind == Call_kind) { + name = visitExpr(expr); + // finish edge + } else { + //FIXME if not name kind + } + + NodeId bsnodeid = pBuilder.buildBaseSpecifier(name); + pBuilder.setIncreasedPosition(bsnodeid, expr->lineno, expr->col_offset, expr->endline, expr->endcol); + object_map[bsnodeid] = str; + bases.push_back(bsnodeid); + } + } + return bases; +} + +vector ASTVisitor::visitExprAsdl(asdl_seq* ch_list) { + vector body; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + body.push_back(visitExpr(static_cast(ch_list->elements[i]))); + } + } + return body; +} + +NodeId ASTVisitor::createParamAndObject(std::string name, python::asg::ParameterKind kind, NodeId lastParam){ + NodeId objNid = pBuilder.buildObject(name); + NodeId param = pBuilder.buildParameter(name, objNid, kind); + + //FIXME: its wrong if the parameters are not on the same line + if (lastParam){ + base::Positioned& lastParamNode = static_cast(pBuilder.getFactory()->getRef(lastParam)); + int col = lastParamNode.getPosition().getEndCol() + 2; // +2 for ", " between the parameters + int endCol = col + name.length(); + pBuilder.setIncreasedPosition(param, lastParamNode.getPosition().getLine(), col, lastParamNode.getPosition().getEndLine(), endCol); + } + + objects.back().first->insert( pair(name,objNid) ); + + pBuilder.AddObjectRef(objNid, param); + return param; +} + +vector ASTVisitor::visitParameterListAsdl(arguments_ty arguments) { + vector body; + + asdl_seq* ch_list = arguments->args; + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { +#ifdef PY3 + arg_ty arg = static_cast(ch_list->elements[i]); + std::string name = PyString_AS_STRING(arg->arg); + + NodeId param = createParamAndObject(name, pmkNormal); + //pBuilder.setIncreasedPosition(param, arg->lineno, arg->col_offset, arg->endline, arg->endcol); + // TODO endline and endcol for "arg" type + pBuilder.setIncreasedPosition(param, arg->lineno, arg->col_offset, arg->lineno, arg->col_offset + name.size()); + body.push_back(param); +#else + expr_ty expr = static_cast(ch_list->elements[i]); + std::string name = ""; + if (expr->kind == Name_kind){ + name = PyString_AS_STRING(expr->v.Name.id); + } else { + // FIXME if not a name + // check ref 7.6. Function definitions + // e.g. def comp_args((a, b)=(3, 4)): + } + + NodeId param = createParamAndObject(name, pmkNormal); + pBuilder.setIncreasedPosition(param, expr->lineno, expr->col_offset, expr->endline, expr->endcol); + body.push_back(param); +#endif + } + } + + vector::iterator argItEnd = body.end(); + ch_list = arguments->defaults; + if (ch_list != 0) { + if (body.size() >= static_cast(arguments->defaults->size)) { + for (int i = static_cast(ch_list->size) - 1; i >= 0; --i) { + statement::Parameter& param = dynamic_cast(pBuilder.getFactory()->getRef(*(--argItEnd))); + param.setDefaultValue(visitExpr(static_cast(ch_list->elements[i]))); + } + } + } + +#ifndef PY3 + NodeId lastParam = 0; + if (!body.empty()){ + lastParam = body.back(); + } + + if (arguments->vararg){ + std::string varargName(PyString_AS_STRING(arguments->vararg)); + body.push_back(createParamAndObject(varargName, pmkVararg, lastParam)); + lastParam = body.back(); + } + + if(arguments->kwarg){ + std::string kwargName(PyString_AS_STRING(arguments->kwarg)); + body.push_back(createParamAndObject(kwargName, pmkKwarg, lastParam)); + } +#endif + + return body; +} + +vector ASTVisitor::visitAliasAsdl(asdl_seq* ch_list, stmt_ty parent) { + vector< NodeId > names; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + alias_ty al = static_cast(ch_list->elements[i]); + std::string name(PyString_AS_STRING(al->name)); + std::string asname; + if(al->asname != 0) asname = std::string(PyString_AS_STRING(al->asname)); + + NodeId aliasId = pBuilder.buildAlias(name, asname); + //FIXME: alias position + pBuilder.setIncreasedPosition(aliasId, parent->lineno, parent->col_offset, parent->endline, parent->endcol); + names.push_back(aliasId); + object_map[aliasId] = name; + } + } + return names; +} + +vector< BinaryLogicalKind > ASTVisitor::visitCompAsdl(asdl_int_seq* ch_list){ + vector< BinaryLogicalKind > comp; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + comp.push_back(comp_map[static_cast(ch_list->elements[i])]); + } + } + return comp; +} + +vector ASTVisitor::visitKeywordAsdl(asdl_seq* ch_list) { + vector body; + + if (ch_list != 0) { + int previousKeyWordEndLine = 0; + bool first = true; + for (int i = 0; i < (ch_list->size); i++) { + keyword_ty elem = static_cast(ch_list->elements[i]); +#ifdef PY3 + std::string name(elem->arg ? PyString_AS_STRING(elem->arg) : ""); +#else + std::string name(PyString_AS_STRING(elem->arg)); +#endif + NodeId identifier = pBuilder.buildIdentifier(name, 0); + NodeId value = visitExpr(elem->value); + NodeId keyw = pBuilder.buildKeyword(identifier, value); + body.push_back(keyw); + + //FIXME: the positions are estimated and if the key and the value not on the same line they are totally wrong + int keyWordStartLine; + if (first){ + keyWordStartLine = elem->value->lineno; + } else { + keyWordStartLine = previousKeyWordEndLine +1; + } + int keyWordStartCol = elem->value->col_offset - (name.length() +1 ); // +1 for the "=" + pBuilder.setIncreasedPosition(identifier, keyWordStartLine, keyWordStartCol, elem->value->endline, elem->value->col_offset -1); + pBuilder.setIncreasedPosition(keyw, keyWordStartLine, keyWordStartCol, elem->value->endline, elem->value->endcol); + + previousKeyWordEndLine = elem->value->endline; + first = false; + } + } + return body; +} + +vector ASTVisitor::visitComprehensionAsdl(asdl_seq* ch_list){ + vector body; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + comprehension_ty elem = static_cast(ch_list->elements[i]); + NodeId target = visitExpr(elem->target); + + NodeId iter = visitExpr(elem->iter); + vector ifs; + if(elem->ifs != 0){ + ifs = visitExprAsdl(elem->ifs); + } + + int line = elem->target->lineno; + int col = elem->target->col_offset - 4; // -4 for "for " + int endLine = elem->iter->endline; + int endCol = elem->iter->endcol; + + if (!ifs.empty()){ + base::Positioned& lastCond = static_cast(pBuilder.getFactory()->getRef(ifs.back())); + endLine = lastCond.getPosition().getEndLine(); + endCol = lastCond.getPosition().getEndCol(); + } + + NodeId gen = pBuilder.buildGenerator(target, iter, ifs); + pBuilder.setIncreasedPosition(gen, line, col, endLine, endCol); + + body.push_back(gen); + } + } + return body; +} + +vector ASTVisitor::visitSliceAsdl(asdl_seq* ch_list) { + vector body; + + if (ch_list != 0) { + for (int i = 0; i < (ch_list->size); i++) { + body.push_back(visitSlice(static_cast(ch_list->elements[i]))); + } + } + return body; +} + +void ASTVisitor::buildLocalObjects() { + for(std::multimap::iterator it = temp_objects.back()->begin(); it != temp_objects.back()->end(); ++it) { + std::string name = (*it).first; + std::map::iterator result = objects.back().first->find(name); + if (result == objects.back().first->end() && + global_list.back()->find(name) == global_list.back()->end()) { //id not in local list, nor in global, create local object + + NodeId objNid = pBuilder.buildObject(name); + objects.back().first->insert(pair(name, objNid)); + static_cast(pBuilder.getFactory()->getRef((*it).second)).setRefersTo(objNid); + pBuilder.AddObjectRef(objNid, (*it).second); + } else if (global_list.back()->find(name) != global_list.back()->end()) { // id in global list + std::map::iterator global_result = objects.front().first->find(name); + if (global_result == objects.front().first->end()) { // no actual global obj found, create global object + NodeId objNid = pBuilder.buildObject(name); + objects.front().first->insert(pair(name, objNid)); + static_cast(pBuilder.getFactory()->getRef((*it).second)).setRefersTo(objNid); + pBuilder.AddObjectRef(objNid, (*it).second); + } else { + // setRef id to module obj + static_cast(pBuilder.getFactory()->getRef((*it).second)).setRefersTo((*global_result).second); + std::map::iterator reverse_edge = reverse_edge_objects.front()->find((*it).second); + if (reverse_edge != reverse_edge_objects.front()->end()) { + if ((*reverse_edge).second) { + pBuilder.AddObjectRef((*global_result).second, (*it).second); + } + } + } + } else if (result != objects.back().first->end()) { // already existing local object, no global keyword + static_cast(pBuilder.getFactory()->getRef((*it).second)).setRefersTo((*result).second); + std::map::iterator reverse_edge = reverse_edge_objects.back()->find((*it).second); + if (reverse_edge != reverse_edge_objects.back()->end()) { + if ((*reverse_edge).second) { + pBuilder.AddObjectRef((*result).second, (*it).second); + } + } + } + } +} + +Factory* ASTVisitor::Visit(std::string path_name, std::string modul_name, mod_ty root, vector& llines, map& commentMap) { + + path = modul_name; + logical_lines = llines; + pBuilder.setPath(path_name); + commentHolderCandidates.clear(); + + size_t start = modul_name.find_last_of("/\\"); + size_t end = modul_name.find_last_of("."); + std::string name = modul_name.substr(start+1, end-start-1); + NodeId module = visitMod(name, root); + // if the last lines only has comments, than attach them to the module node + getOuterNodeInLine(module, static_cast(pBuilder.getFactory()->getRef(module)).getPosition().getEndLine() + 1); + vector body; + NodeId package = pBuilder.buildPackage(modul_name, body); + + pBuilder.AddModule(module, package); + + for (std::map::iterator commentIt = commentMap.begin(); commentIt != commentMap.end(); ++commentIt){ + int line = commentIt->first; + while(true){ + std::map::iterator candidate; + if ( ( candidate = commentHolderCandidates.find(line) ) == commentHolderCandidates.end()){ + ++line; + } else { + base::Positioned& pos = dynamic_cast(pBuilder.getFactory()->getRef(candidate->second)); + pos.addComments(commentIt->second); + break; + } + } + } + + return pBuilder.getFactory(); +} + +NodeId ASTVisitor::visitMod(std::string modul_name, mod_ty parent) { + asdl_seq * ch_list; + + NodeId parentNid = 0; + + switch (parent->kind) { + case Module_kind: + { + std::map local_objects; + std::set local_globals; + + objects.push_back( pair*, NodeKind>(&local_objects, ndkModule)); + global_list.push_back(&local_globals); + + ch_list = parent->v.Module.body; + + int realEndline = logical_lines.back(); + logical_lines.pop_back(); + + NodeId docstring = getDocstring(ch_list); + vector body = visitStmtAsdl(ch_list, docstring); // if the module has docstring, than don't need to build the first stringliteral + + std::vector object; + for(std::map::iterator it = local_objects.begin(); it != local_objects.end(); ++it){ + object.push_back((*it).second); + } + + int lloc = 0, endline = 1, endcol = 1, docSize = 0; + + if (!body.empty()) { + base::Positioned& last = static_cast(pBuilder.getFactory()->getRef(body.back())); + endline = last.getPosition().getEndLine(); + endcol = last.getPosition().getEndCol(); + } + + if (docstring){ + base::Docstring& doc = static_cast(pBuilder.getFactory()->getRef(docstring)); + docSize = doc.getPosition().getEndLine() - doc.getPosition().getLine() + 1; + + if (body.empty()){ // if the module only has a docstring, than the module's end position same as the docstring's end position + endline = doc.getPosition().getEndLine(); + endcol = doc.getPosition().getEndCol(); + } + } + + if (realEndline > endline) { + endline = realEndline; + endcol = 1; + } + + lloc = getLLOC(1, endline, logical_lines) - docSize; + parentNid = pBuilder.buildModule(modul_name, docstring, body, object, lloc ); + pBuilder.setPosition(parentNid, 1, 1, endline, endcol); + + objects.pop_back(); + global_list.pop_back(); + } + break; + case Interactive_kind: + case Expression_kind: + case Suite_kind: + default: + break; + } + + return parentNid; +} + +NodeId ASTVisitor::visitExceptHandler(excepthandler_ty parent) { + NodeId parentNid = 0; + asdl_seq * ch_list; + + switch (parent->kind) { + case ExceptHandler_kind: + { + ch_list = parent->v.ExceptHandler.body; + vector body = visitStmtAsdl(ch_list); + NodeId suiteNid = pBuilder.buildSuite(body); + NodeId name = 0; + + if (parent->v.ExceptHandler.name != 0) { +#ifdef PY3 + std::string str(PyString_AS_STRING(parent->v.ExceptHandler.name)); + name = pBuilder.buildIdentifier(str, 0); +#else + name = visitExpr(parent->v.ExceptHandler.name); +#endif + } + + NodeId type = visitExpr(parent->v.ExceptHandler.type); + + parentNid = pBuilder.buildHandler(type, name, suiteNid); + + statement::Statement& last = static_cast(pBuilder.getFactory()->getRef(body.back())); + unsigned endline = last.getPosition().getEndLine(); + unsigned endcol = last.getPosition().getEndCol(); + pBuilder.setIncreasedPosition(parentNid, parent->lineno, parent->col_offset, endline, endcol); + } + } + + + return parentNid; +} + + +NodeId ASTVisitor::visitStmt(stmt_ty parent) { + asdl_seq * ch_list; + NodeId parentNid = 0; + + if (parent == 0) { + return parentNid; + } + + EXCEPTION_LOC_BEGIN + + switch (parent->kind) { + case FunctionDef_kind: + { + std::map local_objects; + std::set local_globals; + std::map local_build_objects; + std::multimap temp_local_objects; + vector decorator_list; + + objects.push_back(pair*, NodeKind>(&local_objects, ndkFunctionDef)); + temp_objects.push_back(&temp_local_objects); + global_list.push_back(&local_globals); + reverse_edge_objects.push_back(&local_build_objects); + + NodeId suiteNid = 0; + std::string str; + + arguments_ty temp = parent->v.FunctionDef.args; + vector args; + if (temp != 0) { + args = visitParameterListAsdl(temp); + } + + ch_list = parent->v.FunctionDef.body; + bool prev_state = collect_objects; + collect_objects = true; + + NodeId docstring = getDocstring(ch_list); + vector body = visitStmtAsdl(ch_list, docstring); + collect_objects = prev_state; + suiteNid = pBuilder.buildSuite(body); + + identifier tempx = parent->v.FunctionDef.name; + if (tempx != 0) { + str.assign(PyString_AS_STRING(tempx)); + } + + ch_list = parent->v.FunctionDef.decorator_list; + if (ch_list != 0) { + decorator_list = visitExprAsdl(parent->v.FunctionDef.decorator_list); + } + + buildLocalObjects(); + + std::vector object; + for(std::map::iterator it = local_objects.begin(); it != local_objects.end(); ++it){ + object.push_back((*it).second); + } + + objects.pop_back(); + temp_objects.pop_back(); + global_list.pop_back(); + reverse_edge_objects.pop_back(); + + NodeId objNid = 0; + if( objects.back().first->find(str) == objects.back().first->end() ){ + objNid = pBuilder.buildObject(str); + objects.back().first->insert( pair(str,objNid) ); + }else{ + std::map::iterator it = objects.back().first->find(str); + objNid = (*it).second; + } + + parentNid = pBuilder.buildFunctionDef(str, docstring, suiteNid, args, decorator_list, object, objNid, 0); + pBuilder.AddObjectRef(objNid, parentNid); + } + break; + case ClassDef_kind: + { + vector decorator_list; + std::map local_objects; + std::set local_globals; + std::map local_build_objects; + std::multimap temp_local_objects; + + objects.push_back(pair*, NodeKind>(&local_objects, ndkClassDef)); + temp_objects.push_back(&temp_local_objects); + global_list.push_back(&local_globals); + reverse_edge_objects.push_back(&local_build_objects); + + ch_list = parent->v.ClassDef.body; + bool prev_state = collect_objects; + collect_objects = true; + + NodeId docstring = getDocstring(ch_list); + vector body = visitStmtAsdl(ch_list, docstring); + collect_objects = prev_state; + NodeId suiteNid = pBuilder.buildSuite(body); + + vector bases; + if(parent->v.ClassDef.bases != 0) { + bases = visitBaseSpecifierAsdl(parent->v.ClassDef.bases); + } + + std::string name(PyString_AS_STRING(parent->v.ClassDef.name)); + + ch_list = parent->v.ClassDef.decorator_list; + if (ch_list != 0) { + decorator_list = visitExprAsdl(parent->v.ClassDef.decorator_list); + } + + buildLocalObjects(); + + std::vector object; + for(std::map::iterator it = local_objects.begin(); it != local_objects.end(); ++it){ + object.push_back((*it).second); + } + + objects.pop_back(); + temp_objects.pop_back(); + global_list.pop_back(); + reverse_edge_objects.pop_back(); + + NodeId objNid = 0; + if( objects.back().first->find(name) == objects.back().first->end() ){ + objNid = pBuilder.buildObject(name); + objects.back().first->insert( pair(name,objNid) ); + }else{ + std::map::iterator it = objects.back().first->find(name); + objNid = (*it).second; + } + + parentNid = pBuilder.buildClassDef(name, docstring, suiteNid, bases, decorator_list, object, objNid, 0 ); + pBuilder.AddObjectRef(objNid, parentNid); + } + break; + case Return_kind: + { + NodeId exp = 0; + if (parent->v.Return.value) { + exp = visitExpr(parent->v.Return.value); + } + parentNid = pBuilder.buildReturn(exp); + } + break; + case Delete_kind: + { + vector list = visitExprAsdl(parent->v.Delete.targets); + NodeId tglist = pBuilder.buildTargetList(list); + + parentNid = pBuilder.buildDelete(tglist); + } + break; + case Assign_kind: + { + bool prev_state = build_object; + build_object = true; + vector list = visitExprAsdl(parent->v.Assign.targets); + NodeId tglist = pBuilder.buildTargetList(list); + + build_object = false; + + bool prev_collect_state = collect_objects; + collect_objects = false; + NodeId value = visitExpr(parent->v.Assign.value); + parentNid = pBuilder.buildAssign(tglist, value); + + collect_objects = prev_collect_state; + build_object = prev_state; + } + break; + case AugAssign_kind: + { + NodeId target = visitExpr(parent->v.AugAssign.target); + vector list; + list.push_back(target); + NodeId tglist = pBuilder.buildTargetList(list); + NodeId value = visitExpr(parent->v.AugAssign.value); + + parentNid = pBuilder.buildAugAssign(tglist, value, assignment_map[parent->v.AugAssign.op]); + } + break; +#ifndef PY3 + case Print_kind: + { + ch_list = parent->v.Print.values; + NodeId dest = visitExpr(parent->v.Print.dest); + vector args = visitExprAsdl(ch_list); + NodeId expl = pBuilder.buildExpressionList(args, false); + + parentNid = pBuilder.buildPrint(parent->v.Print.nl, dest, expl); + } + break; +#endif + case For_kind: + { + bool prev_state = build_object; + build_object = false; + + ch_list = parent->v.For.body; + vector bodyl = visitStmtAsdl(ch_list); + NodeId body = pBuilder.buildSuite(bodyl); + + ch_list = parent->v.For.orelse; + NodeId elsebody = 0; + if(ch_list != 0){ + vector elsebodyl = visitStmtAsdl(ch_list); + elsebody = pBuilder.buildSuite(elsebodyl); + } + + build_object = true; + NodeId target = visitExpr(parent->v.For.target); + build_object = false; + vector target_list; + target_list.push_back(target); + NodeId targetl = pBuilder.buildTargetList(target_list); + + NodeId expression = visitExpr(parent->v.For.iter); + vector expression_list; + expression_list.push_back(expression); + NodeId expressionl = pBuilder.buildExpressionList(expression_list, false); + + parentNid = pBuilder.buildFor(targetl, body, elsebody, expressionl); + + build_object = prev_state; + } + break; + case While_kind: + { + ch_list = parent->v.While.body; + vector bodyl = visitStmtAsdl(ch_list); + NodeId body = pBuilder.buildSuite(bodyl); + + ch_list = parent->v.While.orelse; + NodeId elsebody = 0; + if(ch_list != 0){ + vector elsebodyl = visitStmtAsdl(ch_list); + elsebody = pBuilder.buildSuite(elsebodyl); + } + + NodeId expression = visitExpr(parent->v.While.test); + + parentNid = pBuilder.buildWhile(expression, body, elsebody); + } + break; + case If_kind: + { + ch_list = parent->v.If.body; + vector bodyl = visitStmtAsdl(ch_list); + NodeId body = pBuilder.buildSuite(bodyl); + + ch_list = parent->v.If.orelse; + NodeId elsebody = 0; + if(ch_list != 0){ + vector elsebodyl = visitStmtAsdl(ch_list); + elsebody = pBuilder.buildSuite(elsebodyl); + } + + NodeId expression = visitExpr(parent->v.If.test); + + parentNid = pBuilder.buildIf(expression, body, elsebody); + } + break; + case With_kind: + { + NodeId body = 0; + ch_list = parent->v.With.body; + if(ch_list != 0) { + vector bodyl = visitStmtAsdl(ch_list); + body = pBuilder.buildSuite(bodyl); + } + +#ifdef PY3 + NodeId context_expr = 0; + NodeId optional_vars = 0; +#else + NodeId context_expr = visitExpr(parent->v.With.context_expr); + NodeId optional_vars = visitExpr(parent->v.With.optional_vars); +#endif + + parentNid = pBuilder.buildWith(body, optional_vars, context_expr); + + } + break; + case Raise_kind: + { +#ifdef PY3 + NodeId type = 0; + NodeId traceback = 0; + NodeId value = 0; +#else + NodeId type = visitExpr(parent->v.Raise.type); + NodeId traceback = visitExpr(parent->v.Raise.tback); + NodeId value = visitExpr(parent->v.Raise.inst); +#endif + parentNid = pBuilder.buildRaise(type, value, traceback); + } + break; +#ifdef PY3 + case Try_kind: + { + NodeId body = 0, orelse = 0; + vector handlerl; + + ch_list = parent->v.Try.body; + if (ch_list != 0) { + vector bodyl = visitStmtAsdl(ch_list); + body = pBuilder.buildSuite(bodyl); + } + + ch_list = parent->v.Try.handlers; + if (ch_list != 0) { + handlerl = visitExceptHandlerAsdl(ch_list); + } + + ch_list = parent->v.Try.orelse; + if (ch_list != 0) { + vector orelsel = visitStmtAsdl(ch_list); + orelse = pBuilder.buildSuite(orelsel); + } + + parentNid = pBuilder.buildTryExcept(handlerl, body, orelse); + } + break; +#else + case TryExcept_kind: + { + NodeId body = 0, orelse = 0; + vector handlerl; + + ch_list = parent->v.TryExcept.body; + if(ch_list != 0) { + vector bodyl = visitStmtAsdl(ch_list); + body = pBuilder.buildSuite(bodyl); + } + + ch_list = parent->v.TryExcept.handlers; + if(ch_list != 0) { + handlerl = visitExceptHandlerAsdl(ch_list); + } + + ch_list = parent->v.TryExcept.orelse; + + if(ch_list != 0) { + vector orelsel = visitStmtAsdl(ch_list); + orelse = pBuilder.buildSuite(orelsel); + } + + + parentNid = pBuilder.buildTryExcept(handlerl, body, orelse); + } + break; + case TryFinally_kind: + { + NodeId body = 0, finally_body = 0; + ch_list = parent->v.TryFinally.body; + if(ch_list != 0) { + vector bodyl = visitStmtAsdl(ch_list); + body = pBuilder.buildSuite(bodyl); + } + + ch_list = parent->v.TryFinally.finalbody; + if(ch_list != 0) { + vector finally_bodyl = visitStmtAsdl(ch_list); + finally_body = pBuilder.buildSuite(finally_bodyl); + } + + parentNid = pBuilder.buildTryFinal(body, finally_body); + + } + break; +#endif + case Assert_kind: + { + NodeId message = visitExpr(parent->v.Assert.msg); + NodeId test = visitExpr(parent->v.Assert.test); + + parentNid = pBuilder.buildAssert(test, message); + } + break; + case Import_kind: + { + vector< NodeId > names = visitAliasAsdl(parent->v.Import.names, parent); + parentNid = pBuilder.buildImportStatement(names); + } + break; + case ImportFrom_kind: + { + vector< NodeId > names = visitAliasAsdl(parent->v.ImportFrom.names, parent); + + int level = parent->v.ImportFrom.level; + std::string modulename = ""; + if (parent->v.ImportFrom.module) + modulename = PyString_AS_STRING(parent->v.ImportFrom.module); + parentNid = pBuilder.buildImportFrom(names, modulename, level); + } + break; +#ifndef PY3 + case Exec_kind: + { + NodeId body = visitExpr(parent->v.Exec.body); + NodeId globals = visitExpr(parent->v.Exec.globals); + NodeId locals = visitExpr(parent->v.Exec.locals); + parentNid = pBuilder.buildExec(body, globals, locals); + } + break; +#endif + case Global_kind: + { + ch_list = parent->v.Global.names; + vector args = visitIdentifierAsdl(ch_list); + + //fixme: better solution? + int offset = parent->col_offset + 7; // +7 for: "global " + for (vector::iterator beginIt = args.begin(); beginIt != args.end(); ++beginIt){ + expression::Identifier& id = dynamic_cast(pBuilder.getFactory()->getRef(*beginIt)); + int nameSize = id.getName().size(); + pBuilder.setIncreasedPosition(id.getId(), parent->lineno, offset, parent->lineno, offset + nameSize); + offset += nameSize + 2; // +2 for: ", " + } + + parentNid = pBuilder.buildGlobal(args); + } + break; + case Expr_kind: + { + parentNid = visitExpr(parent->v.Expr.value); + } + break; + case Pass_kind: + { + parentNid = pBuilder.buildPass(); + } + break; + case Break_kind: + { + parentNid = pBuilder.buildBreak(); + } + break; + case Continue_kind: + { + parentNid = pBuilder.buildContinue(); + } + break; +#ifdef PY3 + default: + parentNid = pBuilder.buildPass(); + break; +#endif + } + + int endLine = parent->endline; + int endCol = parent->endcol; + + statement::Suite* body = 0; + base::Base& node = pBuilder.getFactory()->getRef(parentNid); + + if (Common::getIsClassDef(node)){ + statement::ClassDef& stm = static_cast(node); + body = stm.getBody(); + int defEndLine = 0, defEndCol = 0; + if (body->getStatementIsEmpty()){ + if (stm.getDocstring()){ // if the body is empty bot the definition has a docstring + defEndLine = stm.getDocstring()->getPosition().getEndLine(); + defEndCol = stm.getDocstring()->getPosition().getEndCol(); + } + } else { + defEndLine = body->getPosition().getEndLine(); + defEndCol = body->getPosition().getEndCol(); + } + pBuilder.setIncreasedPosition(parentNid, parent->lineno, parent->col_offset, defEndLine, defEndCol); + } else if (Common::getIsFunctionDef(node) ){ + statement::FunctionDef& stm = static_cast(node); + body = stm.getBody(); + int defEndLine = 0, defEndCol = 0; + if (body->getStatementIsEmpty()){ + if (stm.getDocstring()){ // if the body is empty bot the definition has a docstring + defEndLine = stm.getDocstring()->getPosition().getEndLine(); + defEndCol = stm.getDocstring()->getPosition().getEndCol(); + } + } else { + defEndLine = body->getPosition().getEndLine(); + defEndCol = body->getPosition().getEndCol(); + } + pBuilder.setIncreasedPosition(parentNid, parent->lineno, parent->col_offset, defEndLine, defEndCol); + } else { + if ( Common::getIsWith(node)){ + statement::CompoundStatement& stm = static_cast(node); + body = stm.getBody(); + } + + if (Common::getIsIf(node)){ + statement::If& ifStm = static_cast(node); + if (ifStm.getElseBody()){ + body = ifStm.getElseBody(); + } else { + body = ifStm.getBody(); + } + } + + if (Common::getIsIteration(node)){ + statement::Iteration& iterStm = static_cast(node); + if (iterStm.getElseBody()){ + body = iterStm.getElseBody(); + } else { + body = iterStm.getBody(); + } + } + + if (Common::getIsTryFinal(node)){ + statement::TryFinal& tryFinal = static_cast(node); + body = tryFinal.getFinallyBody(); + } + + if (Common::getIsTryExcept(node)){ + statement::TryExcept& tryExcept = static_cast(node); + if (tryExcept.getFinallyBody()) { + body = tryExcept.getFinallyBody(); + } else if (tryExcept.getElseBody()) { + body = tryExcept.getElseBody(); + } else if (!tryExcept.getHandlerIsEmpty()) { + python::asg::ListIterator handlerItEnd = tryExcept.getHandlerListIteratorEnd(); + --handlerItEnd; + body = handlerItEnd->getExceptBody(); + } + } + + if (body){ + endLine = body->getPosition().getEndLine(); + endCol = body->getPosition().getEndCol(); + } + + pBuilder.setIncreasedPosition(parentNid, parent->lineno, parent->col_offset, endLine, endCol); + } + + if (Common::getIsFunctionDef(node)){ + statement::FunctionDef& func = static_cast(node); + int docLength = 0; + if (func.getDocstring()){ + base::Docstring& doc = *func.getDocstring(); + docLength = doc.getPosition().getEndLine()-doc.getPosition().getLine()+1; + } + func.setLloc(getLLOC(func.getPosition().getLine(), func.getPosition().getEndLine(), logical_lines) - docLength); + } + + if (Common::getIsClassDef(node)){ + statement::ClassDef& cls = static_cast(node); + int docLength = 0; + if (cls.getDocstring()){ + base::Docstring& doc = *cls.getDocstring(); + docLength = doc.getPosition().getEndLine()-doc.getPosition().getLine()+1; + } + cls.setLloc(getLLOC(cls.getPosition().getLine(), cls.getPosition().getEndLine(), logical_lines) - docLength); + } + + getOuterNodeInLine(parentNid); + + EXCEPTION_LOC_END("ASTVisitor::visitStmt()") + + return parentNid; +} + +NodeId ASTVisitor::visitExpr(expr_ty parent) { + NodeId parentNid = 0; + + if (parent == 0) { + return parentNid; + } + + EXCEPTION_LOC_BEGIN + + switch (parent->kind) { + case BoolOp_kind: + { + vector values = visitExprAsdl(parent->v.BoolOp.values); + + parentNid = pBuilder.buildBinaryLogical(values, boolop_map[parent->v.BoolOp.op]); + } + break; + case BinOp_kind: + { + NodeId left = visitExpr(parent->v.BinOp.left); + NodeId right = visitExpr(parent->v.BinOp.right); + + parentNid = pBuilder.buildBinaryArithmetic(left, right, arithmetic_map[parent->v.BinOp.op]); + } + break; + case UnaryOp_kind: + { + NodeId operand = visitExpr(parent->v.UnaryOp.operand); + + parentNid = pBuilder.buildUnaryOperation(operand, unary_map[parent->v.UnaryOp.op]); + } + break; + case Lambda_kind: + { + std::map local_objects; + objects.push_back( pair*, NodeKind>(&local_objects, ndkLambda)); + + vector args = visitParameterListAsdl(parent->v.Lambda.args); + + NodeId body = visitExpr(parent->v.Lambda.body); + + std::map* lastMap = objects.back().first; + + vector lambda_object_list; + for (vector::iterator argsBegin = args.begin() ; argsBegin != args.end(); ++argsBegin){ + std::string paramName = dynamic_cast(pBuilder.getFactory()->getRef(*argsBegin)).getName(); + lambda_object_list.push_back(lastMap->find(paramName)->second); + } + objects.pop_back(); + parentNid = pBuilder.buildLambda(args, lambda_object_list, body); + } + break; + case IfExp_kind: + { + NodeId test = visitExpr(parent->v.IfExp.test); + NodeId body = visitExpr(parent->v.IfExp.body); + NodeId elsebody = visitExpr(parent->v.IfExp.orelse); + + parentNid = pBuilder.buildIfExpression(test, body, elsebody); + } + break; + case Dict_kind: + { + vector keys = visitExprAsdl(parent->v.Dict.keys); + vector values = visitExprAsdl(parent->v.Dict.values); + vector key_list; + if(keys.size() == values.size()){ + vector::iterator keysit = keys.begin(); + vector::iterator valuesit = values.begin(); + while(keysit != keys.end() && valuesit != values.end()){ + key_list.push_back(pBuilder.buildKeyValue(*keysit, *valuesit)); + keysit++; + valuesit++; + } + } + parentNid = pBuilder.buildDictionary(key_list); + } + break; + case Set_kind: // python 2.7 feature + { + vector args = visitExprAsdl(parent->v.Set.elts); + parentNid = pBuilder.buildSet(args); + } + break; + case ListComp_kind: + { + NodeId elt = visitExpr(parent->v.ListComp.elt); + vector generators = visitComprehensionAsdl(parent->v.ListComp.generators); + + parentNid = pBuilder.buildListComp(elt, generators); + } + break; + case SetComp_kind: // python 2.7 feature + { + NodeId elt = visitExpr(parent->v.SetComp.elt); + vector generators = visitComprehensionAsdl(parent->v.SetComp.generators); + + parentNid = pBuilder.buildSetComp(elt, generators); + } + break; + case DictComp_kind: // python 2.7 feature + { + NodeId key = visitExpr(parent->v.DictComp.key); + NodeId value = visitExpr(parent->v.DictComp.value); + vector key_list; + NodeId keyValue = pBuilder.buildKeyValue(key, value); + vector generators = visitComprehensionAsdl(parent->v.DictComp.generators); + + parentNid = pBuilder.buildDictComp(keyValue, generators); + } + break; + case GeneratorExp_kind: + { + NodeId elt = visitExpr(parent->v.GeneratorExp.elt); + vector generators = visitComprehensionAsdl(parent->v.GeneratorExp.generators); + + parentNid = pBuilder.buildGeneratorExpression(elt, generators); + } + break; + case Yield_kind: + { + vector list; + if (parent->v.Yield.value) { + NodeId value = visitExpr(parent->v.Yield.value); + list.push_back(value); + } + NodeId exprl = pBuilder.buildExpressionList(list, true); + parentNid = pBuilder.buildYield(exprl); + } + break; + case Compare_kind: + { + NodeId left = visitExpr(parent->v.Compare.left); + vector ops = visitCompAsdl(parent->v.Compare.ops); + vector operands = visitExprAsdl(parent->v.Compare.comparators); + + parentNid = pBuilder.buildCompare(left, operands, ops); + } + break; + case Call_kind: + { + bool prev_state = collect_objects; + collect_objects = false; + NodeId func = visitExpr(parent->v.Call.func); + collect_objects = prev_state; + + vector args = visitExprAsdl(parent->v.Call.args); + + NodeId arguments = 0; + if(!args.empty()) arguments = pBuilder.buildExpressionList(args, false); + + vector keys = visitKeywordAsdl(parent->v.Call.keywords); + + NodeId starargs = 0; + NodeId kwargs = 0; + + unsigned line = 0, endline = 0, col = 0, endcol = 0; + + line = parent->lineno; col = parent->col_offset; + endline = parent->endline; endcol = parent->endcol; + +#ifndef PY3 + if(parent->v.Call.starargs != 0) { + starargs = visitExpr(parent->v.Call.starargs); + line = parent->v.Call.starargs->lineno; col = parent->v.Call.starargs->col_offset; + endline = parent->v.Call.starargs->endline; endcol = parent->v.Call.starargs->endcol; + } + if(parent->v.Call.kwargs != 0) { + kwargs = visitExpr(parent->v.Call.kwargs); + line = parent->v.Call.kwargs->lineno; col = parent->v.Call.kwargs->col_offset; + endline = parent->v.Call.kwargs->endline; endcol = parent->v.Call.kwargs->endcol; + } + + if (parent->v.Call.kwargs != 0 && parent->v.Call.starargs != 0) { + line = parent->v.Call.starargs->lineno; col = parent->v.Call.starargs->col_offset; + endline = parent->v.Call.kwargs->endline; endcol = parent->v.Call.kwargs->endcol; + } +#endif + + unsigned arglist_line = line, arglist_endline = endline, arglist_col = col, arglist_endcol = endcol; + + if (!keys.empty()){ + expression::Keyword& firstKey = dynamic_cast(pBuilder.getFactory()->getRef(*(keys.begin()))); + expression::Keyword& lastKey = dynamic_cast(pBuilder.getFactory()->getRef(keys.back())); + arglist_line = firstKey.getPosition().getLine(); + arglist_col = firstKey.getPosition().getCol(); + arglist_endline = lastKey.getPosition().getEndLine(); + arglist_endcol = lastKey.getPosition().getEndCol(); + } + + if (arguments){ + expression::Expression& argList = dynamic_cast(pBuilder.getFactory()->getRef(arguments)); + arglist_line = argList.getPosition().getLine(); + arglist_col = argList.getPosition().getCol(); + arglist_endline = argList.getPosition().getEndLine(); + arglist_endcol = argList.getPosition().getEndCol(); + } + + NodeId argument_list = pBuilder.buildArgumentList(arguments, keys, kwargs, starargs); + pBuilder.setPosition(argument_list, arglist_line, arglist_col, arglist_endline, arglist_endcol); + + parentNid = pBuilder.buildCall(argument_list, func); + } + break; +#ifndef PY3 + case Repr_kind: + { + // built-in function for string representation of an object + NodeId value = visitExpr(parent->v.Repr.value); + vector list; + list.push_back(value); + NodeId exprl = pBuilder.buildExpressionList(list, true); //TODO:why exprlist? yield? + + parentNid = pBuilder.buildStringConversion(exprl); + } + break; +#endif + case Num_kind: + { + if(PyFloat_Check(parent->v.Num.n)){ + float x = static_cast(PyFloat_AS_DOUBLE(parent->v.Num.n)); + parentNid = pBuilder.buildFloatNumber(x); + }else if(PyComplex_Check(parent->v.Num.n)){ + Py_complex z; + z = PyComplex_AsCComplex(parent->v.Num.n); + parentNid = pBuilder.buildImagNumber(z.imag, z.real); + }else{ + int x = static_cast(PyLong_AsLongLong(parent->v.Num.n)); // TODO signed/unsigned int/long/long long + parentNid = pBuilder.buildIntegerLiteral(x); + } + } + break; + case Str_kind: + { + std::string str; +#ifdef PY3 + // TODO unicodes + // it fails for e.g. "\uDC80", "\N{EMPTY SET}" + const char *s = PyString_AS_STRING(parent->v.Str.s); + if (s) + str = std::string(s); +#else + std::string type(parent->v.Str.s->ob_type->tp_name); + if(type.compare("unicode") == 0) + str = std::string(PyString_AS_STRING(PyUnicode_AsUTF8String(parent->v.Str.s))); + else if(type.compare("str") == 0) + str = std::string(PyString_AS_STRING(parent->v.Str.s)); +#endif + + parentNid = pBuilder.buildStringLiteral(str); + } + break; + case Attribute_kind: + { + NodeId primary = visitExpr(parent->v.Attribute.value); + std::string str(PyString_AS_STRING(parent->v.Attribute.attr)); + NodeId identifier = pBuilder.buildIdentifier(str, 0); + //FIXME: hacked + int primaryStartCol = parent->v.Attribute.value->col_offset; + pBuilder.setIncreasedPosition(identifier, parent->lineno, primaryStartCol + 1, parent->endline, parent->endcol); // +1 for the "." + + parentNid = pBuilder.buildAttributeRef(identifier, primary); + } + break; + case Subscript_kind: + { + NodeId sliceNid = visitSlice(parent->v.Subscript.slice); + NodeId value = visitExpr(parent->v.Subscript.value); + parentNid = pBuilder.buildSubscription(sliceNid, value); + } + break; + case Name_kind: + { + std::string str(PyString_AS_STRING(parent->v.Name.id)); + + NodeId objNid = 0; + + if (collect_objects) { + parentNid = pBuilder.buildIdentifier(str, objNid); + temp_objects.back()->insert(pair(str, parentNid)); + reverse_edge_objects.back()->insert(pair(parentNid, build_object)); + } else { + bool foundObject = false; + std::list< std::pair< std::map* , NodeKind > >::reverse_iterator rvIter; + std::map::iterator it; + for ( rvIter = objects.rbegin(); rvIter != objects.rend(); rvIter++) { + if((*rvIter).second != ndkClassDef){ + it = (*rvIter).first->find(str); + if( it != (*rvIter).first->end()) { + foundObject = true; + break; + } + } + } + + if( foundObject ) { + objNid = (*it).second; + }else if(build_object){ + objNid = pBuilder.buildObject(str); + objects.back().first->insert(pair(str, objNid)); + } + + parentNid = pBuilder.buildIdentifier(str, objNid); + + if(!foundObject && build_object){ + pBuilder.AddObjectRef(objNid, parentNid); + } + } + } + break; + case List_kind: + { + vector args = visitExprAsdl(parent->v.List.elts); + parentNid = pBuilder.buildList(args, false); + } + break; + case Tuple_kind: + { + vector args = visitExprAsdl(parent->v.Tuple.elts); + parentNid = pBuilder.buildList(args, true); + } + break; +#ifdef PY3 + case NameConstant_kind: + { + std::string name = ""; + PyObject *o = parent->v.NameConstant.value; + if (o == Py_None) + name = "None"; + else if (o == Py_True) + name = "True"; + else if (o == Py_False) + name = "False"; + + if (!name.empty()) + parentNid = pBuilder.buildIdentifier(name, 0); + else + parentNid = pBuilder.buildStringLiteral(""); + } + break; + default: + parentNid = pBuilder.buildStringLiteral(""); + break; +#endif + } + + pBuilder.setIncreasedPosition(parentNid, parent->lineno, parent->col_offset, parent->endline, parent->endcol); + + getOuterNodeInLine(parentNid); + + EXCEPTION_LOC_END("ASTVisitor::visitExpr()") + + return parentNid; +} + +NodeId ASTVisitor::visitSlice(slice_ty parent) { + NodeId parentNid = 0; + + switch (parent->kind) { +#ifndef PY3 + case Ellipsis_kind: + { + parentNid = pBuilder.buildEllipsis(); + } + break; +#endif + case Slice_kind: + { + NodeId lower = 0; + NodeId upper = 0; + NodeId step = 0; + unsigned line = 0, col = 0, endline = 0, endcol = 0; + + if(parent->v.Slice.lower != 0) { + lower = visitExpr(parent->v.Slice.lower); + line = parent->v.Slice.lower->lineno; + col = parent->v.Slice.lower->col_offset; + endline = parent->v.Slice.lower->endline; + endcol = parent->v.Slice.lower->endcol; + } + + if(parent->v.Slice.upper != 0) { + upper = visitExpr(parent->v.Slice.upper); + if (line == 0) { + line = parent->v.Slice.upper->lineno; + col = parent->v.Slice.upper->col_offset; + } + endline = parent->v.Slice.upper->endline; + endcol = parent->v.Slice.upper->endcol; + } + + if(parent->v.Slice.step != 0) { + step = visitExpr(parent->v.Slice.step); + if (line == 0) { + line = parent->v.Slice.step->lineno; + col = parent->v.Slice.step->col_offset; + } + endline = parent->v.Slice.step->endline; + endcol = parent->v.Slice.step->endcol; + parentNid = pBuilder.buildSlice(upper, lower, step); + }else{ + parentNid = pBuilder.buildSlice(upper, lower, step); + } + + pBuilder.setIncreasedPosition(parentNid, line, col, endline, endcol); + } + break; + case ExtSlice_kind: + { + vector args = visitSliceAsdl(parent->v.ExtSlice.dims); + + parentNid = pBuilder.buildExtSlice(args, 0); + } + break; + case Index_kind: + { + expr_ty indexValue = parent->v.Index.value; + NodeId value = visitExpr(indexValue); + parentNid = pBuilder.buildIndex(value); + pBuilder.setIncreasedPosition(parentNid, indexValue->lineno, indexValue->col_offset, indexValue->endline, indexValue->endcol); + } + break; + } + + + return parentNid; +} + +NodeId ASTVisitor::getDocstring(asdl_seq* ch_list){ + stmt_ty stmt = 0; + if (ch_list != 0) { + stmt = static_cast(ch_list->elements[0]); + } + + if (!stmt){ + return 0; + } + + NodeId docstring = 0; + if (stmt->kind == Expr_kind){ + expr_ty expr = stmt->v.Expr.value; + if (expr->kind == Str_kind){ + std::string str; +#ifdef PY3 + // TODO unicodes + const char *s = PyString_AS_STRING(expr->v.Str.s); + if (s) + str = std::string(s); +#else + std::string type(expr->v.Str.s->ob_type->tp_name); + if(type.compare("unicode") == 0) + str = std::string(PyString_AS_STRING(PyUnicode_AsUTF8String(expr->v.Str.s))); + else if(type.compare("str") == 0) + str = std::string(PyString_AS_STRING(expr->v.Str.s)); +#endif + + int lineBreaks = static_cast(std::count(str.begin(), str.end(), '\n')); + + docstring = pBuilder.buildDocstring(str); + pBuilder.setIncreasedPosition(docstring, expr->endline-lineBreaks, 0, expr->endline, expr->endcol); + } + } + return docstring; +} + +int ASTVisitor::getLLOC(int first_line, int last_line, std::vector logical_lines) { + int lloc = 0; + for(vector::iterator it = logical_lines.begin(); it != logical_lines.end(); it++){ + if (*it >= first_line) { + if (*it <= last_line) + lloc++; + else + break; // because lloc lines are sorted we can skip checking the rest + } + } + return lloc; +} + +void ASTVisitor::getOuterNodeInLine(NodeId id, int forcedLine){ + base::Positioned& actualNode = static_cast(pBuilder.getFactory()->getRef(id)); + int actualLine = forcedLine == 0 ? actualNode.getPosition().getLine() : forcedLine; + std::map::iterator it = commentHolderCandidates.find(actualLine); + if (it != commentHolderCandidates.end()){ // the last visited node has the most outer range in a line + it->second = id; + } else { + commentHolderCandidates.insert(pair(actualLine, id)); + } +} diff --git a/cl/PAN/src/VisitorImport.cpp b/cl/PAN/src/VisitorImport.cpp new file mode 100644 index 0000000..73409e8 --- /dev/null +++ b/cl/PAN/src/VisitorImport.cpp @@ -0,0 +1,423 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/VisitorImport.h" +#include +#include "../inc/messages.h" + +using namespace common; +using namespace columbus; +using namespace std; + +void VisitorImport::setType(module::Object& obj, type::Type& type) { + std::map< NodeId, std::set >::iterator it = type_set.find(obj.getId()); + + if(it == type_set.end()){ + std::set node_set; + bool new_type = true; + ListIterator lit = obj.getTypeListIteratorBegin(); + for (; lit != obj.getTypeListIteratorEnd(); ++lit){ + NodeId type_id = lit->getId(); + if(type.getId() == type_id) new_type = false; + node_set.insert(type_id); + } + if(new_type){ + node_set.insert(type.getId()); + obj.addType(&type); + } + type_set[obj.getId()] = node_set; + }else{ + std::set::iterator type_it = (*it).second.find(type.getId()); + if(type_it == (*it).second.end()){ + (*it).second.insert(type.getId()); + obj.addType(&type); + } + } +} + +NodeId VisitorImport::findModule(module::Package& package, std::string name){ + NodeId package_id = package.getId(); + NodeId module_id = 0; + + while(name.find_first_of(".") != std::string::npos){ + std::string pname = name.substr(0, name.find_first_of(".")); + module::Package& package = dynamic_cast(factory->getRef(package_id)); + ListIterator lit = package.getPackageListIteratorBegin(); + + bool find = false; + for (; lit != package.getPackageListIteratorEnd(); ++lit) { + const module::Package& chpackage = *lit; + if(pname.compare(chpackage.getName()) == 0){ + package_id = chpackage.getId(); + find = true; + break; + } + } + if(!find){ + package_id = 0; + break; + } + + size_t size = name.find_first_of(".")+1; + name = name.substr(size, name.length()-size); + } + if(package_id != 0){ + module::Package& pkg = dynamic_cast(factory->getRef(package_id)); + ListIterator lit = pkg.getPackageListIteratorBegin(); + ListIterator litEnd = pkg.getPackageListIteratorEnd(); + for(; lit != litEnd; ++lit){ + const module::Package& package = *lit; + if(name.compare(package.getName()) == 0){ + package_id = package.getId(); + name = "__init__"; + break; + } + } + module::Package& act_pkg = dynamic_cast(factory->getRef(package_id)); + ListIterator moduleLit = act_pkg.getModuleListIteratorBegin(); + for(; moduleLit != act_pkg.getModuleListIteratorEnd(); ++moduleLit){ + const module::Module& module = *moduleLit; + if(name.compare(module.getName()) == 0){ + module_id = module.getId(); + break; + } + } + } + return module_id; +} + +std::set VisitorImport::getAll(module::Module& module){ + ListIterator lit = module.getObjectListIteratorBegin(); + std::set __all__; + std::set ret; + for(; lit != module.getObjectListIteratorEnd(); ++lit){ + const module::Object& obj = *lit; + std::string name = obj.getName(); + if(obj.getName().compare("__all__") == 0){ + bool new_all = false; + if(obj.getRefersToSize() == 1){ + const base::Base& id = *obj.getRefersToListIteratorBegin(); + if(id.getNodeKind() == ndkIdentifier){ + base::Base* parent = id.getParent(); + NodeKind ndk = parent->getNodeKind(); + while(parent && (ndk != ndkModule && ndk != ndkAssign)){ + parent = parent->getParent(); + if(parent) ndk = parent->getNodeKind(); + } + if(parent && ndk == ndkAssign){ + statement::Assign& assign = dynamic_cast(*parent); + statement::TargetList* trlist = assign.getTargetList(); + if(trlist){ + NodeId all = 0; + ListIterator trlit = trlist->getTargetListIteratorBegin(); + for(; trlit != trlist->getTargetListIteratorEnd(); ++trlit){ + all = getAssignValue(const_cast(*trlit), *assign.getExpression(), id.getId()); + if (all != 0){ + break; + } + } + if(Common::getIsValid(all)){ + const base::Base& all_node = factory->getRef(all); + if(all_node.getNodeKind() == ndkList){ + new_all = true; + ListIterator list = dynamic_cast(all_node).getExpressionListIteratorBegin(); + for(; list != dynamic_cast(all_node).getExpressionListIteratorEnd(); ++list){ + const base::Base& item = *list; + if(item.getNodeKind() == ndkStringLiteral){ + __all__.insert(dynamic_cast(item).getValue()); + }else{ + new_all = false; + } + } + } + } + } + } + } + } + if(new_all){ + ret = __all__; + break; + } + } + if(name[0] != '_'){ + ret.insert(name); + } + } + return ret; +} + +NodeId VisitorImport::findObject(const std::string& name, ListIterator lit, ListIterator litEnd) { + NodeId object = 0; + for (; lit != litEnd; ++lit){ + const module::Object& obj = *lit; + if(obj.getName().compare(name) == 0){ + object = obj.getId(); + break; + } + } + return object; +} + +NodeId VisitorImport::getObject(base::Base& current_scope, std::string name, bool create_object){ + NodeId object = 0; + NodeKind scope_kind = current_scope.getNodeKind(); + + if(scope_kind == ndkModule || scope_kind == ndkFunctionDef || scope_kind == ndkClassDef || scope_kind == ndkLambda){ + switch(scope_kind){ + case ndkModule: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + case ndkFunctionDef: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + case ndkClassDef: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + case ndkLambda: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + default: + break; + } + + if(object == 0 && create_object){ + module::Object* obj = dynamic_cast(factory->createNode(ndkObject)); + obj->setName(name); + switch(scope_kind){ + case ndkModule: + dynamic_cast(current_scope).addObject(obj); + break; + case ndkFunctionDef: + dynamic_cast(current_scope).addObject(obj); + break; + case ndkClassDef: + dynamic_cast(current_scope).addObject(obj); + break; + case ndkLambda: + dynamic_cast(current_scope).addObject(obj); + break; + default: + break; + } + object = obj->getId(); + } + } + return object; +} + +NodeId VisitorImport::getAssignValue(expression::Expression& target_list, expression::Expression& value, NodeId target){ + NodeId ret = 0; + if(target_list.getNodeKind() == ndkList){ + if(value.getNodeKind() == ndkStringLiteral){ + if(dynamic_cast(target_list).getIsTuple()){ + ret = value.getId(); + } + }else if(value.getNodeKind() == ndkList){ + ListIterator trlit = dynamic_cast(target_list).getExpressionListIteratorBegin(); + ListIterator trlitEnd = dynamic_cast(target_list).getExpressionListIteratorEnd(); + ListIterator lit = dynamic_cast(value).getExpressionListIteratorBegin(); + ListIterator litEnd = dynamic_cast(value).getExpressionListIteratorEnd(); + for(; trlit != trlitEnd && lit != litEnd; ++trlit, ++lit){ + const expression::Expression& rt = *trlit; + const expression::Expression& vl = *lit; + if(rt.getNodeKind() == ndkList){ + ret = getAssignValue(const_cast(dynamic_cast(rt)), const_cast(vl), target); + }else if(rt.getNodeKind() == ndkIdentifier){ + if(rt.getId() == target){ + ret = vl.getId(); + break; + } + } // TODO: else if... + } + } + }else if(target_list.getNodeKind() == ndkIdentifier){ + if(target_list.getId() == target){ + ret = value.getId(); + } + } + return ret; +} + +void VisitorImport::visit(const statement::ClassDef& n, bool callVirtualBase){ + scope.push_back(n.getId()); +} + +void VisitorImport::visitEnd(const statement::ClassDef& n, bool callVirtualBase){ + scope.pop_back(); +} + +void VisitorImport::visit(const statement::FunctionDef& n, bool callVirtualBase){ + scope.push_back(n.getId()); +} + +void VisitorImport::visitEnd(const statement::FunctionDef& n, bool callVirtualBase){ + scope.pop_back(); +} + +void VisitorImport::visit(const module::Module& n, bool callVirtualBase){ +#ifdef _DEBUG + for(unsigned i=0; igetId(); + import_tree.push_back(n.getId()); + scope.push_back(n.getId()); +} + +void VisitorImport::visitEnd(const module::Module& n, bool callVirtualBase){ + import_resolved.insert(n.getId()); + import_tree.pop_back(); + scope.pop_back(); +} + +void VisitorImport::visit(const statement::ImportFrom& node, bool callVirtualBase){ + import_scope = package_id; + int level = node.getLevel(); + bool found = true; + for (int i = 0; i < level; ++i){ + base::Base& base = factory->getRef(import_scope); + if (base.getParent()){ + import_scope = base.getParent()->getId(); + }else{ + WriteMsg::write(CMSG_WRONG_PKG_LEVEL, level, node.getId()); + found = false; + break; + } + } + if (found) + import_scope = findModule(dynamic_cast(factory->getRef(import_scope)), node.getModulname()); +} +void VisitorImport::visitEnd(const statement::ImportFrom& node, bool callVirtualBase){ + import_scope = 0; +} + +void VisitorImport::visit(const statement::ImportStatement& node, bool callVirtualBase){ + import_scope = package_id; +} +void VisitorImport::visitEnd(const statement::ImportStatement& node, bool callVirtualBase){ + import_scope = 0; +} + +void VisitorImport::visit(const statement::Alias& node, bool callVirtualBase){ + + if(!node.getRefersTo()){ + std::string name = node.getName(); + if(import_scope){ + base::Base& iscope = factory->getRef(import_scope); + if(iscope.getNodeKind() == ndkModule){ + list::iterator it = find(import_tree.begin(), import_tree.end(), import_scope); + if(import_resolved.find(import_scope) == import_resolved.end()){ + if(it != import_tree.end()){ + + }else{ + VisitorImport* edge_visit = new VisitorImport(factory, import_tree, type_set, import_resolved); + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + ap.run(*factory, *edge_visit, import_scope); + delete edge_visit; + } + } + + std::set __all__ = getAll(dynamic_cast(iscope)); + ListIterator lit = dynamic_cast(iscope).getObjectListIteratorBegin(); + ListIterator litEnd = dynamic_cast(iscope).getObjectListIteratorEnd(); + if(name.compare("*") == 0){ + const_cast(node).setRefersTo(import_scope); + for(; lit != litEnd; ++lit){ + const module::Object& obj = *lit; + if(__all__.find(obj.getName()) != __all__.end()){ + NodeId objid = getObject(factory->getRef(scope.back()), obj.getName(), true); + if(Common::getIsValid(objid) && objid != obj.getId()){ + module::Object& local_obj = dynamic_cast(factory->getRef(objid)); + ListIterator reflit = obj.getRefersToListIteratorBegin(); + for(; reflit != obj.getRefersToListIteratorEnd(); ++reflit){ + local_obj.addRefersTo(reflit->getId()); + } + ListIterator typeLit = obj.getTypeListIteratorBegin(); + for(; typeLit != obj.getTypeListIteratorEnd(); ++typeLit){ + setType(local_obj, const_cast(*typeLit)); + } + } + } + } + }else{ + for(; lit != litEnd; ++lit){ + const module::Object& obj = *lit; + if(name.compare(obj.getName()) == 0){ + const_cast(node).setRefersTo(obj.getId()); + std::string obj_name; + if(node.getAlias().size() != 0){ + obj_name = node.getAlias(); + }else{ + obj_name = name; + } + NodeId objid = getObject(factory->getRef(scope.back()), obj_name, true); + if(obj.getId() != objid){ + module::Object& local_obj = dynamic_cast(factory->getRef(objid)); + ListIterator reflit = obj.getRefersToListIteratorBegin(); + for(; reflit != obj.getRefersToListIteratorEnd(); ++reflit){ + local_obj.addRefersTo(reflit->getId()); + } + ListIterator typeLit = obj.getTypeListIteratorBegin(); + for(; typeLit != obj.getTypeListIteratorEnd(); ++typeLit){ + setType(local_obj, const_cast(*typeLit)); + } + } + } + } + } + }else{ + NodeId import_module = findModule(dynamic_cast(factory->getRef(import_scope)), name); + if (Common::getIsValid(import_module)) { + module::Module& module = dynamic_cast(factory->getRef(import_module)); + list::iterator it = find(import_tree.begin(), import_tree.end(), module.getId()); + if (import_resolved.find(module.getId()) == import_resolved.end() && it == import_tree.end()) { + VisitorImport* edge_visit = new VisitorImport(factory, import_tree, type_set, import_resolved); + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + ap.run(*factory, *edge_visit, module); + delete edge_visit; + } + std::string obj_name; + if(node.getAlias().size() != 0){ + obj_name = node.getAlias(); + }else{ + obj_name = name; + } + const_cast(node).setRefersTo(import_module); + size_t pos = obj_name.find_first_of("."); + if(pos != std::string::npos){ + obj_name = obj_name.substr(0, pos); + import_module = findModule(dynamic_cast(factory->getRef(import_scope)), obj_name); + } + NodeId objid = getObject(factory->getRef(scope.back()), obj_name, true); + module::Object& local_obj = dynamic_cast(factory->getRef(objid)); + local_obj.addRefersTo(import_module); + setType(local_obj, dynamic_cast(factory->createReferenceType(import_module))); + } + } + } + } +} +void VisitorImport::visitEnd(const statement::Alias& node, bool callVirtualBase){} diff --git a/cl/PAN/src/VisitorType.cpp b/cl/PAN/src/VisitorType.cpp new file mode 100644 index 0000000..b2250e2 --- /dev/null +++ b/cl/PAN/src/VisitorType.cpp @@ -0,0 +1,769 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/VisitorType.h" +#include "../inc/VisitorImport.h" +#include +#include "../inc/messages.h" + +using namespace common; +using namespace columbus; +using namespace std; + +std::map< NodeId, std::set > VisitorType::type_set; + +void VisitorType::setType(module::Object& obj, type::Type& type) { + std::map< NodeId, std::set >::iterator it = type_set.find(obj.getId()); + + if(it == type_set.end()){ + std::set node_set; + bool new_type = true; + for (python::asg::ListIterator lit = obj.getTypeListIteratorBegin(), litEnd = obj.getTypeListIteratorEnd(); lit != litEnd; ++lit) { + NodeId type_id = lit->getId(); + if(type.getId() == type_id) new_type = false; + node_set.insert(type_id); + } + if(new_type){ + node_set.insert(type.getId()); + obj.addType(&type); + } + type_set[obj.getId()] = node_set; + }else{ + std::set::iterator type_it = (*it).second.find(type.getId()); + if(type_it == (*it).second.end()){ + (*it).second.insert(type.getId()); + obj.addType(&type); + } + } +} + +void VisitorType::setType(expression::Expression& obj, type::Type& type) { + if(obj.getType()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_REDEFINITION(Common::toString(obj.getId()))); + obj.setType(&type); +} + +NodeId VisitorType::findObject(const std::string& name, ListIterator lit, ListIterator litEnd) { + NodeId object = 0; + for (; lit != litEnd; ++lit){ + const module::Object& obj = *lit; + if (obj.getName().compare(name) == 0) { + object = obj.getId(); + break; + } + } + return object; +} + +NodeId VisitorType::getObject(base::Base& current_scope, std::string name, bool create_object){ + NodeId object = 0; + NodeKind scope_kind = current_scope.getNodeKind(); + + if(scope_kind == ndkModule || scope_kind == ndkFunctionDef || scope_kind == ndkClassDef || scope_kind == ndkLambda ){ + switch(scope_kind){ + case ndkModule: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + case ndkFunctionDef: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + case ndkClassDef: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + case ndkLambda: + object = findObject(name, dynamic_cast(current_scope).getObjectListIteratorBegin(), dynamic_cast(current_scope).getObjectListIteratorEnd()); + break; + default: + break; + } + + if(object == 0 && create_object){ + module::Object* obj = dynamic_cast(factory->createNode(ndkObject)); + obj->setName(name); + switch(scope_kind){ + case ndkModule: + dynamic_cast(current_scope).addObject(obj); + break; + case ndkFunctionDef: + dynamic_cast(current_scope).addObject(obj); + break; + case ndkClassDef: + dynamic_cast(current_scope).addObject(obj); + break; + case ndkLambda: + dynamic_cast(current_scope).addObject(obj); + break; + default: + break; + } + object = obj->getId(); + } + } + return object; +} + +NodeId VisitorType::findObject(base::Base& base_scope, std::string name, bool top_level_only) { + NodeId object = getObject(base_scope, name); + + if (object == 0) { + NodeKind base_ndk = base_scope.getNodeKind(); + if (base_ndk == ndkClassDef) { + ListIterator spec = dynamic_cast(base_scope).getBaseSpecifierListIteratorBegin(); + ListIterator specEnd = dynamic_cast(base_scope).getBaseSpecifierListIteratorEnd(); + for (; spec != specEnd; ++spec) { + if (spec->getDerivesFrom()) { + object = getObject(*spec->getDerivesFrom(), name); + if (object != 0) { + break; + } + } + } + if (object == 0 && !top_level_only) { + base::Base* curr_scope = base_scope.getParent(); + if (curr_scope) { + object = findObject(*curr_scope, name); + } + } + } else if (base_ndk != ndkModule) { + base::Base* curr_scope = base_scope.getParent(); + if (curr_scope) { + NodeKind ndk = curr_scope->getNodeKind(); + while (ndk != ndkFunctionDef && ndk != ndkModule && ndk != ndkLambda) { + curr_scope = curr_scope->getParent(); + if (curr_scope) { + ndk = curr_scope->getNodeKind(); + } else { + break; + } + } + } + if (curr_scope) { + object = findObject(*curr_scope, name); + } + } + } + return object; +} + +void VisitorType::ListAssign(expression::List& target, expression::Expression& value){ + ListIterator trlit = target.getExpressionListIteratorBegin(); + ListIterator trlitEnd = target.getExpressionListIteratorEnd(); + if(value.getNodeKind() == ndkStringLiteral){ + for (; trlit != trlitEnd; ++trlit){ + const expression::Expression& expr = *trlit; + if (expr.getNodeKind() == ndkIdentifier) { + const expression::Identifier& id = dynamic_cast(expr); + if(id.getRefersTo()){ + setType(*id.getRefersTo(), factory->createSequenceType(sekString)); + if(!id.getType()) + setType(const_cast(id), factory->createSequenceType(sekString)); + } + } + } + }else if(value.getNodeKind() == ndkList){ + ListIterator lit = dynamic_cast(value).getExpressionListIteratorBegin(); + ListIterator litEnd = dynamic_cast(value).getExpressionListIteratorEnd(); + for(; trlit != trlitEnd && lit != litEnd; ++trlit, ++lit){ + const expression::Expression& rt = *trlit; + const expression::Expression& vl = *lit; + if(rt.getNodeKind() == ndkList){ + ListAssign(const_cast(dynamic_cast(rt)), const_cast(vl)); + }else if(rt.getNodeKind() == ndkIdentifier){ + if(vl.getType() && dynamic_cast(rt).getRefersTo()){ + setType(*dynamic_cast(rt).getRefersTo(), *vl.getType()); + if(!rt.getType()) + setType(const_cast(rt), *vl.getType()); + } + } // TODO: else if... + } + } +} + +// module +void VisitorType::visit(const module::Package& node, bool callVirtualBase){ + scope.push_back(node.getId()); + module_scope.push_back(node.getId()); +} +void VisitorType::visitEnd(const module::Package& node, bool callVirtualBase){ + scope.pop_back(); + module_scope.pop_back(); +} + +void VisitorType::visit(const module::Module& node, bool callVirtualBase){ + WriteMsg::write(CMSG_VISITING, node.getName().c_str()); + + if (import_resolved.find(node.getId()) == import_resolved.end()) { + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + + VisitorImport* edge_visit = new VisitorImport(factory, std::list< NodeId >(), type_set, import_resolved); + ap.run(*factory, *edge_visit, node); + delete edge_visit; + } + if (node.getName().compare("__init__") == 0 && node.getParent() && filter == ExpressionsAndInit) { + module::Package& base = dynamic_cast(*node.getParent()); + for (ListIterator lit = base.getModuleListIteratorBegin(), litEnd = base.getModuleListIteratorEnd(); lit != litEnd; ++lit) { + const module::Module& module = *lit; + NodeId objectId = getObject(const_cast(node), module.getName(), true); + if (objectId) { + module::Object& obj = dynamic_cast(factory->getRef(objectId)); + if(obj.getRefersToSize() == 0) + obj.addRefersTo(module.getId()); + setType(obj, factory->createReferenceType(module.getId())); + } + } + for (ListIterator plit = base.getPackageListIteratorBegin(), plitEnd = base.getPackageListIteratorEnd(); plit != plitEnd; ++plit) { + const module::Package& package = *plit; + for (ListIterator lit = package.getModuleListIteratorBegin(), litEnd = package.getModuleListIteratorEnd(); lit != litEnd; ++lit) { + const module::Module& module = *lit; + if(module.getName().compare("__init__") == 0){ + NodeId objectId = getObject(const_cast(node), module.getName(), true); + if (objectId) { + module::Object& obj = dynamic_cast(factory->getRef(objectId)); + if(obj.getRefersToSize() == 0) + obj.addRefersTo(module.getId()); + setType(obj, factory->createReferenceType(module.getId())); + } + } + } + } + } + scope.push_back(node.getId()); + module_scope.push_back(node.getId()); +} +void VisitorType::visitEnd(const module::Module& node, bool callVirtualBase){ + scope.pop_back(); + module_scope.pop_back(); +} + +void VisitorType::visit(const module::Object& node, bool callVirtualBase){ + +} + +void VisitorType::visitEnd(const module::Object& node, bool callVirtualBase){ + +} + +// statement +void VisitorType::visit(const statement::ClassDef& node, bool callVirtualBase){ + scope.push_back(node.getId()); + module::Object* obj = node.getRefersTo(); + if(obj){ + setType(*obj, factory->createReferenceType(node.getId())); + } +} + +void VisitorType::visitEnd(const statement::ClassDef& node, bool callVirtualBase){ + scope.pop_back(); +} + +void VisitorType::visit(const statement::FunctionDef& node, bool callVirtualBase){ + NodeId parent = scope.back(); + scope.push_back(node.getId()); + module::Object* obj = node.getRefersTo(); + if(obj){ + setType(*obj, factory->createReferenceType(node.getId())); + } + + if(parent){ + base::Base& bob = factory->getRef(parent); + if(bob.getNodeKind() == ndkClassDef){ + if(node.getParameterSize() > 0){ + ListIterator lit = node.getParameterListIteratorBegin(); + if (lit != node.getParameterListIteratorEnd()) { + const statement::Parameter& par = *lit; + + if(par.getRefersTo() && par.getName().compare("self") == 0) { + module::Object& bb = *par.getRefersTo(); + setType(bb, factory->createReferenceType(parent)); + } + } + } + } + } +} + +void VisitorType::visitEnd(const statement::FunctionDef& node, bool callVirtualBase) { + scope.pop_back(); +} + +void VisitorType::visit(const statement::BaseSpecifier& node, bool callVirtualBase){ +} +void VisitorType::visitEnd(const statement::BaseSpecifier& node, bool callVirtualBase){ + if (!node.getDerivesFrom() && node.getName() && filter >= ReturnAndBaseSpec) { + expression::Expression* name = node.getName(); + if(name->getType()){ + type::Type* type = name->getType(); + if(type->getNodeKind() == ndkReferenceType){ + if(dynamic_cast(*type).getRefersTo()){ + base::Base* base = dynamic_cast(*type).getRefersTo(); + if(base->getNodeKind() == ndkClassDef){ + const_cast(node).setDerivesFrom(base->getId()); + } + } + } + } + } +} + +void VisitorType::visit(const statement::Assign& node, bool callVirtualBase){ +} +void VisitorType::visitEnd(const statement::Assign& node, bool callVirtualBase){ + if(filter >= Assignments){ + statement::TargetList* target_list = node.getTargetList(); + expression::Expression* value = node.getExpression(); + + ListIterator trlit = target_list->getTargetListIteratorBegin(); + for (; trlit != target_list->getTargetListIteratorEnd(); ++trlit){ + const expression::Expression& rt = *trlit; + if(rt.getNodeKind() == ndkList){ + ListAssign(const_cast(dynamic_cast(rt)), *value); + }else if(rt.getNodeKind() == ndkIdentifier){ + if(value->getType() && dynamic_cast(rt).getRefersTo()){ + setType(*dynamic_cast(rt).getRefersTo(), *value->getType()); + if(!rt.getType()) + setType(const_cast(rt), *value->getType()); + } + }// TODO: else if(rt.getNodeKind() == ndkAttributeRef || ndkSubscript || ...) + } + } +} + +void VisitorType::visit(const statement::Return& node, bool callVirtualBase) { +} + +void VisitorType::visitEnd(const statement::Return& node, bool callVirtualBase) { + if(filter >= ReturnAndBaseSpec){ + NodeId parentNid = scope.back(); + base::Base& parent = factory->getRef(parentNid); + if (parent.getNodeKind() == ndkFunctionDef) { // if the return is in a function's block - should be, otherwise we get parser error + statement::FunctionDef& fdef = dynamic_cast(parent); + + expression::Expression* rExp = node.getExpression(); + if (rExp && rExp->getType()) { + if (!fdef.getReturnType()) { + fdef.setReturnType(rExp->getType()); + } else if (fdef.getReturnType() != rExp->getType()) { + fdef.setReturnType(&factory->createSimpleType(stkUnknown)); + } + } + } + } +} + +void VisitorType::visit(const statement::TargetList& node, bool callVirtualBase){ +} + +void VisitorType::visitEnd(const statement::TargetList& node, bool callVirtualBase){ +} + +// expression +void VisitorType::visit(const expression::List& node, bool callVirtualBase){ + if (!node.getType()) { + if(node.getIsTuple()){ + setType(const_cast(node), factory->createSequenceType(sekTuple)); + }else{ + setType(const_cast(node), factory->createSequenceType(sekList)); + } + } +} + +void VisitorType::visitEnd(const expression::List& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::KeyValue& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::KeyValue& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Generator& node, bool callVirtualBase){ +} +void VisitorType::visitEnd(const expression::Generator& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::GeneratorExpression& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSequenceType(sekList)); + } +} + +void VisitorType::visitEnd(const expression::GeneratorExpression& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Lambda& node, bool callVirtualBase){ + scope.push_back(node.getId()); +} +void VisitorType::visitEnd(const expression::Lambda& node, bool callVirtualBase){ + if (!node.getType() && node.getExpression()) { + type::Type* eType = node.getExpression()->getType(); + if (eType){ + setType(const_cast(node), *eType); + } + } +} + +void VisitorType::visit(const expression::Keyword& node, bool callVirtualBase){} + +void VisitorType::visitEnd(const expression::Keyword& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::BinaryLogical& node, bool callVirtualBase){ + if (!node.getType()) { // TODO: in case of 'and' or 'or' operation the type is not allways boolean + setType(const_cast(node), factory->createSimpleType(stkBoolean)); + } +} +void VisitorType::visitEnd(const expression::BinaryLogical& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::IfExpression& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::IfExpression& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::ArgumentList& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::ArgumentList& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::StringConversion& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSequenceType(sekString)); + } +} +void VisitorType::visitEnd(const expression::StringConversion& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::UnaryOperation& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::UnaryOperation& node, bool callVirtualBase){ + if (!node.getType()) { + if(node.getKind() == unkNot){ + setType(const_cast(node), factory->createSimpleType(stkBoolean)); + }else{ + expression::Expression* expr = node.getExpression(); + if(expr){ + type::Type* eType = expr->getType(); + if(eType){ + setType(const_cast(node), *eType); + } + } + } + } +} + +void VisitorType::visit(const expression::AttributeRef& node, bool callVirtualBase) { +} + +void VisitorType::setAttributeType(const expression::AttributeRef& node, NodeId lTypeNid) { + NodeKind lTypeKind; + expression::Identifier* right = dynamic_cast(node.getRightExpression()); + std::string rightString = right->getName(); + + if (Common::getIsValid(lTypeNid)) { + type::Type& lType = dynamic_cast(factory->getRef(lTypeNid)); + lTypeKind = lType.getNodeKind(); + + if (lTypeKind == ndkReferenceType) { + base::Positioned* object = dynamic_cast(factory->getRef(lTypeNid)).getRefersTo(); + NodeKind objectKind; + if (object) { + objectKind = object->getNodeKind(); + if (objectKind == ndkClassDef || objectKind == ndkModule) { + NodeId returnedNid = findObject(*object, rightString, true); // looking for "rightString" attribute/class/function in "curr_scope" class/module + if (!Common::getIsValid(returnedNid)) { // no such object + // TODO:check if it was last part of the attributeref (and left side of an assign) - in that case create a new object + } else { + module::Object& returned = dynamic_cast(factory->getRef(returnedNid)); + if (returned.getTypeSize() == 1) { // the resolved object has exactly one type -- clone, should be refactored + ListIterator lit = returned.getTypeListIteratorBegin(); + const type::Type& tt = *lit; + setType(const_cast(node), const_cast(tt)); + right->setRefersTo(returned.getId()); + setType(const_cast(*right), const_cast(tt)); + } else if (returned.getTypeSize() > 1){ + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } + } else if (objectKind == ndkFunctionDef) { + type::Type* returnType = dynamic_cast(*object).getReturnType(); + if (returnType && lTypeNid != returnType->getId()) { + setAttributeType(node, returnType->getId()); + } + } else { + // TODO? + } + } + } else { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } +} + +void VisitorType::visitEnd(const expression::AttributeRef& node, bool callVirtualBase) { + if (!node.getType() && filter >= ExprAndAtrRef) { + expression::Expression* left = node.getLeftExpression(); + expression::Identifier* right = dynamic_cast(node.getRightExpression()); + + std::string rightString = right->getName(); + NodeKind lKind = left->getNodeKind(); + + if (lKind == ndkAttributeRef || lKind == ndkIdentifier) { + if (!left->getType() && lKind == ndkAttributeRef) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } else { + NodeId lTypeNid = 0; + + if (lKind == ndkIdentifier) { + NodeId lObjectNid = findObject(factory->getRef(scope.back()), dynamic_cast(*left).getName()); + if (!Common::getIsValid(lObjectNid)) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } else { + module::Object& lObject = dynamic_cast(factory->getRef(lObjectNid)); + if (lObject.getTypeSize() == 1) { + ListIterator lit = lObject.getTypeListIteratorBegin(); + lTypeNid = (*lit).getId(); + } else if (lObject.getTypeSize() > 1) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } + } else { + lTypeNid = left->getType()->getId(); + } + + setAttributeType(node, lTypeNid); + } + } else if (lKind == ndkCall) { + statement::CompoundStatement* comStm = dynamic_cast(*left).getRefersTo(); + if (comStm) { + NodeKind refKind = comStm->getNodeKind(); + if (refKind == ndkClassDef) { + NodeId objNid = getObject(*comStm, rightString); + if (!Common::getIsValid(objNid)) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } else { + module::Object& returned = dynamic_cast(factory->getRef(objNid)); + if (returned.getTypeSize() == 1) { // the resolved object has exactly one type -- clone, should be refactored + ListIterator lit = returned.getTypeListIteratorBegin(); + const type::Type& tt = *lit; + setType(const_cast(node), const_cast(tt)); + right->setRefersTo(returned.getId()); + setType(const_cast(*right), const_cast(tt)); + } else if (returned.getTypeSize() > 1) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } + } else if (refKind == ndkFunctionDef) { + type::Type* returnType = dynamic_cast(*comStm).getReturnType(); + if (returnType) { + setAttributeType(node, returnType->getId()); + } + } + } + } + } +} + +void VisitorType::visit(const expression::Dictionary& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createDictType()); + } +} +void VisitorType::visitEnd(const expression::Dictionary& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Slicing& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::Slicing& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Slice& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::Slice& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::BinaryArithmetic& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::BinaryArithmetic& node, bool callVirtualBase){ + if (!node.getType()) { + expression::Expression* leftExp = node.getLeftExpression(); + expression::Expression* rightExp = node.getRightExpression(); + + type::Type* leftType = leftExp->getType(); + type::Type* rightType = rightExp->getType(); + + if (leftType && rightType) { + NodeKind lNodeKind = leftType->getNodeKind(); + NodeKind rNodeKind = rightType->getNodeKind(); + + if (lNodeKind == ndkSimpleType && rNodeKind == ndkSimpleType) { + SimpleTypeKind nType; + SimpleTypeKind lType = dynamic_cast(*leftType).getKind(); + SimpleTypeKind rType = dynamic_cast(*rightType).getKind(); + if (lType == stkImaginary || rType == stkImaginary) nType = stkImaginary; + else if (lType == stkFloat || rType == stkFloat) nType = stkFloat; + else if (lType == stkLong || rType == stkLong) nType = stkLong; + else nType = stkInteger; + if (lType == stkUnknown || rType == stkUnknown) nType = stkUnknown; + + setType(const_cast(node), factory->createSimpleType(nType)); + } else if (lNodeKind == ndkSequenceType && rNodeKind == ndkSequenceType) { + SequenceTypeKind lType = dynamic_cast(*leftType).getKind(); + SequenceTypeKind rType = dynamic_cast(*rightType).getKind(); + + if (lType == rType) { + setType(const_cast(node), factory->createSequenceType(lType)); + } else { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } else if (lNodeKind == ndkDictType && rNodeKind == ndkDictType) { + setType(const_cast(node), factory->createDictType()); + } else if (lNodeKind == ndkSequenceType && rNodeKind == ndkSimpleType) { + SequenceTypeKind lType = dynamic_cast(*leftType).getKind(); + SimpleTypeKind rType = dynamic_cast(*rightType).getKind(); + + if (rType == stkUnknown) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } else if (lType == sekString && (rType == stkInteger || rType == stkLong) ) { + setType(const_cast(node), factory->createSequenceType(sekString)); + } else if (lType == sekList && (rType == stkBoolean || rType == stkInteger) ) { + setType(const_cast(node), factory->createSequenceType(sekList)); + } else { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } else if (lNodeKind == ndkSimpleType && rNodeKind == ndkSequenceType) { + SimpleTypeKind lType = dynamic_cast(*leftType).getKind(); + SequenceTypeKind rType = dynamic_cast(*rightType).getKind(); + + if (lType == stkUnknown) { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } else if (rType == sekString && (lType == stkInteger || lType == stkLong) ) { + setType(const_cast(node), factory->createSequenceType(sekString)); + } else if (rType == sekList && (lType == stkBoolean || lType == stkInteger) ) { + setType(const_cast(node), factory->createSequenceType(sekList)); + } else { + setType(const_cast(node), factory->createSimpleType(stkUnknown)); + } + } + } + } +} + +void VisitorType::visit(const expression::Identifier& node, bool callVirtualBase){ + if(!node.getType() && filter >= ExprAndAtrRef){ + if(node.getRefersTo()){ + module::Object* ob = node.getRefersTo(); + if(ob->getTypeSize() == 1){ + ListIterator lit = ob->getTypeListIteratorBegin(); + setType(const_cast(node), const_cast(*lit)); + }else if(ob->getRefersToSize() == 1){ + ListIterator lit = ob->getRefersToListIteratorBegin(); + const base::Base& base = *lit; + if(base.getNodeKind() == ndkFunctionDef || base.getNodeKind() == ndkClassDef) + setType(const_cast(node), factory->createReferenceType(base.getId())); + } + }else{ + if(node.getParent() && node.getParent()->getNodeKind() != ndkAttributeRef){ + NodeId objid = findObject(factory->getRef(scope.back()), node.getName()); + if(Common::getIsValid(objid)){ + module::Object& ob = dynamic_cast(factory->getRef(objid)); + const_cast(node).setRefersTo(objid); + if(ob.getTypeSize() == 1){ + ListIterator lit = ob.getTypeListIteratorBegin(); + setType(const_cast(node), const_cast(*lit)); + } + } + } + } + } +} +void VisitorType::visitEnd(const expression::Identifier& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::ListComp& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSequenceType(sekList)); + } +} +void VisitorType::visitEnd(const expression::ListComp& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::ExpressionList& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::ExpressionList& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Ellipsis& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::Ellipsis& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::ExtSlice& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::ExtSlice& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Subscription& node, bool callVirtualBase){} +void VisitorType::visitEnd(const expression::Subscription& node, bool callVirtualBase){} + +void VisitorType::visit(const expression::Call& node, bool callVirtualBase) { + +} +void VisitorType::visitEnd(const expression::Call& node, bool callVirtualBase) { + if (filter >= ExprAndAtrRef) { + if (!node.getRefersTo()) { + expression::Expression* ex = node.getExpression(); + if (ex->getType()) { + type::Type* type = ex->getType(); + if (type->getNodeKind() == ndkReferenceType) { + if (dynamic_cast(*type).getRefersTo()) { + base::Base* ref = dynamic_cast(*type).getRefersTo(); + NodeKind ndk = ref->getNodeKind(); + if (ndk == ndkClassDef || ndk == ndkFunctionDef) { + const_cast(node).setRefersTo(ref->getId()); + } + } + } + } + }else{ + if (!node.getType()) { + base::Base* ref = node.getRefersTo(); + NodeKind ndk = ref->getNodeKind(); + if (ndk == ndkClassDef) { + setType(const_cast(node), factory->createReferenceType(ref->getId())); + } else if(ndk == ndkFunctionDef) { + type::Type* return_type = dynamic_cast(*ref).getReturnType(); + if (return_type) { + setType(const_cast(node), *return_type); + } + } + } + } + } +} + +void VisitorType::visit(const expression::Index& node, bool callVirtualBase){ +} + +void VisitorType::visitEnd(const expression::Index& node, bool callVirtualBase){} + + +// literal +void VisitorType::visit(const expression::LongInteger& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSimpleType(stkLong)); + } +} + +void VisitorType::visit(const expression::IntegerLiteral& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSimpleType(stkInteger)); + } +} + +void VisitorType::visit(const expression::ImagNumber& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSimpleType(stkImaginary)); + } +} + +void VisitorType::visit(const expression::FloatNumber& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSimpleType(stkFloat)); + } +} + +void VisitorType::visit(const expression::StringLiteral& node, bool callVirtualBase){ + if (!node.getType()) { + setType(const_cast(node), factory->createSequenceType(sekString)); + } +} diff --git a/cl/PAN/src/main.cpp b/cl/PAN/src/main.cpp new file mode 100644 index 0000000..e3dedf0 --- /dev/null +++ b/cl/PAN/src/main.cpp @@ -0,0 +1,521 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifdef PY3 +#define PAN_VER "3" +#else +#define PAN_VER "2" +#endif +#define PROGRAM_NAME "PAN" PAN_VER +#define EXECUTABLE_NAME PROGRAM_NAME + +#include +#include "../inc/PVisitor.h" +#include "../inc/VisitorType.h" +#include "../inc/messages.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::python::asg; + + +static int parseErrors = 0; + +// command line +static std::string listFile; +static std::string out; +static std::string prefix; +static bool dPML = false; +static std::list inputFiles; +static std::string outPath; +static bool pkg = false; +static std::string filterFile; +static bool analyzePackages = false; +static std::string pythonBinary; + +// Callback methods for argument processing +static bool ppList (const Option *o, char *argv[]) { + listFile = argv[0]; + return true; +} + +static bool ppOut (const Option *o, char *argv[]) { + out = argv[0]; + return true; +} + +static bool ppDPML (const Option *o, char *argv[]) { + dPML = true; + return true; +} + +static bool ppPref (const Option *o, char *argv[]) { + prefix = argv[0]; + return true; +} + +static void ppFile (char *filename) { + inputFiles.push_back(filename); +} + +static bool ppPkg (const Option *o, char *argv[]) { + pkg = true; + return true; +} + +static bool ppFilterPath (const Option *o, char *argv[]) { + filterFile = argv[0]; + return true; +} + +static bool ppAnalyzePackages ( const Option *o, char *argv[] ) { + analyzePackages = true; + return true; +} + +bool ppPythonBinary(const common::Option *o, char *argv[]) { + pythonBinary = argv[0]; + return true; +} + +const common::Option OPTIONS_OBJ [] = { + { false, "-lst", 1, "filename", 0, OT_WC, ppList, NULL, CLARG_LST}, + { false, "-out", 1, "filename", 0, OT_WC, ppOut, NULL, CLARG_OUT}, + { false, "-dPML", 0, "", 0, OT_NONE, ppDPML, NULL, CLARG_XML}, + { false, "-basepath", 1, "path", 0, OT_WC, ppPref, NULL, CLARG_PREFIX}, + { false, "-pkg", 0, "", 0, OT_NONE, ppPkg, NULL, CLARG_PKG}, + { false, "-analyzepackages", 0, "", 0, OT_NONE, ppAnalyzePackages, NULL, CLARG_ANALYZE_PKG}, + { false, "-pythonBinary", 1, "filename", 0, OT_WC, ppPythonBinary, NULL, CLARG_PYBIN}, + CL_FLTP + COMMON_CL_ARGS +}; + + +void checkOutputFile() { + static std::string psi = ".psi"; + if (!out.empty()) { + size_t len = out.length(); + size_t psiLen = strlen(psi.c_str()); + if ((psiLen <= len) && (out.substr(len - psiLen) == psi)) { + outPath = out.substr(0, len - psiLen); + } else { + WriteMsg::write(CMSG_NOT_PSI_EXTENSION, out.c_str()); + outPath = std::string(out); + out += psi; + } + } else { + if (inputFiles.size() == 1) { + std::string tmp(*inputFiles.begin()); + outPath = tmp.substr(0, tmp.find_last_of('.')); + } else { + outPath = "noname"; + } + out = outPath + psi; + } +} + +static inline void setStartTime(uint64_t *time) +{ + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system; +} + +static inline void setElapsedTime(uint64_t *time) +{ + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system - *time; +} + +static inline void updateMemStat(uint64_t *max_mem) +{ + memstat ms = getProcessUsedMemSize(); + if (*max_mem < ms.size) { + *max_mem = ms.size; + } +} + + +static void collectFiles(const std::string& fileOrDir, std::set& uniqueFiles, const std::string& ext) { + try { + boost::filesystem::path p(fileOrDir); + + if (boost::filesystem::exists(p)) { + + // skip hidden files and directories + std::string filename = p.filename().string(); + if (filename.empty() || (filename[0] == '.' && filename != ".")) { + return; + } + + if (boost::filesystem::is_regular_file(p)) { + // file + if (p.extension().string() == ext) { + uniqueFiles.insert(p.string()); + } + + } else if (boost::filesystem::is_directory(p)) { + // directory + std::vector paths; + std::copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(paths)); + std::sort(paths.begin(), paths.end()); + for (std::vector::const_iterator it = paths.begin(); it != paths.end(); ++it) { + collectFiles(it->string(), uniqueFiles, ext); + } + + } + + } else { + WriteMsg::write(PATH_DOES_NOT_EXIST, fileOrDir.c_str()); + } + } catch (const boost::filesystem::filesystem_error& ex) { + WriteMsg::write(ERROR_WHILE_COLLECTING_FILES, ex.what()); + } +} + +static void collectFiles(std::list& files, const std::string& ext) { + std::set uniqueFiles; + + for (std::list::const_iterator it = files.begin(), itEnd = files.end(); it != itEnd; ++it) { + collectFiles(*it, uniqueFiles, ext); + } + + // case insensitive sort + std::set ciFiles(uniqueFiles.begin(), uniqueFiles.end()); + + files.clear(); + files.insert(files.begin(), ciFiles.begin(), ciFiles.end()); +} + + +void run(const std::string& name, ASTVisitor& ast_visitor) { + FILE* file = fopen(name.c_str(), "r"); + if (file == NULL) { + WriteMsg::write(CMSG_CANNOT_OPEN_FILE, name.c_str()); + return; + } + + PyArena *arena = PyArena_New(); + if (arena == NULL) { + fclose(file); + return; + } + + WriteMsg::write(CMSG_PARSING, name.c_str()); + PyCompilerFlags flags; + flags.cf_flags = 0; + int errorCode = 0; + +#ifdef PY3 + mod_ty mod = PyParser_ASTFromFile(file, name.c_str(), 0, Py_file_input, 0, 0, &flags, &errorCode, arena); +#else + mod_ty mod = PyParser_ASTFromFile(file, name.c_str(), Py_file_input, 0, 0, &flags, &errorCode, arena); +#endif + + if (!mod) { + ++parseErrors; + cout.flush(); + cerr.flush(); + PyErr_PrintEx(0); + cout.flush(); + cerr.flush(); + } + + fclose(file); + + PlLOC plloc; + vector llines = plloc.processLines(name, ast_visitor.getBuilder()); + + if(mod == 0) { + PyArena_Free(arena); + WriteMsg::write(CMSG_PARSE_ERROR); + return; + } + + std::string module_name = name; + if(!prefix.empty()){ + size_t pos = module_name.find(prefix); + if(pos == 0){ + module_name = module_name.substr(prefix.size()); + }else{ + WriteMsg::write(CMSG_PARSE_ERROR); + } + } + + ast_visitor.Visit(name, module_name, mod, llines, plloc.getCommentMap()); + PyArena_Free(arena); +} + +void checkPython() { + std::string pyBin; + + if (!pythonBinary.empty()) { + pyBin = pythonBinary; + } else { + // use env vars instead of command line switch +#ifdef PY3 + char* columbusPythonBinary = getenv("COLUMBUS_PYTHON3_BINARY"); +#else + char* columbusPythonBinary = getenv("COLUMBUS_PYTHON2_BINARY"); +#endif + if (columbusPythonBinary != NULL) + pyBin = columbusPythonBinary; + } + + if (pyBin.empty()) { + WriteMsg::write(CMSG_PYTHON_BIN_UNSPEC); + exit(EXIT_FAILURE); + } + + std::string pythonPath; + std::string pythonReleaseVersion; // in the format X.Y + + { + std::vector sv; + sv.push_back("--version"); + std::stringstream ss; + int ret = common::run(pyBin, sv, ss); + std::string outStr = ss.str(); + + if (ret != 0) { + WriteMsg::write(CMSG_PYTHON_BIN_ERROR); + exit(EXIT_FAILURE); + } + + static const boost::regex versionRegex("Python (\\d+)\\.(\\d+)"); + boost::smatch match; + + if (boost::regex_search(outStr, match, versionRegex)) { + pythonReleaseVersion = match[1].str() + "." + match[2].str(); + + if (match[1].str() != PAN_VER) { + WriteMsg::write(CMSG_PAN_PY_COMPAT_ERROR, PAN_VER, pythonReleaseVersion.c_str()); + exit(EXIT_FAILURE); + } + } + } + + { + std::vector sv; + sv.push_back("-c"); + sv.push_back("import sys; print(sys.prefix); print(sys.exec_prefix);"); + std::stringstream ss; + + int ret = common::run(pyBin, sv, ss); + if (ret != 0) { + WriteMsg::write(CMSG_PY_PREFIX_ERROR); + exit(EXIT_FAILURE); + } + + std::string line; + while (getline(ss, line)) { + common::trim(line); + if (!line.empty()) { + boost::filesystem::path p(line); +#ifdef _WIN32 + p /= "Lib"; +#else + p /= "lib"; + p /= ("python" + pythonReleaseVersion); +#endif + if (boost::filesystem::exists(p)) { + pythonPath = p.string(); + break; + } + } + } + } + + if (pythonPath.empty()) { + WriteMsg::write(CMSG_PY_LIB_NOT_FOUND); + exit(EXIT_FAILURE); + } + + char* pythonPathEnv = getenv("PYTHONPATH"); + if (pythonPathEnv != NULL) { + pythonPath += PATH_SEPARATOR + std::string(pythonPathEnv); + } + + if (common::setEnvironmentVariable("PYTHONPATH", pythonPath.c_str()) != 0) { + WriteMsg::write(CMSG_ERROR_ENVSET_FAILURE, "PYTHONPATH"); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char** argv) +{ + MAIN_BEGIN + + uint64_t totalTime; + uint64_t parseTime; + uint64_t saveTime; + uint64_t dumpTime; + + uint64_t maxMem = 0; + + setStartTime(&totalTime); + + MainInit(argc, argv, "-"); + + checkPython(); + + loadStringListFromFile(listFile, inputFiles); + + if (analyzePackages) { + if (inputFiles.size() != 1) { + WriteMsg::write(CMSG_ONE_INPUT_REQ); + clError(); + } + + std::string baseDir = inputFiles.front(); + inputFiles.clear(); + columbus::python::collectPackageFiles(baseDir, "", inputFiles); + + } else { + collectFiles(inputFiles, ".py"); + } + + if (!filterFile.empty()) { + DirectoryFilter filter; + if (common::pathFileExists(filterFile, false)) { + filter.openFilterFile(filterFile); + } else { + WriteMsg::write(CMSG_CANNOT_OPEN_FILE, filterFile.c_str()); + return EXIT_FAILURE; + } + if (!filter.isEmpty()) { + std::list::iterator it = inputFiles.begin(); + while (it != inputFiles.end()) { + if (filter.isFilteredOut(*it)) { + WriteMsg::write(CMSG_FILTERED_FILE, it->c_str()); + it = inputFiles.erase(it); + } else { + ++it; + } + } + } + } + + if (inputFiles.empty()) { + WriteMsg::write(CMSG_NO_INPUT_FILES); + } + + checkOutputFile(); + + RefDistributorStrTable strTable; + Factory* factory = new Factory(strTable); + + setStartTime(&parseTime); + + if (!inputFiles.empty()) { + if( !Py_IsInitialized() ) { + Py_NoSiteFlag = 1; + Py_DontWriteBytecodeFlag = 1; // Suppress writing bytecode files (*.pyc) + Py_FrozenFlag = 1; // Suppress errors from getpath.c (could not find prefix/exec_prefix... on linux) + Py_Initialize(); + } + + PBuilder p_builder(factory, pkg); + ASTVisitor ast_visitor(p_builder); + + for(std::list::iterator it = inputFiles.begin(); it != inputFiles.end(); it++) { + run(*it, ast_visitor); + } + + updateMemStat(&maxMem); + + VisitorType* edge_visit = new VisitorType(factory, ExpressionsAndInit); + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + ap.run(*factory, *edge_visit, *factory->getRoot()); + delete edge_visit; + edge_visit = new VisitorType(factory, Assignments); + ap.run(*factory, *edge_visit, *factory->getRoot()); + delete edge_visit; + edge_visit = new VisitorType(factory, ExprAndAtrRef); + ap.run(*factory, *edge_visit, *factory->getRoot()); + delete edge_visit; + edge_visit = new VisitorType(factory, ReturnAndBaseSpec); + ap.run(*factory, *edge_visit, *factory->getRoot()); + delete edge_visit; + edge_visit = new VisitorType(factory, ExprAndAtrRef); + ap.run(*factory, *edge_visit, *factory->getRoot()); + delete edge_visit; + edge_visit = new VisitorType(factory, ReturnAndBaseSpec); + ap.run(*factory, *edge_visit, *factory->getRoot()); + delete edge_visit; + } + + updateMemStat(&maxMem); + setElapsedTime(&parseTime); + setStartTime(&saveTime); + + WriteMsg::write(CMSG_SAVING_ASG, out.c_str()); + CsiHeader header; + header.add(header.csih_OriginalLocation,out); + + factory->save(out, header); + factory->saveFilter(outPath + ".fpsi"); + + updateMemStat(&maxMem); + setElapsedTime(&saveTime); + setStartTime(&dumpTime); + + if (dPML) { + std::string pmlFile = outPath + ".pml"; + WriteMsg::write(CMSG_CREATING_PML, pmlFile.c_str()); + std::ofstream ofs(pmlFile.c_str()); + if (!ofs.is_open()) { + WriteMsg::write(CMSG_CANNOT_OPEN_FILE, pmlFile.c_str()); + } else { + VisitorPYTHONML* visitor = new VisitorPYTHONML(ofs, "", NULL, false); + AlgorithmPreorder ap; + ap.run(*factory, *visitor); + delete visitor; + ofs.close(); + } + } + + setElapsedTime(&dumpTime); + setElapsedTime(&totalTime); + + delete factory; + + WriteMsg::write( + CMSG_STATISTICS, + parseTime / 100.0f, + saveTime / 100.0f, + dumpTime / 100.0f, + totalTime / 100.0f, + maxMem / 1048576, + parseErrors + ); + + MAIN_END + + return 0; +} diff --git a/cl/PAN/src/plloc.cpp b/cl/PAN/src/plloc.cpp new file mode 100644 index 0000000..dc4dfd7 --- /dev/null +++ b/cl/PAN/src/plloc.cpp @@ -0,0 +1,186 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/PlLOC.h" + +#include +#include +#include +#include +#include +#include "../inc/messages.h" + +using namespace std; +using namespace columbus; +using namespace common; + + +int PlLOC::strreplace(std::string &str, const std::string &find_what, const std::string &replace_with) { + std::string::size_type pos=0; + int count = 0; + + while((pos=str.find(find_what, pos))!=std::string::npos) { + str.erase(pos, find_what.length()); + str.insert(pos, replace_with); + pos+=replace_with.length(); + count++; + } + + return count; +} + +std::string PlLOC::modifyEscapedChar( std::string str){ + std::string::size_type pos=0; + while((pos=str.find('\\', pos))!=std::string::npos) { + str.erase(pos, 2); + str.insert(pos, "$$"); + pos+=2; + } + return str; +} + +int PlLOC::strcount(std::string &str, const std::string &find_what, int endPos) { + std::string::size_type pos=0; + int count = 0; + + while((pos=str.find(find_what, pos))!=std::string::npos) { + pos+=find_what.length(); + count++; + } + + return count; +} + + +std::string PlLOC::leftrim(std::string str) { + size_t start = str.find_first_not_of(" \t\n\r"); + if(start == std::string::npos) return ""; + return str.substr(start, str.length()); +} + +int PlLOC::findFirst(const std::string &line, vector tokens, std::string &significantToken, int from){ + size_t lastTokenPos = string::npos; + for (vector::iterator token = tokens.begin(); token != tokens.end(); ++token){ + size_t tokenPos = line.find(*token, from); + if (tokenPos != string::npos){ + if (lastTokenPos == string::npos || tokenPos < lastTokenPos){ + lastTokenPos = tokenPos; + significantToken = *token; + } + } + } + return lastTokenPos; +} + +vector PlLOC::processLines(const std::string& name, PBuilder& builder) { + builder.setPath(const_cast(name)); + std::string myline; + int lc = 0; + int moduleEndLine = lc; + vector lines; + bool docstring = false; + + ifstream infile(name.c_str ()); + + if (!infile.is_open()) { + WriteMsg::write(CMSG_CANNOT_OPEN_FILE, name.c_str()); + exit(1); + } + + vector significantTokens; // search for these strings in the line, the search order is important + significantTokens.push_back("\"\"\""); + significantTokens.push_back("'''"); + significantTokens.push_back("\""); + significantTokens.push_back("'"); + string multiLineLiteralStarterString = ""; + while (1) { + getline(infile, myline); + ++lc; + //process comments + string lineWithoutBackslashes = modifyEscapedChar(myline); // use this version of the line when search for quotes + + string firstSignificantToken; + int bannedRangeEndPos = 0; + int bannedRangeStartPos = static_cast(string::npos); + // if we are in a multi-line stringliteral, than search for the closer quote from 0 col + if (!multiLineLiteralStarterString.empty()){ + firstSignificantToken = multiLineLiteralStarterString; + bannedRangeStartPos = -1 * static_cast(firstSignificantToken.length()); + } else { // else search for the first quote in the line + bannedRangeStartPos = findFirst(lineWithoutBackslashes, significantTokens, firstSignificantToken, bannedRangeEndPos); + } + set bannedPositions; + while (bannedRangeStartPos != static_cast(string::npos)){ + bannedRangeEndPos = lineWithoutBackslashes.find(firstSignificantToken, bannedRangeStartPos + firstSignificantToken.length()); // find the closer quote for the string literal + if (bannedRangeEndPos == static_cast(string::npos)){ //there is no closer quote, we ar in a multi-line literal + bannedRangeEndPos = myline.length(); // ban the whole line + multiLineLiteralStarterString = firstSignificantToken; // store the literal starter token + } else { + multiLineLiteralStarterString = ""; + bannedRangeEndPos += firstSignificantToken.length(); + } + for (int i = bannedRangeStartPos; i < bannedRangeEndPos; ++i){ + bannedPositions.insert(i); + } + bannedRangeStartPos = findFirst(lineWithoutBackslashes, significantTokens, firstSignificantToken, bannedRangeEndPos); + } + + int hashPos = 0; + while ( (hashPos = myline.find('#', hashPos) ) != static_cast(string::npos)){ + if (bannedPositions.find(hashPos) == bannedPositions.end()){ + NodeId doc = builder.buildComment(myline.substr(hashPos)); + builder.setIncreasedPosition(doc, lc, hashPos, lc, myline.length()); + commentMap.insert(std::pair(lc, doc)); + break; + } + hashPos++; + } + //process comments end + + std::string trimmedLine = leftrim(myline); // remove leading white spaces + if (trimmedLine.length() != 0){ + moduleEndLine = lc; + } + if (!docstring) { + if (trimmedLine.length() == 0) { + } else if (trimmedLine[0] == '#') { + } else { + lines.push_back(lc); + } + } else { + lines.push_back(lc); + } + + bool oddQuote = strcount(trimmedLine, "\"\"\"", trimmedLine.length()) % 2 == 1; + bool oddApos = strcount(trimmedLine, "'''", trimmedLine.length()) % 2 == 1; + if (oddQuote || oddApos) docstring = !docstring; + + if (infile.eof()) break; + } + + infile.close(); + lines.push_back(moduleEndLine); // the last stored number is the module's endLine + return lines; +} + +std::map& PlLOC::getCommentMap(){ + return commentMap; +} + diff --git a/cl/PAN2Lim/CMakeLists.txt b/cl/PAN2Lim/CMakeLists.txt new file mode 100644 index 0000000..9f98e89 --- /dev/null +++ b/cl/PAN2Lim/CMakeLists.txt @@ -0,0 +1,14 @@ +set (PROGRAM_NAME PAN2Lim) + +set (SOURCES + src/main.cpp + src/python2lim.cpp + + inc/messages.h + inc/python2lim.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} lim python strtable common csi io ${COMMON_EXTERNAL_LIBRARIES}) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/PAN2Lim/inc/messages.h b/cl/PAN2Lim/inc/messages.h new file mode 100644 index 0000000..8d352c7 --- /dev/null +++ b/cl/PAN2Lim/inc/messages.h @@ -0,0 +1,56 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PAN2LIM_MESSAGE_H +#define _PAN2LIM_MESSAGE_H + +//cl arg descriptions +#define CLARG_LIM "Name of the output LIM file" +#define CLARG_NOFILTER "Filter files are not used" +#define CLARG_MAXMEM "Maximum usable memory (not converted files are written out)" + +//ERROR messages +#define CMSG_MISSING_INPUT_FILES common::WriteMsg::mlError, "Error: Missing input files!\n" +#define CMSG_CANNOT_OPEN_FILE common::WriteMsg::mlWarning, "Warining: Cannot open file: \"%s\"\n" +#define CMSG_NEGATIVE_MEMORY_VALUE common::WriteMsg::mlError, "Error: Wrong (negative) maximum memory value.\n" +#define CMSG_INVALID_MEMORY_VALUE common::WriteMsg::mlError, "Error: Invalid maxmem value!\n" +#define CMSG_FILTER_FILE_DEPRECATED common::WriteMsg::mlWarning, "Warning: Filter file (%s) is older than the input file (.lim). Filter file is not used.\n" +#define CMSG_CANNOT_OPEN_FILTER_FILE common::WriteMsg::mlWarning, "Warning: Filter file cannot be loaded (%s)\n" +#define CMSG_MAXMEM_EXCEEDED common::WriteMsg::mlError, "Error: Maximum memory exceeded, the remaining files are skipped.\n" + +#define CMSG_WARN_CANNOT_READ_FILE common::WriteMsg::mlWarning, "Warning: File \"%s\" cannot be loaded\n" +#define CMSG_WARN_CANNOT_WRITE_FILE common::WriteMsg::mlWarning, "Warning: File \"%s\" cannot be saved\n" +#define CMSG_CONVERTING_FILE common::WriteMsg::mlDebug, "Converting file: %s\n" +#define CMSG_SAVING_FILE common::WriteMsg::mlDebug, "Saving \"%s\" file.\n" + +//Normal messages +#define CMSG_LOADING_FILE common::WriteMsg::mlNormal, "Loading file: %s\n" +#define CMSG_STATISTICS common::WriteMsg::mlNormal, "\nStatistics:\n\ +\tConverting time : %10.2fs\n\ +\tSaving asg time : %10.2fs\n\ +\tTotal time : %10.2fs\n\ +\tPeak memory usage : %10luMB\n\ +\tNumber of not existed files : %10d\n\n" + +//Exception messages +#define CMSG_INVALID_NODEKIND "invalid nodeKind" +#define CMSG_WRONG_ASG "Wrong ASG" + +#endif diff --git a/cl/PAN2Lim/inc/python2lim.h b/cl/PAN2Lim/inc/python2lim.h new file mode 100644 index 0000000..5c55b16 --- /dev/null +++ b/cl/PAN2Lim/inc/python2lim.h @@ -0,0 +1,306 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef PYTHON2LIM_H +#define PYTHON2LIM_H + +#include +#include +#include + +namespace columbus { namespace python { + + class Python2LimVisitor : public python::asg::VisitorAbstractNodes { + public: + + typedef std::map Key2IdMapType; + + Python2LimVisitor(python::asg::Factory& pyFact, lim::asg::Factory& limFact, LimOrigin& origin, const std::string& componentName, Key2IdMapType& key2Ids); + virtual ~Python2LimVisitor(); + + virtual void visit (const columbus::python::asg::base::Positioned&, bool); + + /* visiting MODULE */ + virtual void visit (const columbus::python::asg::module::Package&, bool); + virtual void visitEnd (const columbus::python::asg::module::Package&, bool); + virtual void visit (const columbus::python::asg::module::Module&, bool); + virtual void visitEnd (const columbus::python::asg::module::Module&, bool); + + /* visiting STATEMENT */ + virtual void visit (const columbus::python::asg::statement::ClassDef&, bool); + virtual void visitEnd (const columbus::python::asg::statement::ClassDef&, bool); + virtual void visit (const columbus::python::asg::statement::FunctionDef&, bool); + virtual void visitEnd (const columbus::python::asg::statement::FunctionDef&, bool); + virtual void visit (const columbus::python::asg::statement::Parameter&, bool); + + virtual void visit (const columbus::python::asg::statement::Try&, bool); + virtual void visitEnd (const columbus::python::asg::statement::Try&, bool); + virtual void visit (const columbus::python::asg::statement::With&, bool); + virtual void visitEnd (const columbus::python::asg::statement::With&, bool); + virtual void visit (const columbus::python::asg::statement::Iteration&, bool); + virtual void visitEnd (const columbus::python::asg::statement::Iteration&, bool); + virtual void visit (const columbus::python::asg::statement::If&, bool); + virtual void visitEnd (const columbus::python::asg::statement::If&, bool); + virtual void visit (const columbus::python::asg::statement::Handler&, bool); + virtual void visit (const columbus::python::asg::statement::Global&, bool); + virtual void visit (const columbus::python::asg::statement::Raise&, bool); + virtual void visit (const columbus::python::asg::statement::Assert&, bool); + virtual void visit (const columbus::python::asg::statement::Pass&, bool); + virtual void visit (const columbus::python::asg::statement::Assign&, bool); + virtual void visit (const columbus::python::asg::statement::Delete&, bool); + virtual void visit (const columbus::python::asg::statement::ImportStatement&, bool); + virtual void visit (const columbus::python::asg::statement::Return&, bool); + virtual void visit (const columbus::python::asg::statement::Print&, bool); + virtual void visit (const columbus::python::asg::statement::Break&, bool); + virtual void visit (const columbus::python::asg::statement::Continue&, bool); + virtual void visit (const columbus::python::asg::statement::Exec&, bool); + virtual void visit (const columbus::python::asg::statement::Alias&, bool); + + /* visiting EXPRESSION */ + virtual void visit (const columbus::python::asg::expression::Identifier&, bool); + virtual void visit (const columbus::python::asg::expression::IfExpression&, bool); + virtual void visit (const columbus::python::asg::expression::Call&, bool); + virtual void visit (const columbus::python::asg::expression::BinaryLogical&, bool); + virtual void visit (const columbus::python::asg::expression::Expression&, bool); + + virtual void finishVisit(); + + + static void finalize( const columbus::lim::asg::Factory& factory ); + static void setLineMetrics( columbus::lim::asg::base::Base& node ); + + + private: + + struct MethodInfo; + struct ScopeInfo; + + protected: + + static void setPackageLines( columbus::lim::asg::logical::Package& package ); + + /** + * \brief Returns the id of a lim node + * \param id [in] The id of python node whose lim id is needed. + * \return The lim id of the python node. + */ + NodeId getLimNodeId(NodeId pythonId); + + /** + * \brief Creates lim::asg::Base::base node or return it if it already exists. + * \param _node [in] The python node whose lim node pair is created. + * \return The lim node. + */ + lim::asg::base::Base& createIncompleteLimNode(const python::asg::base::Base& _node); + + /** + * \brief Creates lim::asg::Base::base node or return it if it already exists. + * \param _node [in] The python node whose lim node pair is created. + * \return The lim node. + */ + lim::asg::base::Base& createCompleteLimNode(const python::asg::base::Base& _node); + + /** + * \brief Creates a lim::asg::Base::base node or return it if it already exist and the node + * is marked complete or incomplete according to the second parameter. + * \param _node [in] The python node whose lim node pair is created. + * \param isComplete [in] Deciding whether a complete or an incomplete node is created. + * \return The lim node. + */ + lim::asg::base::Base& createLimNode(const python::asg::base::Base& _node, bool isComplete); + + /** + * \brief Converts data for lim::asg::logical::Member + * \param _node [in] The python node which is converted. + * \param limMember [in] The lim node whose data will be set. + */ + void setLimMemberData(const python::asg::base::Base& _node, lim::asg::logical::Member& limMember); + + /** + * \brief Converts data for lim::asg::logical::Class + * \param _node [in] The python node which is converted. + * \param limClass [in] The lim node whose data will be set. + */ + void setLimClassData(const python::asg::statement::Statement& _node, lim::asg::logical::Class& limClass); + + /** + * \brief Converts data for lim::asg::logical::Method + * \param _node [in] The python node which is converted. + * \param limMethod [in] The lim node whose data will be set. + */ + void setLimMethodData(const python::asg::statement::Statement& _node, lim::asg::logical::Method& limMethod); + + /** + * \brief Converts data for a fictive lim method, which contains statements and expressions which are not in a class method or in a module function. + * \param fictiveLimMethod [in] The lim node whose data will be set. + */ + void setFictiveMethodData(lim::asg::logical::Method& fictiveLimMethod); + + /** + * \brief Converts data for lim::asg::logical::Attribute + * \param _node [in] The python node which is converted. + * \param limAttribute [in] The lim node whose data will be set. + */ + void setLimAttributeData(const python::asg::expression::Identifier& _node, lim::asg::logical::Attribute& limAttribute); + + /** + * \brief Sets the component for the node. + * \param limNodeId [in] The node whose component data is set. + */ + void setComponentData(NodeId limNodeId) const; + + /** + * \brief Creates a fictive method for the given lim::asg::logical::Scope node. + * \param limNode [in] The lime node. + * \return The lim method node. + */ + lim::asg::logical::Method* createFictiveMethod(lim::asg::logical::Scope& limNode); + + /** + * \brief Sets collected metrics and relations for lim::asg::logical::Method + * \param limMethod [in] The lim node whose data will be set. + * \param methodInfo [in] The collected info. + */ + void fillCollectedMethodData(lim::asg::logical::Method& limMethod, MethodInfo* methodInfo); + + /** + * \brief Creates lim::asg::type::Type node + */ + NodeId createType(NodeId pyType); + + void processDocstring(lim::asg::logical::Member& member, python::asg::base::Docstring* docstring); + + /** + * \brief Returns the parent of a python node (it would be FunctionDef, ClassDef, Module) + */ + NodeId getPythonParent(const python::asg::base::Base& _node); + + /** + * \brief Increases the value of NOS if the statement is in a function. + */ + void incNos(const python::asg::base::Positioned& _node); + + /** + * \brief Increases the value of NOB if the statement is in a function. + */ + void incNob(const python::asg::base::Base& _node); + + /** + * \brief Returns true if the node is an If that is the FalseSubstatement of another If. + */ + bool eligibleForNLE(const python::asg::statement::If& _node); + + /** + * \brief Increases the current values of NL and NLE. + */ + void incNL(bool NLE); + + /** + * \brief Decreases the current values of NL and NLE. + */ + void decNL(bool NLE); + + /** + * \brief Create File node from the give SourcePosition. + */ + lim::asg::physical::File& buildFileNode(const python::asg::Range& range); + + private: + /** \internal \brief Map type for mapping python id to lim id. */ + typedef std::map NodeIdMapType; + + /** \internal \brief Map type for mapping string table Key to lim NodeId. */ + typedef std::map KeyNodeIdMapType; + + typedef std::map > NodeId2UnsignedIntervalSetMap; + + /** \internal \brief python factory */ + python::asg::Factory& pyFact; + /** \internal \brief lim factory */ + lim::asg::Factory& limFact; + /** \internal \brief lim origin */ + LimOrigin& origin; + + /** \internal \brief For mapping from python id to lim id. */ + NodeIdMapType pythonId2limId; + + /** \internal \brief The id of the component.*/ + NodeId actualCompNodeId; + + /** \internal \brief Set for storing incomplete nodes */ + std::set incompleteNodes; + + /** \internal \brief For mapping from python string table key to lim id. */ + Key2IdMapType& pythonKey2LimId; + + /** \internal \brief Map for storing python type to lim type */ + std::map PythonType2LimTypeMap; + + + struct ScopeInfo { + public: + ScopeInfo() : node(NULL), limNode(NULL), fictiveMethodInfo(NULL), CLOC(0) {} + virtual ~ScopeInfo() {} + virtual MethodInfo* getMethodInfo() { return fictiveMethodInfo; } + + const python::asg::base::Base* node; + lim::asg::base::Base* limNode; + MethodInfo* fictiveMethodInfo; + + unsigned short CLOC; + + private: + ScopeInfo(const ScopeInfo&); + ScopeInfo& operator=(const ScopeInfo&); + }; + + struct MethodInfo : public ScopeInfo { + public: + MethodInfo() : NOS(0), NOB(1), NL(0), NLE(0), currentNL(0), currentNLE(0) {} + virtual ~MethodInfo() {} + virtual MethodInfo* getMethodInfo() { return this; } + + unsigned int NOS; + unsigned int NOB; + unsigned short NL; + unsigned short NLE; + + unsigned short currentNL; + unsigned short currentNLE; + + std::set calls; + std::set accessesAttribute; + std::set instantiates; + std::set throws; + std::set uses; + }; + + /** \internal \brief Stack for the current node info */ + std::vector infoStack; + + /** \internal \brief Map for storing the already built FileNodes */ + KeyNodeIdMapType pathFileNodeIdMap; + + /** \internal \brief */ + NodeId2UnsignedIntervalSetMap fileNodeIdCommentLinesMap; + }; + +}} +#endif //PYTHON2LIM_H diff --git a/cl/PAN2Lim/src/main.cpp b/cl/PAN2Lim/src/main.cpp new file mode 100644 index 0000000..1b1ed5c --- /dev/null +++ b/cl/PAN2Lim/src/main.cpp @@ -0,0 +1,365 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +/******************************************************************** +* DEFINES AND INCLUDES * +********************************************************************/ + +#define PROGRAM_NAME "PAN2Lim" +#define EXECUTABLE_NAME PROGRAM_NAME + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../inc/python2lim.h" +#include "../inc/messages.h" + +using namespace std; +using namespace columbus; +using namespace common; + + +/******************************************************************** +* ARGUMENT PROCESSING * +********************************************************************/ + +namespace columbus { namespace PAN2Lim { namespace options +{ + using namespace std; + + // main option parser from command line arguments + void parse( int argc, char** argv); + + // parameters + static std::string listFile; // file containing the files to be converted + static std::list inputFiles; // the processed file list - together with ppFile + + static std::string out; + + static std::vector fltpVector; // the processed filter entries + static bool noFilter = false; + + static std::string maxmem; + static unsigned maxMem = 0; + + void checkInputFiles(); + void checkMaxMem(); + + void parse( int argc, char** argv) + { + // read parameters + MainInit( argc, argv, "-"); + + // validate parameters + checkInputFiles(); + checkMaxMem(); + } + + void checkInputFiles() + { + if ( !listFile.empty() ) + { + ifstream ifs( listFile.c_str() ); + if ( ifs.is_open() ) + { + string tmp; + while ( getline(ifs, tmp) ) + { + if ( !tmp.length() ) + { + continue; + } + if ( tmp[tmp.length()-1] == 0xD ) // handle DOS line-ends in unix + { + inputFiles.push_back( tmp.substr(0,tmp.length()-1) ); + } + else + { + inputFiles.push_back( tmp ); + } + } + ifs.close(); + } + } + + if (inputFiles.size() == 0) + { + WriteMsg::write(CMSG_MISSING_INPUT_FILES); + clError(); + } + + if ( inputFiles.size() == 1 ) + { + if ( out.empty() ) + { + string outname = *inputFiles.begin(); + out = outname.substr(0, outname.find_last_of('.')) + ".lim"; + } + } + else + { + if (out.empty()) + { + out = "noname.lim"; + } + } + } + + void checkMaxMem() + { + maxMem = 0; + if ( !maxmem.empty() ) + { + int mm = 0; + if ( str2int(maxmem, mm) ) + { + if ( 0 < mm ) + { + maxMem = static_cast(mm * 1024 * 1024); + } + else + { + WriteMsg::write(CMSG_NEGATIVE_MEMORY_VALUE); + clError(); + } + } + else + { + WriteMsg::write(CMSG_INVALID_MEMORY_VALUE); + clError(); + } + } + } + +}}} // end options, end PAN2Lim, end columbus + + +using namespace columbus::PAN2Lim; + +// callbacks for argument processing +static bool ppList ( const Option *o, char *argv[] ) { options::listFile = argv[0]; return true; } +static bool ppOut ( const Option *o, char *argv[] ) { options::out = argv[0]; return true; } +static bool ppNoFilt ( const Option *o, char *argv[] ) { options::noFilter = true; return true; } +static bool ppMaxMem ( const Option *o, char *argv[] ) { options::maxmem = argv[0]; return true; } +static void ppFile ( char *filename ) { columbus::PAN2Lim::options::inputFiles.push_back( filename ); } + + +// the list of valid options +const Option OPTIONS_OBJ [] = +{ + { false, "-out", 1, "filename", 0, OT_WC | OT_WS, ppOut, NULL, CLARG_LIM}, + { false, "-nofilter", 0, "", 0, OT_NONE, ppNoFilt, NULL, CLARG_NOFILTER}, + { false, "-maxmem", 1, "number", 0, OT_WC, ppMaxMem, NULL, CLARG_MAXMEM}, + CL_INPUT_LIST + COMMON_CL_ARGS +}; + + +/******************************************************************** +* UTILITY FUNCTIONS * +********************************************************************/ + +void loadFilter( python::asg::Factory& fact, const string& file ) +{ + string flt = pathRemoveExtension(file) + ".fpsi"; + if ( fileTimeCmp(flt, file) == -1 ) + { + WriteMsg::write(CMSG_FILTER_FILE_DEPRECATED, flt.c_str()); + return; + } + + try + { + fact.loadFilter( flt ); + } + catch ( IOException e ) + { + WriteMsg::write(CMSG_CANNOT_OPEN_FILTER_FILE, flt.c_str()); + } +} + +static inline void setStartTime(uint64_t *time) +{ + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system; +} + +static inline void setElapsedTime(uint64_t *time) +{ + timestat usedtime= getProcessUsedTime(); + *time= usedtime.user + usedtime.system - *time; +} + +static inline void updateMemStat(uint64_t *max_mem) +{ + memstat ms = getProcessUsedMemSize(); + if (*max_mem < ms.size) { + *max_mem = ms.size; + } +} + +int main( int argc, char* argv[] ) +{ + int exitCode = 0; + MAIN_BEGIN + + uint64_t totalTime; + uint64_t conversionTime; + uint64_t saveTime; + + uint64_t maxMem = 0; + + int missingFiles = 0; + + setStartTime( &totalTime ); + + // preparing comman line options + columbus::PAN2Lim::options::parse( argc, argv); + + // lim graph + RefDistributorStrTable limStrTable; + lim::asg::Factory limFactory( limStrTable, "", lim::asg::limLangPython ); + + // origin + LimOrigin origin; + + setStartTime( &conversionTime ); + + for ( list::const_iterator it = PAN2Lim::options::inputFiles.begin(); it != PAN2Lim::options::inputFiles.end(); ++it ) + { + // creating factory + RefDistributorStrTable javaStrTable; + python::asg::Factory factory( javaStrTable ); + + // load schema instance + WriteMsg::write(CMSG_LOADING_FILE, it->c_str()); + + CsiHeader header; + try + { + factory.load( it->c_str(), header ); + } + catch ( IOException e ) + { + WriteMsg::write(CMSG_WARN_CANNOT_READ_FILE, it->c_str()); + exitCode = 1; + missingFiles++; + continue; + } + + // component name + string compPath; + header.get(CsiHeader::csih_OriginalLocation, compPath); + if ( compPath.empty() ) compPath = *it; + + // filter init + if ( ! PAN2Lim::options::noFilter ) + { + factory.turnFilterOn(); + factory.initializeFilter(); + loadFilter( factory, *it ); + + factory.turnFilterOff(); + } + + // PAN2Lim visitor is created and called + WriteMsg::write(CMSG_CONVERTING_FILE, it->c_str()); + + python::Python2LimVisitor::Key2IdMapType uname2NodeId; + + python::Python2LimVisitor visitor(factory, limFactory, origin, compPath, uname2NodeId); + python::asg::AlgorithmPreorder().run( factory, visitor, *factory.getRoot() ); + + updateMemStat( &maxMem ); + + if ( PAN2Lim::options::maxMem != 0 && maxMem > PAN2Lim::options::maxMem ) + { + WriteMsg::write( CMSG_MAXMEM_EXCEEDED ); + break; + } + } + + // finalizing and cleanup + python::Python2LimVisitor::finalize( limFactory ); + + updateMemStat( &maxMem ); + + setElapsedTime( &conversionTime ); + setStartTime( &saveTime ); + + // saving the lim graph + WriteMsg::write(CMSG_SAVING_FILE, options::out.c_str()); + + std::list limHeader; + limHeader.push_back( &origin ); + + try + { + limFactory.save( PAN2Lim::options::out, limHeader ); + } + catch (IOException e) + { + WriteMsg::write(CMSG_WARN_CANNOT_WRITE_FILE, options::out.c_str()); + } + + // saving the filter + string filterfile = options::out.substr(0, options::out.find_last_of('.')) + ".flim"; + try + { + limFactory.saveFilter(filterfile); + } + catch (IOException e) + { + WriteMsg::write(CMSG_WARN_CANNOT_WRITE_FILE, filterfile.c_str()); + } + + setElapsedTime( &saveTime ); + setElapsedTime( &totalTime ); + + WriteMsg::write( + CMSG_STATISTICS, + conversionTime / 100.0f, + saveTime / 100.0f, + totalTime / 100.0f, + maxMem / 1048576, + missingFiles + ); + + MAIN_END + + return exitCode; +} diff --git a/cl/PAN2Lim/src/python2lim.cpp b/cl/PAN2Lim/src/python2lim.cpp new file mode 100644 index 0000000..2fb753c --- /dev/null +++ b/cl/PAN2Lim/src/python2lim.cpp @@ -0,0 +1,1106 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/python2lim.h" +#include "../inc/messages.h" +#include + + +using namespace std; + +using namespace columbus::python::asg; + +#define SAFE_EDGE( node, name, type, param ) \ + do \ + { \ + bool node##_found = false; \ + lim::asg::ListIterator node##_it = node.get##name##ListIteratorBegin(); \ + for ( ; node##_it != node.get##name##ListIteratorEnd(); ++node##_it ) \ + { \ + if ( node##_it->getId() == param ) { node##_found = true; break; } \ + } \ + if ( ! node##_found ) \ + { \ + node.add##name( param ); \ + } \ + } \ + while ( false ) + + +namespace columbus { namespace python { + + Python2LimVisitor::Python2LimVisitor(columbus::python::asg::Factory& pyFact, + columbus::lim::asg::Factory& limFact, + LimOrigin& origin, + const std::string& componentName, + columbus::python::Python2LimVisitor::Key2IdMapType& key2Ids + ): + pyFact(pyFact), + limFact(limFact), + origin(origin), + actualCompNodeId(0), + pythonKey2LimId(key2Ids) + { + pythonId2limId.insert(make_pair(pyFact.getRoot()->getId(), limFact.getRoot()->getId())); + + limFact.getRoot()->setName((dynamic_cast(*pyFact.getRoot())).getName()); + limFact.getRoot()->setMangledName(python::asg::Common::getUniqueName(*pyFact.getRoot())); + limFact.getRoot()->setDemangledName(python::asg::Common::getUniqueName(*pyFact.getRoot())); + + lim::asg::base::Component& actualComp = limFact.createComponent(componentName); + actualCompNodeId = actualComp.getId(); + limFact.getComponentRootRef().addContains(&actualComp); + + origin.addCompIdCppIdLimIdToMap( actualCompNodeId, pyFact.getRoot()->getId(), limFact.getRoot()->getId() ); + } + + + Python2LimVisitor::~Python2LimVisitor() { + } + + void Python2LimVisitor::visit(const columbus::python::asg::base::Positioned& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + if ( !(Common::getIsComment(_node) || Common::getIsDocstring(_node)) ){ + + unsigned commentLoc = 0; + for(ListIterator it =_node.getCommentsListIteratorBegin(); it != _node.getCommentsListIteratorEnd(); ++it){ + commentLoc += static_cast(std::count(it->getText().begin(), it->getText().end(), '\n') + 1); + } + infoStack.back()->CLOC += commentLoc; + } else { + Range range = _node.getPosition(); + lim::asg::physical::File& file = buildFileNode(range); + fileNodeIdCommentLinesMap[file.getId()] += boost::icl::discrete_interval::closed(range.getLine(), range.getEndLine()); + } + } + +/********** + * MODULE * + **********/ + + void Python2LimVisitor::visit(const columbus::python::asg::module::Package& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + lim::asg::logical::Package& limPackageNode = dynamic_cast(createCompleteLimNode(_node)); + setComponentData(limPackageNode.getId()); + setLimMemberData(_node, limPackageNode); + } + + + void Python2LimVisitor::visitEnd(const columbus::python::asg::module::Package& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + } + + + void Python2LimVisitor::visit(const columbus::python::asg::module::Module& _node, bool callVirtualBase ) { + + ScopeInfo* scopeInfo = new ScopeInfo(); + infoStack.push_back(scopeInfo); + scopeInfo->node = &_node; + + lim::asg::logical::Package& limPackageNode = dynamic_cast(createCompleteLimNode(_node)); + + processDocstring(limPackageNode, _node.getDocstring()); + scopeInfo->limNode = &limPackageNode; + createFictiveMethod(limPackageNode); + + limPackageNode.setPackageKind( lim::asg::pkModule ); + + // map Module line info to the lim Package + limPackageNode.setTLOC( _node.getPosition().getEndLine() - _node.getPosition().getLine() + 1 ); + limPackageNode.setTLLOC( _node.getLloc() ); + + // map Module line info to the corresponding lim File too + lim::asg::physical::File& file = buildFileNode( _node.getPosition()); + file.setLOC( _node.getPosition().getEndLine() - _node.getPosition().getLine() + 1 ); + file.setLLOC( _node.getLloc() ); + + setComponentData(limPackageNode.getId()); + setLimMemberData(_node, limPackageNode); + + VisitorAbstractNodes::visit(_node, callVirtualBase); + } + + + void Python2LimVisitor::visitEnd(const columbus::python::asg::module::Module& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + ScopeInfo* scopeInfo = infoStack.back(); + fillCollectedMethodData(dynamic_cast(*scopeInfo->getMethodInfo()->limNode), scopeInfo->getMethodInfo()); + dynamic_cast(*scopeInfo->limNode).setCommentLines(scopeInfo->CLOC); + + delete scopeInfo->fictiveMethodInfo; + delete scopeInfo; + infoStack.pop_back(); + } + +/************* + * STATEMENT * + *************/ + + void Python2LimVisitor::visit(const columbus::python::asg::statement::ClassDef& _node, bool callVirtualBase ) { + ScopeInfo* scopeInfo = new ScopeInfo(); + infoStack.push_back(scopeInfo); + scopeInfo->node = &_node; + + lim::asg::logical::Class& limClassNode = dynamic_cast(createCompleteLimNode(_node)); + processDocstring(limClassNode, _node.getDocstring()); + + scopeInfo->limNode = &limClassNode; + createFictiveMethod(limClassNode); + + setComponentData(limClassNode.getId()); + setLimMemberData(_node, limClassNode); + setLimClassData(_node, limClassNode); + + // (L)LOC from PAN is really T(L)LOC + limClassNode.setTLOC( _node.getPosition().getEndLine() - _node.getPosition().getLine() + 1 ); + limClassNode.setTLLOC( _node.getLloc() ); + + if(!_node.getBaseSpecifierIsEmpty()) { + set subSet; + ListIterator it = _node.getBaseSpecifierListIteratorBegin(); + for(; it != _node.getBaseSpecifierListIteratorEnd(); ++it){ + const statement::BaseSpecifier& bsNode = *it; + if(bsNode.getDerivesFrom() && python::asg::Common::getIsClassDef(*bsNode.getDerivesFrom())) { + python::asg::statement::ClassDef& classDef = dynamic_cast(*bsNode.getDerivesFrom()); + if (classDef.getRefersTo()) { + subSet.insert(createType(classDef.getRefersTo()->getId())); + } + } + } + set::const_iterator subIt; + for(subIt = subSet.begin(); subIt != subSet.end(); subIt++) { + limClassNode.addIsSubclass(*subIt); + } + } + + VisitorAbstractNodes::visit(_node, callVirtualBase); + } + + + void Python2LimVisitor::visitEnd(const columbus::python::asg::statement::ClassDef& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + ScopeInfo* scopeInfo = infoStack.back(); + fillCollectedMethodData(dynamic_cast(*scopeInfo->getMethodInfo()->limNode), scopeInfo->getMethodInfo()); + dynamic_cast(*scopeInfo->limNode).setCommentLines(scopeInfo->CLOC); + + delete scopeInfo->fictiveMethodInfo; + delete scopeInfo; + infoStack.pop_back(); + } + + + void Python2LimVisitor::visit(const columbus::python::asg::statement::FunctionDef& _node, bool callVirtualBase ) { + + MethodInfo* methodInfo = new MethodInfo(); + infoStack.push_back(methodInfo); + methodInfo->node = &_node; + + lim::asg::logical::Method& limMethodNode = dynamic_cast(createCompleteLimNode(_node)); + processDocstring(limMethodNode, _node.getDocstring()); + + methodInfo->limNode = &limMethodNode; + + setComponentData(limMethodNode.getId()); + setLimMemberData(_node, limMethodNode); + setLimMethodData(_node, limMethodNode); + + // (L)LOC from PAN is really T(L)LOC + limMethodNode.setTLOC( _node.getPosition().getEndLine() - _node.getPosition().getLine() + 1 ); + limMethodNode.setTLLOC( _node.getLloc() ); + + VisitorAbstractNodes::visit(_node, callVirtualBase); + } + + + void Python2LimVisitor::visitEnd(const columbus::python::asg::statement::FunctionDef& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + MethodInfo* methodInfo = dynamic_cast(infoStack.back()); + fillCollectedMethodData(dynamic_cast(*methodInfo->limNode), methodInfo); + dynamic_cast(*methodInfo->limNode).setCommentLines(methodInfo->CLOC); + + delete methodInfo; + infoStack.pop_back(); + } + + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Parameter& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + if (_node.getParent() && python::asg::Common::getIsFunctionDef(*_node.getParent())) { // TODO lambda? + if (!infoStack.empty()) { + MethodInfo* methodInfo = dynamic_cast(infoStack.back()); + + lim::asg::logical::Parameter& limParam = dynamic_cast(createCompleteLimNode(_node)); + dynamic_cast(*methodInfo->limNode).addParameter(limParam.getId()); + + if(_node.getRefersTo()) { + python::asg::module::Object& objNode = dynamic_cast(*_node.getRefersTo()); + NodeId limType = createType(objNode.getId()); + if(limFact.getExist(limType)) { + limParam.setType(limType); + } + limParam.setParamKind(lim::asg::pmkInOut); + } + } + } + } + + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Try& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + incNL( true ); + } + + void Python2LimVisitor::visitEnd(const columbus::python::asg::statement::Try& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + decNL( true ); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::With& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + incNL( true ); + } + + void Python2LimVisitor::visitEnd(const columbus::python::asg::statement::With& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + decNL( true ); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Iteration& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNL(true); + incNos(_node); + incNob(_node); + } + + void Python2LimVisitor::visitEnd(const columbus::python::asg::statement::Iteration& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + decNL(true); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::If& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNL(eligibleForNLE(_node)); + incNos(_node); + incNob(_node); + } + + void Python2LimVisitor::visitEnd(const columbus::python::asg::statement::If& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visitEnd(_node, callVirtualBase); + + decNL(eligibleForNLE(_node)); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Handler& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNob(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Global& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Raise& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + expression::Expression* expr = _node.getTypeExpression(); + if(expr) { + type::Type* type = expr->getType(); + if(type) { + NodeId limType = createType(type->getId()); + if(limFact.getExist(limType)) { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->throws.insert(limType); + } + } + } + } + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Assert& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Pass& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Assign& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Delete& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::ImportStatement& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Return& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Print& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Break& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Continue& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Exec& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + incNos(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::statement::Alias& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + base::Base* ref = _node.getRefersTo(); + if(ref) { + if(python::asg::Common::getIsObject(*ref)) { + NodeId limType = createType(ref->getId()); + if(limFact.getExist(limType)) { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->uses.insert(limType); + } + } + } + } + } + +/************** + * EXPRESSION * + **************/ + + void Python2LimVisitor::visit(const columbus::python::asg::expression::Identifier& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + bool isLimAttr = false; + + if (_node.getParent() && python::asg::Common::getIsTargetList(*_node.getParent()) && + _node.getParent()->getParent() && python::asg::Common::getIsAssign(*_node.getParent()->getParent())) + { + NodeId pyParent = getPythonParent(_node); + if (pyParent) { + if (!python::asg::Common::getIsFunctionDef(pyFact.getRef(pyParent))) { // TODO global variables + isLimAttr = true; + } + } + } + + if (isLimAttr) { + lim::asg::logical::Attribute& limAttrib = dynamic_cast(createCompleteLimNode(_node)); + + if (limAttrib.getIsContainedInIsEmpty()) { // only the first declaration counts now + setLimMemberData(_node, limAttrib); + setLimAttributeData(_node, limAttrib); + setComponentData(limAttrib.getId()); + } + } + + if(_node.getRefersTo()) { + + if(_node.getParent() && !python::asg::Common::getIsAttributeRef(*_node.getParent())) { + + python::asg::module::Object& objNode = dynamic_cast(*_node.getRefersTo()); + NodeId instId = createType(objNode.getId()); + lim::asg::type::TypeFormerType *tft; + if(limFact.getExist(instId)) { + lim::asg::ListIterator tfIt = dynamic_cast(limFact.getRef(instId)).getTypeFormerListIteratorBegin(); + if(dynamic_cast(limFact.getRef(instId)).getTypeFormerSize() == 1) { + tft = &const_cast(dynamic_cast(*tfIt)); + if(lim::asg::Common::getIsClass(*tft->getRefersTo())) { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->instantiates.insert(instId); + } + } + } + } + + } else if(_node.getParent() && python::asg::Common::getIsAttributeRef(*_node.getParent()) && python::asg::Common::getIsObject(*_node.getRefersTo())) { + + python::asg::module::Object& objNode = dynamic_cast(*_node.getRefersTo()); + if(objNode.getRefersToSize() == 1) { + python::asg::ListIterator refIt = objNode.getRefersToListIteratorBegin(); + const python::asg::base::Positioned& baseNode = *refIt; + NodeId baseParId = getPythonParent(baseNode); + if(python::asg::Common::getIsIdentifier(baseNode) && pyFact.getExist(baseParId) && + python::asg::Common::getIsClassDef(pyFact.getRef(baseParId)) && limFact.getExist(getLimNodeId(baseNode.getId()))) + { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->accessesAttribute.insert(baseNode.getId()); + } + } + } + + } + + } + + } + + + void Python2LimVisitor::visit(const columbus::python::asg::expression::IfExpression& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + incNob(_node); + } + + void Python2LimVisitor::visit(const columbus::python::asg::expression::Call& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + statement::CompoundStatement* ref = _node.getRefersTo(); + if (ref && python::asg::Common::getIsFunctionDef(*ref)) { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->calls.insert(ref->getId()); + } + } + } + + + void Python2LimVisitor::visit(const columbus::python::asg::expression::BinaryLogical& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + if (_node.getKind() == python::asg::blkAnd || _node.getKind() == python::asg::blkOr) { + incNob(_node); + } + } + + void Python2LimVisitor::visit(const columbus::python::asg::expression::Expression& _node, bool callVirtualBase ) { + VisitorAbstractNodes::visit(_node, callVirtualBase); + + python::asg::base::Base* parent = _node.getParent(); + if (parent) { + if (python::asg::Common::getIsSuite(*parent)) { + incNos(_node); + } + } + } + +/************* + * LIM GRAPH * + *************/ + + NodeId Python2LimVisitor::getLimNodeId(NodeId pythonId) { + NodeIdMapType::const_iterator nIt = pythonId2limId.find(pythonId); + if(nIt != pythonId2limId.end()) { + return nIt->second; + } else { + const python::asg::base::Base& bn = pyFact.getRef(pythonId); + if (python::asg::Common::getIsIdentifier(bn)) { // only for attributes + string attrUname = dynamic_cast(bn).getPosition().getPath() + "#" + python::asg::Common::getUniqueName(bn); + Key nodeKey = limFact.getStringTable().set(attrUname); + Key2IdMapType::const_iterator kIt = pythonKey2LimId.find(nodeKey); + if(kIt != pythonKey2LimId.end()) { + return kIt->second; + } + } + return 0; + } + } + + + lim::asg::base::Base& Python2LimVisitor::createIncompleteLimNode(const python::asg::base::Base& _node) { + return createLimNode(_node, false); + } + + + lim::asg::base::Base& Python2LimVisitor::createCompleteLimNode(const python::asg::base::Base& _node) { + return createLimNode(_node, true); + } + + + lim::asg::base::Base& Python2LimVisitor::createLimNode(const python::asg::base::Base& _node, bool isComplete) { + NodeId pyId = _node.getId(); + NodeId limId = getLimNodeId(pyId); + + if(limId != 0) { + + if(isComplete) + incompleteNodes.erase(limId); + return limFact.getRef(limId); + + } else { + + lim::asg::base::Named* newLimNode = NULL; + + if(python::asg::Common::getIsClassDef(_node)) { + + newLimNode = dynamic_cast(limFact.createNode(lim::asg::ndkClass)); + newLimNode->setName(dynamic_cast(_node).getName()); + lim::asg::logical::Class* limNode = dynamic_cast(newLimNode); + string uniqueName = python::asg::Common::getUniqueName(_node); + limNode->setMangledName(uniqueName); + limNode->setDemangledName(uniqueName); + + } else if(python::asg::Common::getIsFunctionDef(_node)) { + + newLimNode = dynamic_cast(limFact.createNode(lim::asg::ndkMethod)); + newLimNode->setName(dynamic_cast(_node).getName()); + lim::asg::logical::Method* limNode = dynamic_cast(newLimNode); + string uniqueName = python::asg::Common::getUniqueName(_node); + limNode->setMangledName(uniqueName); + limNode->setDemangledName(uniqueName); + + } else if(python::asg::Common::getIsParameter(_node)) { + + newLimNode = dynamic_cast(limFact.createNode(lim::asg::ndkParameter)); + newLimNode->setName(dynamic_cast(_node).getName()); + string uniqueName = python::asg::Common::getUniqueName(_node); + + } else if(python::asg::Common::getIsModule(_node)) { + + newLimNode = dynamic_cast(limFact.createNode(lim::asg::ndkPackage)); + newLimNode->setName(dynamic_cast(_node).getName()); + lim::asg::logical::Package* limNode = dynamic_cast(newLimNode); + string uniqueName = python::asg::Common::getUniqueName(_node); + limNode->setMangledName(uniqueName); + limNode->setDemangledName(uniqueName); + + } else if(python::asg::Common::getIsIdentifier(_node)) { + + newLimNode = dynamic_cast(limFact.createNode(lim::asg::ndkAttribute)); + newLimNode->setName(dynamic_cast(_node).getName()); + lim::asg::logical::Attribute* limNode = dynamic_cast(newLimNode); + string uniqueName = python::asg::Common::getUniqueName(_node); + limNode->setMangledName(uniqueName); + limNode->setDemangledName(uniqueName); + string attrUname = dynamic_cast(_node).getPosition().getPath() + "#" + uniqueName; + pythonKey2LimId.insert(make_pair(limFact.getStringTable().set(attrUname),newLimNode->getId())); + + } else if(python::asg::Common::getIsPackage(_node)) { + + newLimNode = dynamic_cast(limFact.createNode(lim::asg::ndkPackage)); + newLimNode->setName(dynamic_cast(_node).getName()); + lim::asg::logical::Package* limNode = dynamic_cast(newLimNode); + string uniqueName = python::asg::Common::getUniqueName(_node); + limNode->setMangledName(uniqueName); + limNode->setDemangledName(uniqueName); + + } else { + + throw PythonException(COLUMBUS_LOCATION, CMSG_INVALID_NODEKIND); + + } + + pythonId2limId.insert(make_pair(_node.getId(), newLimNode->getId())); + origin.addCompIdCppIdLimIdToMap( actualCompNodeId, _node.getId(), newLimNode->getId() ); + + if(!isComplete) + incompleteNodes.insert((*newLimNode).getId()); + + if(pyFact.getFilterState(_node.getId()) == python::asg::Filter::Filtered) { + limFact.setFiltered((*newLimNode).getId()); + } + + return *newLimNode; + + } + } + + + void Python2LimVisitor::setLimMemberData(const columbus::python::asg::base::Base& _node, columbus::lim::asg::logical::Member& limMember) { + + limMember.setIsStatic(false); + + if ( ! lim::asg::Common::getIsPackage( limMember ) || dynamic_cast( limMember ).getPackageKind() == lim::asg::pkModule ) { + python::asg::Range pyRange = dynamic_cast(_node).getPosition(); + lim::asg::SourcePosition sourcePosition = lim::asg::SourcePosition(lim::asg::relDefines, pyRange.getLine(), pyRange.getCol(), pyRange.getEndLine(), pyRange.getEndCol()); + limMember.addIsContainedIn( &buildFileNode(pyRange), sourcePosition ); + } + + if (_node.getId() == pyFact.getRoot()->getId()) + return; + + NodeId pythonParentId = getPythonParent(_node); + + if (!pyFact.getExist(pythonParentId)) { + throw PythonException(COLUMBUS_LOCATION, CMSG_WRONG_ASG); + } + + lim::asg::logical::Scope& limParent = dynamic_cast(createIncompleteLimNode(pyFact.getRef(pythonParentId))); + SAFE_EDGE( limParent, Member, lim::asg::logical::Member, limMember.getId() ); + } + + void Python2LimVisitor::processDocstring(lim::asg::logical::Member& member, python::asg::base::Docstring* docstring){ + if (docstring){ + lim::asg::base::Comment& comment = limFact.createComment(docstring->getText()); + member.addComment(comment.getId()); + } + } + + void Python2LimVisitor::setLimClassData(const columbus::python::asg::statement::Statement& _node, columbus::lim::asg::logical::Class& limClass) { + + limClass.setClassKind(lim::asg::clkClass); + + } + + + void Python2LimVisitor::setLimMethodData(const columbus::python::asg::statement::Statement& _node, columbus::lim::asg::logical::Method& limMethod) { + + limMethod.setMethodKind(lim::asg::mekNormal); + + type::Type* retType = dynamic_cast(_node).getReturnType(); + if(retType) { + NodeId limType = createType(retType->getId()); + if(limFact.getExist(limType)) { + limMethod.addReturns(limType); + } + } + + } + + + void Python2LimVisitor::setFictiveMethodData(columbus::lim::asg::logical::Method& fictiveLimMethod) { + + fictiveLimMethod.setMethodKind(lim::asg::mekNormal); + fictiveLimMethod.setIsStatic(false); + fictiveLimMethod.setIsAbstract(false); + + // filter it out + limFact.setFiltered(fictiveLimMethod.getId()); + + } + + + void Python2LimVisitor::setLimAttributeData(const columbus::python::asg::expression::Identifier& _node, columbus::lim::asg::logical::Attribute& limAttribute) { + + if(_node.getRefersTo()) { + python::asg::module::Object& objNode = dynamic_cast(*_node.getRefersTo()); + NodeId limType = createType(objNode.getId()); + if(limFact.getExist(limType)) { + SAFE_EDGE( limAttribute, Type, lim::asg::type::Type, limType ); + } + } + + } + + + void Python2LimVisitor::setComponentData(columbus::NodeId limNodeId) const { + + if(limFact.getFilterState(limNodeId) == lim::asg::Filter::Filtered) { + return; + } + + lim::asg::logical::Member& member = dynamic_cast(limFact.getRef(limNodeId)); + SAFE_EDGE( member, BelongsTo, lim::asg::base::Component, actualCompNodeId ); + + } + + + void Python2LimVisitor::fillCollectedMethodData(lim::asg::logical::Method& limMethod, MethodInfo* methodInfo) { + + limMethod.setNumberOfStatements(methodInfo->NOS); + limMethod.setNumberOfBranches(methodInfo->NOB); + limMethod.setNestingLevel(methodInfo->NL); + limMethod.setNestingLevelElseIf(methodInfo->NLE); + + set::iterator it, itEnd; + + for (it = methodInfo->calls.begin(), itEnd = methodInfo->calls.end(); it != itEnd; ++it) { + lim::asg::base::Base& callNode = createIncompleteLimNode(pyFact.getRef(*it)); + lim::asg::logical::MethodCall& call = limFact.createMethodCall(callNode.getId()); + limMethod.addCalls(&call); + } + + for (it = methodInfo->accessesAttribute.begin(), itEnd = methodInfo->accessesAttribute.end(); it != itEnd; ++it) { + lim::asg::logical::Attribute& limAttrib = dynamic_cast(createIncompleteLimNode(pyFact.getRef(*it))); + lim::asg::logical::AttributeAccess& access = limFact.createAttributeAccess(limAttrib.getId()); + limMethod.addAccessesAttribute(&access); + } + + for (it = methodInfo->instantiates.begin(), itEnd = methodInfo->instantiates.end(); it != itEnd; ++it) { + limMethod.addInstantiates(*it); + } + + for (it = methodInfo->throws.begin(), itEnd = methodInfo->throws.end(); it != itEnd; ++it) { + limMethod.addThrows(*it); + } + + for (it = methodInfo->uses.begin(), itEnd = methodInfo->uses.end(); it != itEnd; ++it) { + limMethod.addUses(*it); + } + + } + + + lim::asg::logical::Method* Python2LimVisitor::createFictiveMethod(lim::asg::logical::Scope& limNode) { + + string fictShortName = ""; + if (lim::asg::Common::getIsPackage(limNode)) { + fictShortName = "fictivePackageMethod"; + } else { + fictShortName = "fictiveClassMethod"; + } + + string fictName = limNode.getMangledName() + "~" + fictShortName; + + lim::asg::logical::Method& fictiveLimMethod = dynamic_cast(*limFact.createNode(lim::asg::ndkMethod)); + fictiveLimMethod.setName(fictShortName); + fictiveLimMethod.setMangledName(fictName); + fictiveLimMethod.setDemangledName(fictName); + setFictiveMethodData(fictiveLimMethod); + limNode.addMember(fictiveLimMethod.getId()); + + ScopeInfo* scopeInfo = infoStack.back(); + scopeInfo->fictiveMethodInfo = new MethodInfo(); + scopeInfo->fictiveMethodInfo->limNode = &fictiveLimMethod; + + return &fictiveLimMethod; + + } + + + NodeId Python2LimVisitor::createType(columbus::NodeId pythonId) { + NodeId pyTypeId = 0; + unsigned int types = 0; + + if(python::asg::Common::getIsObject(pyFact.getRef(pythonId))) { + if(dynamic_cast(pyFact.getRef(pythonId)).getTypeIsEmpty()) { + return 0; + } + python::asg::ListIterator typeIt = dynamic_cast(pyFact.getRef(pythonId)).getTypeListIteratorBegin(); + python::asg::ListIterator typeItEnd = dynamic_cast(pyFact.getRef(pythonId)).getTypeListIteratorEnd(); + for(; typeIt != typeItEnd; ++typeIt){ + pyTypeId = typeIt->getId(); + } + if(dynamic_cast(pyFact.getRef(pythonId)).getTypeSize() == 1) { + types = 1; + } + } else if(python::asg::Common::getIsExpression(pyFact.getRef(pythonId))) { + pyTypeId = dynamic_cast(pyFact.getRef(pythonId)).getType()->getId(); + if(!pyFact.getExist(pyTypeId)) { + return 0; + } else { + types = 1; + } + } else if(python::asg::Common::getIsType(pyFact.getRef(pythonId))) { + pyTypeId = pythonId; + types = 1; + } + + NodeId limTypeId = 0; + NodeId typeId = 0; + bool isClass = false; + + if(PythonType2LimTypeMap.find(pyTypeId) != PythonType2LimTypeMap.end()) { + return PythonType2LimTypeMap[pyTypeId]; + } + + limFact.beginType(); + + if(types == 1) { + python::asg::type::Type& pyType = dynamic_cast(pyFact.getRef(pyTypeId)); + if(python::asg::Common::getIsReferenceType(pyType)) { + if(!dynamic_cast(pyType).getRefersTo()) { + return 0; + } + python::asg::base::Base& refNode = *dynamic_cast(pyType).getRefersTo(); + if(python::asg::Common::getIsClassDef(refNode)) { + isClass = true; + createIncompleteLimNode(refNode); + typeId = getLimNodeId(refNode.getId()); + } + } + if(!isClass) { + typeId = limFact.createSimpleType(lim::asg::stkUnknown).getId(); + } + } else { + typeId = limFact.createSimpleType(lim::asg::stkUnknown).getId(); + } + lim::asg::type::TypeFormerType& tft = limFact.createTypeFormerType(typeId); + limFact.addTypeFormer(tft.getId()); + + limTypeId = limFact.endType().getId(); + PythonType2LimTypeMap.insert(make_pair(pyTypeId, limTypeId)); + + return limTypeId; + } + + + NodeId Python2LimVisitor::getPythonParent(const columbus::python::asg::base::Base& _node) { + base::Base* parent = _node.getParent(); + + while(parent) { + if(python::asg::Common::getIsClassDef(*parent) || python::asg::Common::getIsModule(*parent) || + python::asg::Common::getIsPackage(*parent) || python::asg::Common::getIsFunctionDef(*parent)) + { + break; + } + parent = parent->getParent(); + } + + return parent ? parent->getId() : 0; + } + + + void Python2LimVisitor::incNos(const python::asg::base::Positioned& _node) { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->NOS++; + } + } + + + void Python2LimVisitor::incNob(const python::asg::base::Base& _node) { + if (!infoStack.empty()) { + infoStack.back()->getMethodInfo()->NOB++; + } + } + + + bool Python2LimVisitor::eligibleForNLE(const python::asg::statement::If& _node) { + if (_node.getParent() && python::asg::Common::getIsSuite(*_node.getParent())) { + python::asg::statement::Suite& suiteNode = dynamic_cast(*_node.getParent()); + if (suiteNode.getStatementSize() == 1) { + if (suiteNode.getParent() && python::asg::Common::getIsIf(*suiteNode.getParent())) { + python::asg::statement::If& ifNode = dynamic_cast(*suiteNode.getParent()); + if (ifNode.getElseBody() == &suiteNode) { + return false; + } + } + } + } + + return true; + } + + void Python2LimVisitor::incNL( bool NLE ) { + if ( infoStack.empty() ) return; + + MethodInfo* methodInfo = infoStack.back()->getMethodInfo(); + + // NL + methodInfo->currentNL++; + if ( methodInfo->currentNL > methodInfo->NL ) { + methodInfo->NL = methodInfo->currentNL; + } + + // NLE + if ( NLE ) { + methodInfo->currentNLE++; + if ( methodInfo->currentNLE > methodInfo->NLE ) { + methodInfo->NLE = methodInfo->currentNLE; + } + } + } + + void Python2LimVisitor::decNL( bool NLE) { + if ( infoStack.empty() ) return; + + MethodInfo* methodInfo = infoStack.back()->getMethodInfo(); + + methodInfo->currentNL--; + if ( NLE ) { + methodInfo->currentNLE--; + } + } + + + void Python2LimVisitor::finalize( const lim::asg::Factory& factory ) { + + using namespace lim::asg; + + Factory::const_iterator i = factory.begin(), end = factory.end(); + for ( ; i != end; ++i ) { + + base::Base& node = const_cast( **i ); + + setLineMetrics( node ); + + if ( Common::getIsMember( node ) ) { + dynamic_cast( node ).setLanguage( lnkPython ); + } + } + } + + void Python2LimVisitor::setLineMetrics( lim::asg::base::Base& node ) { + + using namespace lim::asg; + + // FILE, already handled... + + // COMPONENT + if ( Common::getIsComponent( node ) ) { + base::Component& component = dynamic_cast( node ); + const ReverseEdges& revEdges = component.getFactory().getReverseEdges(); + + // Files in the Component (through reverse belongsTo and forward isContainedIn) + std::set files; + ListIterator m = revEdges.constIteratorBegin( component.getId(), edkMember_BelongsTo ), + mEnd = revEdges.constIteratorEnd( component.getId(), edkMember_BelongsTo ); + for ( ; m != mEnd; ++m ) { + const logical::Member& member = dynamic_cast( *m ); + ListIteratorAssocSourcePosition f = member.getIsContainedInListIteratorAssocBegin(), + fEnd = member.getIsContainedInListIteratorAssocEnd(); + for ( ; f != fEnd; ++f ) { + files.insert( &*f ); + } + } + + size_t tloc = 0, tlloc = 0; + std::set::const_iterator f = files.begin(), + fEnd = files.end(); + for ( ; f != fEnd; ++f ) { + tloc += (*f)->getLOC(); + tlloc += (*f)->getLLOC(); + } + + component.setTLOC( tloc ); + component.setTLLOC( tlloc ); + + // Increase TLOC and TLLOC of parent component (only root component has child components now) + ListIterator c = revEdges.constIteratorBegin( component.getId(), edkComponent_Contains ), + cEnd = revEdges.constIteratorEnd( component.getId(), edkComponent_Contains ); + for ( ; c != cEnd; ++c ) { + base::Component& component = const_cast( dynamic_cast( *c ) ); + component.setTLOC(component.getTLOC() + tloc); + component.setTLLOC(component.getTLLOC() + tlloc); + } + } + + // PACKAGE + else if ( Common::getIsPackage( node ) ) { + logical::Package& package = dynamic_cast( node ); + if ( package.getPackageKind() == pkPackage ) { + setPackageLines( package ); + } + } + + // CLASS/METHOD + else if ( Common::getIsClass( node ) || Common::getIsMethod( node ) ) { + logical::Scope& scope = dynamic_cast( node ); + bool isClass = Common::getIsClass( node ); + + // starting (L)LOC is the T(L)LOC which was set earlier + // now it gets reduced + int loc = scope.getTLOC(); + int lloc = scope.getTLLOC(); + + ListIterator memberIt = scope.getMemberListIteratorBegin(), + memberEnd = scope.getMemberListIteratorEnd(); + for ( ; memberIt != memberEnd; ++memberIt ) { + if ( Common::getIsClass( *memberIt ) || ( ! isClass && Common::getIsMethod( *memberIt ) ) ) { + const logical::Scope& childScope = dynamic_cast( *memberIt ); + loc -= childScope.getTLOC(); + lloc -= childScope.getTLLOC(); + } + } + + // truncate negative numbers + // (because of missing line sets... FIXME) + loc = loc < 0 ? 0 : loc; + lloc = lloc < 0 ? 0 : lloc; + + scope.setLOC( loc ); + scope.setLLOC( lloc ); + } + + } + + void Python2LimVisitor::setPackageLines( lim::asg::logical::Package& package ) { + using namespace lim::asg; + int tloc = 0, tlloc = 0; + ListIterator memberIt = package.getMemberListIteratorBegin(), + memberEnd = package.getMemberListIteratorEnd(); + for ( ; memberIt != memberEnd; ++memberIt ) { + + if ( ! Common::getIsPackage( *memberIt ) ) { + throw PythonException(COLUMBUS_LOCATION, CMSG_WRONG_ASG); + } + + logical::Package& subPackage = const_cast( dynamic_cast( *memberIt ) ); + + if ( subPackage.getPackageKind() == pkPackage ) { + setPackageLines( subPackage ); + } + + tloc += subPackage.getTLOC(); + tlloc += subPackage.getTLLOC(); + } + + package.setLOC( 0 ); + package.setLLOC( 0 ); + package.setTLOC( tloc ); + package.setTLLOC( tlloc ); + } + + lim::asg::physical::File& Python2LimVisitor::buildFileNode(const python::asg::Range& range) { + KeyNodeIdMapType::const_iterator fileNodeIt = pathFileNodeIdMap.find(range.getPathKey()); + if (fileNodeIt != pathFileNodeIdMap.end()) { + return dynamic_cast(limFact.getRef(fileNodeIt->second)); + } else { + lim::asg::physical::File& file = limFact.createFile(range.getPath()); + pathFileNodeIdMap[range.getPathKey()] = file.getId(); + return file; + } + + } + + void Python2LimVisitor::finishVisit() { + for (NodeId2UnsignedIntervalSetMap::const_iterator fileCommentMapIt = fileNodeIdCommentLinesMap.begin(); fileCommentMapIt != fileNodeIdCommentLinesMap.end(); ++fileCommentMapIt) { + dynamic_cast(limFact.getRef(fileCommentMapIt->first)).setCLOC(boost::icl::length(fileCommentMapIt->second)); + } + } + + +}} diff --git a/cl/PMD2Graph/CheckerStrategy.cpp b/cl/PMD2Graph/CheckerStrategy.cpp index 06ca53e..e72ee12 100644 --- a/cl/PMD2Graph/CheckerStrategy.cpp +++ b/cl/PMD2Graph/CheckerStrategy.cpp @@ -196,10 +196,6 @@ bool CheckerStrategy::getIsNeeded (const std::string& id, const rul::RulHandler& return xRulHandler.getIsEnabled(id); } -void CheckerStrategy::addLicenseTypeToTheGraphHeader(const string& toolName) { - graph.setHeaderInfo(toolName + graphsupport::graphconstants::HEADER_MODE_KEY_SUFFIX, graphsupport::graphconstants::HEADER_MODE_VALUE_FULL ); -} - void CheckerStrategy::saveGraph(const std::string& filename, bool exportRul) { if(exportRul) graphsupport::buildRulToGraph(graph, *(mt->xRulhandler)); diff --git a/cl/PMD2Graph/CheckerStrategy.h b/cl/PMD2Graph/CheckerStrategy.h index 2801d11..0eea202 100644 --- a/cl/PMD2Graph/CheckerStrategy.h +++ b/cl/PMD2Graph/CheckerStrategy.h @@ -69,7 +69,7 @@ class CheckerStrategy{ this->graphIndexer.turnOn(this->graph); } virtual ~CheckerStrategy(){} - virtual void makeRul(File_Names&,std::string& rul, std::string& rulConfig, std::string& rul_option_filename, std::string& faulthunterrul) = 0; + virtual void makeRul(File_Names&,std::string& rul, std::string& rulConfig, std::string& rul_option_filename) = 0; virtual void makeConfig(File_Names&, std::string&, std::string& rulConfig, std::string& configFile) = 0; virtual void makeCsv(std::string& lim, std::string& rul, std::string& rulConfig, File_Names& file_names, std::string& metrics, std::string& groupedmetrics, std::string& monitor, std::string& checkerbasedir); virtual void makeCsv(std::string& lim, std::string& rul, std::string& rulConfig , File_Names& file_names, std::string& metrics, std::string& groupedmetrics, std::string& monitor, std::string& checkerbasedir, const std::map& levelMap); @@ -78,8 +78,6 @@ class CheckerStrategy{ void setGraph(columbus::graph::Graph& ingraph) { this->graphIndexer.turnOff(this->graph); graph = ingraph; this->graphIndexer.turnOn(this->graph);} - void addLicenseTypeToTheGraphHeader(const std::string& toolName); - protected: XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* doc; MetricTree* mt; diff --git a/cl/PMD2Graph/MetricTree.h b/cl/PMD2Graph/MetricTree.h index d6e1b6a..d781d15 100644 --- a/cl/PMD2Graph/MetricTree.h +++ b/cl/PMD2Graph/MetricTree.h @@ -32,11 +32,6 @@ #include #include -#define FAULTHUNTER "FaultHunter" -#define CONFIG_DEFAULT "Default" -#define CONFIG_FAULTHUNTER FAULTHUNTER - - #include using namespace std; diff --git a/cl/PMD2Graph/PMD/PMD.rul b/cl/PMD2Graph/PMD/PMD.rul index 06124ee..3b2acd2 100644 --- a/cl/PMD2Graph/PMD/PMD.rul +++ b/cl/PMD2Graph/PMD/PMD.rul @@ -6,9 +6,7 @@ PMD - - - + @@ -28,15 +26,6 @@ - - true - - true - - - - - @@ -55,15 +44,6 @@ - - true - - true - - - - - @@ -82,15 +62,6 @@ - - true - - true - - - - - @@ -109,15 +80,6 @@ - - true - - true - - - - - @@ -136,15 +98,6 @@ - - true - - true - - - - - @@ -163,15 +116,6 @@ - - true - - true - - - - - @@ -190,15 +134,6 @@ - - true - - true - - - - - @@ -217,15 +152,6 @@ - - true - - true - - - - - @@ -244,15 +170,6 @@ - - true - - true - - - - - @@ -271,15 +188,6 @@ - - true - - true - - - - - @@ -298,15 +206,6 @@ - - true - - true - - - - - @@ -325,15 +224,6 @@ - - true - - true - - - - - @@ -352,15 +242,6 @@ - - true - - true - - - - - @@ -379,15 +260,6 @@ - - true - - true - - - - - @@ -406,15 +278,6 @@ - - true - - true - - - - - @@ -433,15 +296,6 @@ - - true - - true - - - - - @@ -460,15 +314,6 @@ - - true - - true - - - - - @@ -487,15 +332,6 @@ - - true - - true - - - - - @@ -514,15 +350,6 @@ - - true - - true - - - - - @@ -541,15 +368,6 @@ - - true - - true - - - - - @@ -568,15 +386,6 @@ - - true - - true - - - - - @@ -595,15 +404,6 @@ - - true - - true - - - - - @@ -622,15 +422,6 @@ - - true - - true - - - - - @@ -649,15 +440,6 @@ - - true - - true - - - - - @@ -676,15 +458,6 @@ - - true - - true - - - - - @@ -704,15 +477,6 @@ - - false - - true - - - - - @@ -731,15 +495,6 @@ - - true - - true - - - - - @@ -758,15 +513,6 @@ - - true - - true - - - - - @@ -785,15 +531,6 @@ - - true - - true - - - - - @@ -812,15 +549,6 @@ - - false - - true - - - - - @@ -839,15 +567,6 @@ - - true - - true - - - - - @@ -866,15 +585,6 @@ - - true - - true - - - - - @@ -893,15 +603,6 @@ - - false - - true - - - - - @@ -920,15 +621,6 @@ - - false - - true - - - - - @@ -947,15 +639,6 @@ - - true - - true - - - - - @@ -974,15 +657,6 @@ - - false - - true - - - - - @@ -1001,18 +675,9 @@ - - true - - true - - - - - - - - + + + true false Basic Rules @@ -1028,15 +693,6 @@ - - true - - true - - - - - @@ -1055,15 +711,6 @@ - - false - - true - - - - - @@ -1082,15 +729,6 @@ - - true - - true - - - - - @@ -1110,15 +748,6 @@ - - false - - true - - - - - @@ -1137,15 +766,6 @@ - - false - - true - - - - - @@ -1164,15 +784,6 @@ - - false - - true - - - - - @@ -1191,15 +802,6 @@ - - true - - true - - - - - @@ -1218,15 +820,6 @@ - - true - - true - - - - - @@ -1245,15 +838,6 @@ - - false - - true - - - - - @@ -1272,15 +856,6 @@ - - false - - true - - - - - @@ -1299,15 +874,6 @@ - - false - - true - - - - - @@ -1326,15 +892,6 @@ - - false - - true - - - - - @@ -1353,15 +910,6 @@ - - true - - true - - - - - @@ -1380,15 +928,6 @@ - - false - - true - - - - - @@ -1407,15 +946,6 @@ - - false - - true - - - - - @@ -1434,15 +964,6 @@ - - true - - true - - - - - @@ -1461,15 +982,6 @@ - - false - - true - - - - - @@ -1488,15 +1000,6 @@ - - true - - true - - - - - @@ -1515,15 +1018,6 @@ - - true - - true - - - - - @@ -1542,15 +1036,6 @@ - - true - - true - - - - - @@ -1569,15 +1054,6 @@ - - false - - true - - - - - @@ -1596,15 +1072,6 @@ - - false - - true - - - - - @@ -1623,15 +1090,6 @@ - - true - - true - - - - - @@ -1650,15 +1108,6 @@ - - true - - true - - - - - @@ -1677,15 +1126,6 @@ - - true - - true - - - - - @@ -1704,15 +1144,6 @@ - - true - - true - - - - - @@ -1731,15 +1162,6 @@ - - true - - true - - - - - @@ -1758,15 +1180,6 @@ - - true - - true - - - - - @@ -1785,15 +1198,6 @@ - - false - - true - - - - - @@ -1812,15 +1216,6 @@ - - false - - true - - - - - @@ -1839,15 +1234,6 @@ - - true - - true - - - - - @@ -1866,15 +1252,6 @@ - - true - - true - - - - - @@ -1893,15 +1270,6 @@ - - true - - true - - - - - @@ -1920,15 +1288,6 @@ - - false - - true - - - - - @@ -1947,15 +1306,6 @@ - - false - - true - - - - - @@ -1974,15 +1324,6 @@ - - true - - true - - - - - @@ -2001,15 +1342,6 @@ - - true - - true - - - - - @@ -2028,15 +1360,6 @@ - - false - - true - - - - - @@ -2055,15 +1378,6 @@ - - false - - true - - - - - @@ -2082,15 +1396,6 @@ - - false - - true - - - - - @@ -2109,15 +1414,6 @@ - - false - - true - - - - - @@ -2136,15 +1432,6 @@ - - true - - true - - - - - @@ -2163,15 +1450,6 @@ - - false - - true - - - - - @@ -2191,15 +1469,6 @@ - - false - - true - - - - - @@ -2218,15 +1487,6 @@ - - true - - true - - - - - @@ -2245,15 +1505,6 @@ - - false - - true - - - - - @@ -2272,15 +1523,6 @@ - - false - - true - - - - - @@ -2299,15 +1541,6 @@ - - true - - true - - - - - @@ -2326,15 +1559,6 @@ - - true - - true - - - - - @@ -2353,15 +1577,6 @@ - - true - - true - - - - - @@ -2380,15 +1595,6 @@ - - true - - true - - - - - @@ -2407,15 +1613,6 @@ - - false - - true - - - - - @@ -2434,15 +1631,6 @@ - - true - - true - - - - - @@ -2461,15 +1649,6 @@ - - false - - true - - - - - @@ -2488,15 +1667,6 @@ - - false - - true - - - - - @@ -2515,15 +1685,6 @@ - - true - - true - - - - - @@ -2542,15 +1703,6 @@ - - false - - true - - - - - @@ -2569,15 +1721,6 @@ - - false - - true - - - - - @@ -2596,15 +1739,6 @@ - - false - - true - - - - - @@ -2623,15 +1757,6 @@ - - false - - true - - - - - @@ -2650,15 +1775,6 @@ - - true - - true - - - - - @@ -2677,15 +1793,6 @@ - - false - - true - - - - - @@ -2704,15 +1811,6 @@ - - true - - true - - - - - @@ -2731,15 +1829,6 @@ - - true - - true - - - - - @@ -2758,15 +1847,6 @@ - - true - - true - - - - - @@ -2785,15 +1865,6 @@ - - false - - true - - - - - @@ -2812,15 +1883,6 @@ - - false - - true - - - - - @@ -2839,15 +1901,6 @@ - - false - - true - - - - - @@ -2866,15 +1919,6 @@ - - true - - true - - - - - @@ -2893,15 +1937,6 @@ - - true - - true - - - - - @@ -2920,15 +1955,6 @@ - - true - - true - - - - - @@ -2947,21 +1973,12 @@ - + + + true - - true - - - - - - - - - true - false - Controversial Rules + false + Controversial Rules true Dont Import Sun @@ -2974,15 +1991,6 @@ - - true - - true - - - - - @@ -3001,15 +2009,6 @@ - - false - - true - - - - - @@ -3028,15 +2027,6 @@ - - true - - true - - - - - @@ -3055,15 +2045,6 @@ - - true - - true - - - - - @@ -3082,15 +2063,6 @@ - - true - - true - - - - - @@ -3109,15 +2081,6 @@ - - false - - true - - - - - @@ -3136,15 +2099,6 @@ - - true - - true - - - - - @@ -3163,15 +2117,6 @@ - - false - - true - - - - - @@ -3190,15 +2135,6 @@ - - true - - true - - - - - @@ -3217,15 +2153,6 @@ - - true - - true - - - - - @@ -3244,15 +2171,6 @@ - - true - - true - - - - - @@ -3272,15 +2190,6 @@ - - false - - true - - - - - @@ -3299,15 +2208,6 @@ - - false - - true - - - - - @@ -3326,15 +2226,6 @@ - - true - - true - - - - - @@ -3354,15 +2245,6 @@ - - false - - true - - - - - @@ -3381,15 +2263,6 @@ - - false - - true - - - - - @@ -3409,15 +2282,6 @@ - - false - - true - - - - - @@ -3436,15 +2300,6 @@ - - true - - true - - - - - @@ -3463,15 +2318,6 @@ - - false - - true - - - - - @@ -3490,15 +2336,6 @@ - - true - - true - - - - - @@ -3517,15 +2354,6 @@ - - true - - true - - - - - @@ -3544,15 +2372,6 @@ - - false - - true - - - - - @@ -3571,15 +2390,6 @@ - - false - - true - - - - - @@ -3599,15 +2409,6 @@ - - false - - true - - - - - @@ -3627,15 +2428,6 @@ - - true - - true - - - - - @@ -3655,15 +2447,6 @@ - - true - - true - - - - - @@ -3683,15 +2466,6 @@ - - false - - true - - - - - @@ -3711,15 +2485,6 @@ - - false - - true - - - - - @@ -3739,15 +2504,6 @@ - - false - - true - - - - - @@ -3767,15 +2523,6 @@ - - false - - true - - - - - @@ -3795,15 +2542,6 @@ - - true - - true - - - - - @@ -3822,15 +2560,6 @@ - - true - - true - - - - - @@ -3849,15 +2578,6 @@ - - true - - true - - - - - @@ -3876,15 +2596,6 @@ - - true - - true - - - - - @@ -3903,15 +2614,6 @@ - - false - - true - - - - - @@ -3930,15 +2632,6 @@ - - true - - true - - - - - @@ -3957,15 +2650,6 @@ - - true - - true - - - - - @@ -3984,15 +2668,6 @@ - - true - - true - - - - - @@ -4011,15 +2686,6 @@ - - true - - true - - - - - @@ -4038,15 +2704,6 @@ - - false - - true - - - - - @@ -4065,15 +2722,6 @@ - - true - - true - - - - - @@ -4092,15 +2740,6 @@ - - true - - true - - - - - @@ -4119,15 +2758,6 @@ - - true - - true - - - - - @@ -4146,15 +2776,6 @@ - - true - - true - - - - - @@ -4173,15 +2794,6 @@ - - false - - true - - - - - @@ -4200,15 +2812,6 @@ - - false - - true - - - - - @@ -4227,15 +2830,6 @@ - - true - - true - - - - - @@ -4254,15 +2848,6 @@ - - true - - true - - - - - @@ -4282,15 +2867,6 @@ - - false - - true - - - - - @@ -4309,15 +2885,6 @@ - - true - - true - - - - - @@ -4336,15 +2903,6 @@ - - true - - true - - - - - @@ -4363,15 +2921,6 @@ - - false - - true - - - - - @@ -4390,15 +2939,6 @@ - - true - - true - - - - - @@ -4417,15 +2957,6 @@ - - true - - true - - - - - @@ -4444,15 +2975,6 @@ - - true - - true - - - - - @@ -4472,15 +2994,6 @@ - - false - - true - - - - - @@ -4500,15 +3013,6 @@ - - false - - true - - - - - @@ -4528,15 +3032,6 @@ - - false - - true - - - - - @@ -4556,15 +3051,6 @@ - - false - - true - - - - - @@ -4583,15 +3069,6 @@ - - true - - true - - - - - @@ -4610,15 +3087,6 @@ - - true - - true - - - - - @@ -4637,15 +3105,6 @@ - - true - - true - - - - - @@ -4664,15 +3123,6 @@ - - true - - true - - - - - @@ -4691,15 +3141,6 @@ - - true - - true - - - - - @@ -4719,15 +3160,6 @@ - - false - - true - - - - - @@ -4746,15 +3178,6 @@ - - false - - true - - - - - @@ -4773,15 +3196,6 @@ - - true - - true - - - - - @@ -4800,15 +3214,6 @@ - - true - - true - - - - - @@ -4827,15 +3232,6 @@ - - true - - true - - - - - @@ -4854,15 +3250,6 @@ - - true - - true - - - - - @@ -4881,15 +3268,6 @@ - - false - - true - - - - - @@ -4908,18 +3286,9 @@ - - false - - true - - - - - - - - + + + false false Naming Rules @@ -4935,15 +3304,6 @@ - - false - - true - - - - - @@ -4962,15 +3322,6 @@ - - false - - true - - - - - @@ -4989,15 +3340,6 @@ - - false - - true - - - - - @@ -5017,15 +3359,6 @@ - - false - - true - - - - - @@ -5044,15 +3377,6 @@ - - false - - true - - - - - @@ -5071,15 +3395,6 @@ - - false - - true - - - - - @@ -5098,15 +3413,6 @@ - - false - - true - - - - - @@ -5125,15 +3431,6 @@ - - true - - true - - - - - @@ -5152,15 +3449,6 @@ - - true - - true - - - - - @@ -5179,15 +3467,6 @@ - - true - - true - - - - - @@ -5206,15 +3485,6 @@ - - true - - true - - - - - @@ -5233,15 +3503,6 @@ - - true - - true - - - - - @@ -5260,15 +3521,6 @@ - - true - - true - - - - - @@ -5287,15 +3539,6 @@ - - false - - true - - - - - @@ -5314,15 +3557,6 @@ - - false - - true - - - - - @@ -5341,15 +3575,6 @@ - - false - - true - - - - - @@ -5368,15 +3593,6 @@ - - false - - true - - - - - @@ -5395,15 +3611,6 @@ - - false - - true - - - - - @@ -5422,15 +3629,6 @@ - - true - - true - - - - - @@ -5449,15 +3647,6 @@ - - false - - true - - - - - @@ -5476,15 +3665,6 @@ - - true - - true - - - - - @@ -5503,15 +3683,6 @@ - - false - - true - - - - - @@ -5530,15 +3701,6 @@ - - true - - true - - - - - @@ -5557,15 +3719,6 @@ - - false - - true - - - - - @@ -5584,15 +3737,6 @@ - - true - - true - - - - - @@ -5611,15 +3755,6 @@ - - true - - true - - - - - @@ -5638,15 +3773,6 @@ - - true - - true - - - - - @@ -5665,15 +3791,6 @@ - - false - - true - - - - - @@ -5692,15 +3809,6 @@ - - true - - true - - - - - @@ -5719,15 +3827,6 @@ - - true - - true - - - - - @@ -5746,15 +3845,6 @@ - - true - - true - - - - - @@ -5773,15 +3863,6 @@ - - false - - true - - - - - @@ -5800,15 +3881,6 @@ - - true - - true - - - - - @@ -5827,15 +3899,6 @@ - - false - - true - - - - - @@ -5854,15 +3917,6 @@ - - false - - true - - - - - @@ -5881,15 +3935,6 @@ - - false - - true - - - - - @@ -5908,15 +3953,6 @@ - - true - - true - - - - - @@ -5936,15 +3972,6 @@ - - false - - true - - - - - @@ -5963,15 +3990,6 @@ - - true - - true - - - - - @@ -5990,15 +4008,6 @@ - - true - - true - - - - - @@ -6018,15 +4027,6 @@ - - false - - true - - - - - @@ -6045,15 +4045,6 @@ - - true - - true - - - - - @@ -6072,15 +4063,6 @@ - - true - - true - - - - - @@ -6100,15 +4082,6 @@ - - false - - true - - - - - @@ -6127,15 +4100,6 @@ - - true - - true - - - - - @@ -6154,15 +4118,6 @@ - - true - - true - - - - - @@ -6181,15 +4136,6 @@ - - true - - true - - - - - @@ -6208,15 +4154,6 @@ - - true - - true - - - - - @@ -6235,15 +4172,6 @@ - - false - - true - - - - - @@ -6262,15 +4190,6 @@ - - false - - true - - - - - @@ -6289,15 +4208,6 @@ - - true - - true - - - - - @@ -6316,15 +4226,6 @@ - - true - - true - - - - - @@ -6343,15 +4244,6 @@ - - false - - true - - - - - @@ -6370,15 +4262,6 @@ - - false - - true - - - - - @@ -6397,15 +4280,6 @@ - - false - - true - - - - - @@ -6424,15 +4298,6 @@ - - true - - true - - - - - @@ -6451,15 +4316,6 @@ - - true - - true - - - - - @@ -6478,15 +4334,6 @@ - - true - - true - - - - - @@ -6505,15 +4352,6 @@ - - false - - true - - - - - @@ -6533,15 +4371,6 @@ - - false - - true - - - - - @@ -6560,15 +4389,6 @@ - - false - - true - - - - - @@ -6587,15 +4407,6 @@ - - true - - true - - - - - @@ -6614,15 +4425,6 @@ - - false - - true - - - - - @@ -6641,15 +4443,6 @@ - - false - - true - - - - - @@ -6668,15 +4461,6 @@ - - false - - true - - - - - @@ -6695,15 +4479,6 @@ - - true - - true - - - - - @@ -6722,15 +4497,6 @@ - - false - - true - - - - - @@ -6749,15 +4515,6 @@ - - true - - true - - - - - @@ -6776,15 +4533,6 @@ - - true - - true - - - - - @@ -6803,15 +4551,6 @@ - - true - - true - - - - - @@ -6830,15 +4569,6 @@ - - true - - true - - - - - @@ -6857,15 +4587,6 @@ - - false - - true - - - - - @@ -6884,15 +4605,6 @@ - - false - - true - - - - - @@ -6911,15 +4623,6 @@ - - true - - true - - - - - @@ -6938,15 +4641,6 @@ - - true - - true - - - - - @@ -6965,15 +4659,6 @@ - - true - - true - - - - - @@ -6992,15 +4677,6 @@ - - false - - true - - - - - @@ -7019,15 +4695,6 @@ - - true - - true - - - - - @@ -7046,15 +4713,6 @@ - - true - - true - - - - - @@ -7073,15 +4731,6 @@ - - true - - true - - - - - @@ -7100,15 +4749,6 @@ - - true - - true - - - - - @@ -7127,15 +4767,6 @@ - - true - - true - - - - - @@ -7154,15 +4785,6 @@ - - true - - true - - - - - @@ -7181,15 +4803,6 @@ - - true - - true - - - - - @@ -7208,15 +4821,6 @@ - - false - - true - - - - - @@ -7235,15 +4839,6 @@ - - true - - true - - - - - @@ -7263,15 +4858,6 @@ - - true - - true - - - - - @@ -7290,15 +4876,6 @@ - - true - - true - - - - - @@ -7317,15 +4894,6 @@ - - false - - true - - - - - @@ -7336,21 +4904,12 @@ true Use Equals To Compare Strings Use equals() to compare strings instead of ''=='' or ''!='' - <p>Using '==' or '!=' to compare strings only works if intern version is used on both sides. Use the equals() method instead.</p> <p>Example(s):</p> <pre class="java"><code>public boolean test(String s) { if (s == &quot;one&quot;) return true; // unreliable if (&quot;two&quot;.equals(s)) return true; // better return false; }</code></pre> - - - - Critical - - - - - false - - true + <p>Using '==' or '!=' to compare strings only works if intern version is used on both sides. Use the equals() method instead.</p> <p>Example(s):</p> <pre class="java"><code>public boolean test(String s) { if (s == &quot;one&quot;) return true; // unreliable if (&quot;two&quot;.equals(s)) return true; // better return false; }</code></pre> - + + Critical + @@ -7372,15 +4931,6 @@ - - false - - true - - - - - @@ -7399,15 +4949,6 @@ - - false - - true - - - - - @@ -7426,15 +4967,6 @@ - - true - - true - - - - - @@ -7453,15 +4985,6 @@ - - false - - true - - - - - @@ -7480,15 +5003,6 @@ - - false - - true - - - - - @@ -7507,15 +5021,6 @@ - - true - - true - - - - - @@ -7534,15 +5039,6 @@ - - false - - true - - - - - @@ -7561,15 +5057,6 @@ - - false - - true - - - - - @@ -7588,15 +5075,6 @@ - - false - - true - - - - - @@ -7615,15 +5093,6 @@ - - false - - true - - - - - @@ -7642,15 +5111,6 @@ - - true - - true - - - - - @@ -7670,15 +5130,6 @@ - - true - - true - - - - - @@ -7697,15 +5148,6 @@ - - false - - true - - - - - @@ -7725,15 +5167,6 @@ - - false - - true - - - - - @@ -7753,15 +5186,6 @@ - - true - - true - - - - - @@ -7780,15 +5204,6 @@ - - false - - true - - - - - @@ -7807,15 +5222,6 @@ - - false - - true - - - - - @@ -7834,15 +5240,6 @@ - - false - - true - - - - - @@ -7861,15 +5258,6 @@ - - false - - true - - - - - @@ -7889,15 +5277,6 @@ - - false - - true - - - - - @@ -7916,15 +5295,6 @@ - - false - - true - - - - - @@ -7943,15 +5313,6 @@ - - false - - true - - - - - @@ -7970,15 +5331,6 @@ - - true - - true - - - - - @@ -7997,15 +5349,6 @@ - - false - - true - - - - - @@ -8024,15 +5367,6 @@ - - false - - true - - - - - @@ -8051,15 +5385,6 @@ - - true - - true - - - - - @@ -8078,15 +5403,6 @@ - - true - - true - - - - - @@ -8105,15 +5421,6 @@ - - false - - true - - - - - @@ -8133,15 +5440,6 @@ - - false - - true - - - - - @@ -8160,15 +5458,6 @@ - - true - - true - - - - - @@ -8187,15 +5476,6 @@ - - false - - true - - - - - @@ -8214,15 +5494,6 @@ - - true - - true - - - - - @@ -8241,15 +5512,6 @@ - - true - - true - - - - - @@ -8268,15 +5530,6 @@ - - true - - true - - - - - @@ -8295,15 +5548,6 @@ - - true - - true - - - - - @@ -8322,14 +5566,5 @@ - - true - - true - - - - - diff --git a/cl/PMD2Graph/PMD/PMDStrategy-rul.cpp b/cl/PMD2Graph/PMD/PMDStrategy-rul.cpp index 45efc70..9cd09ae 100644 --- a/cl/PMD2Graph/PMD/PMDStrategy-rul.cpp +++ b/cl/PMD2Graph/PMD/PMDStrategy-rul.cpp @@ -51,7 +51,7 @@ using namespace columbus; using namespace common; XERCES_CPP_NAMESPACE_USE -void PMDStrategy::makeRul(File_Names& file_names, std::string& rul, std::string& rulConfig, std::string& rul_option_filename, std::string& faulthunterrul){ +void PMDStrategy::makeRul(File_Names& file_names, std::string& rul, std::string& rulConfig, std::string& rul_option_filename){ rul::RulHandler rh(rulConfig, "eng"); setConstantData(rh); @@ -60,9 +60,6 @@ void PMDStrategy::makeRul(File_Names& file_names, std::string& rul, std::string& for(File_Names::iterator it = file_names.begin();it != file_names.end();++it) makeRulByFile(it->c_str(), rh, rul_refs); - // FaultHunter -> Default redef - rh.setConfigParent(CONFIG_FAULTHUNTER, CONFIG_DEFAULT); - set ref_id_list; // setting the groups of referenced ruls for(list >::iterator it = rul_refs.begin(); it != rul_refs.end(); ++it) { @@ -158,7 +155,6 @@ void PMDStrategy::makeRul(File_Names& file_names, std::string& rul, std::string& string id = *it; bool enabled = common::str2int(*(++it)) != 0; rh.setIsEnabled(id, enabled); - rh.setIsEnabled(id, CONFIG_FAULTHUNTER, enabled); rh.setSettingValue(id, "Priority", *(++it), true); cols.clear(); @@ -168,30 +164,6 @@ void PMDStrategy::makeRul(File_Names& file_names, std::string& rul, std::string& file.close(); } - // turn off FH rules in the FaultHunter config - if (!faulthunterrul.empty()) { - set pmdRules; - rh.getRuleIdList(pmdRules); - - rul::RulHandler fhRh(faulthunterrul, "Default", "eng"); - - set fhRules; - fhRh.getRuleIdList(fhRules); - - for (set::const_iterator it = fhRules.begin(), itEnd = fhRules.end(); it != itEnd; ++it) { - const string& fhRuleId = *it; - string groupType = fhRh.getGroupType(fhRuleId); - if (groupType == "false") { // only rules, no groups - string pmdRuleId = fh2PMDRuleId(fhRuleId); - if (pmdRules.find(pmdRuleId) != pmdRules.end()) { - if (fhRh.getIsEnabled(fhRuleId)) { - rh.setIsEnabled(pmdRuleId, CONFIG_FAULTHUNTER, false); // disable rule - } - } - } - } - } - //Writing out the rul file rh.saveRul(rul.c_str()); } @@ -224,14 +196,6 @@ void PMDStrategy::makeRulByFile(const char* xmlFile, columbus::rul::RulHandler& rh.setIsVisible(groupshortname, true); rh.setSettingValue(groupshortname, "Priority", "Minor", true); - // FaultHunter config - rh.createConfiguration(groupshortname, CONFIG_FAULTHUNTER); - rh.createLanguage(groupshortname, CONFIG_FAULTHUNTER, "eng"); - rh.setConfig(CONFIG_FAULTHUNTER); - rh.setHasWarningText(groupshortname, true); - rh.setIsEnabled(groupshortname, true); - rh.setConfig(CONFIG_DEFAULT); - string path = xmlFile; std::replace(path.begin(), path.end(), DIRDIVCHAR, '/'); path.erase(0, path.rfind("rulesets/")); @@ -280,14 +244,6 @@ void PMDStrategy::makeRulByFile(const char* xmlFile, columbus::rul::RulHandler& rh.setDescription(shortname, rulename); } - // FaultHunter config - rh.createConfiguration(shortname, CONFIG_FAULTHUNTER); - rh.createLanguage(shortname, CONFIG_FAULTHUNTER, "eng"); - rh.setConfig(CONFIG_FAULTHUNTER); - rh.setHasWarningText(shortname, true); - rh.setIsEnabled(shortname, true); - rh.setConfig(CONFIG_DEFAULT); - } else if(node->getAttributes()->getNamedItem(XMLString::transcode("ref"))) { string name = XMLString::transcode(node->getAttributes()->getNamedItem(XMLString::transcode("ref"))->getNodeValue()); rul_refs.push_back(pair(name, groupshortname)); @@ -352,13 +308,3 @@ string PMDStrategy::pmd2InternalGroupName(const string& pmdGroupName) { group += " Rules"; return group; } - -string PMDStrategy::fh2PMDRuleId(const std::string& fhRuleId) { - string pmdRuleId = fhRuleId; - if (pmdRuleId.find("FH_") == 0) { - pmdRuleId.erase(0, 3); - } - pmdRuleId = "PMD_" + pmdRuleId; - return pmdRuleId; -} - diff --git a/cl/PMD2Graph/PMD/PMDStrategy.h b/cl/PMD2Graph/PMD/PMDStrategy.h index d08789c..eca9d7b 100644 --- a/cl/PMD2Graph/PMD/PMDStrategy.h +++ b/cl/PMD2Graph/PMD/PMDStrategy.h @@ -39,7 +39,7 @@ class PMDStrategy : public CheckerStrategy{ public: PMDStrategy() : CheckerStrategy(), group_paths() { } virtual ~PMDStrategy(){} - virtual void makeRul(File_Names&, std::string& rul, std::string& rulConfig, std::string& rul_option_filename, std::string& faulthunterrul); + virtual void makeRul(File_Names&, std::string& rul, std::string& rulConfig, std::string& rul_option_filename); virtual void makeConfig(File_Names& file_names, std::string& rul, std::string& rulConfig, std::string& configFile); virtual void makeCsv(std::string& lim, std::string& rul, std::string& rulConfig, File_Names& file_names, std::string& metrics, std::string& groupedmetrics, std::string& monitor, std::string& checkerbasedir, std::string& pathfrom, std::string& pathto, FILE *f); protected: @@ -51,7 +51,6 @@ class PMDStrategy : public CheckerStrategy{ static const char OPTION_SEPARATOR = ';'; std::string pmd2InternalGroupName(const std::string& pmdGroup); - std::string fh2PMDRuleId(const std::string& fhRuleId); //makeRul section void makeRulByFile(const char*, columbus::rul::RulHandler&, list > &rul_refs); diff --git a/cl/PMD2Graph/main.cpp b/cl/PMD2Graph/main.cpp index eb8b134..50e8489 100644 --- a/cl/PMD2Graph/main.cpp +++ b/cl/PMD2Graph/main.cpp @@ -58,7 +58,6 @@ static string changepathfrom; static string changepathto; static string lim; static string separator = ";"; -static string faulthunter_rul; static bool exportRul = false; static bool printstdout = false; static std::string out; //name of the output file @@ -160,11 +159,6 @@ static bool ppPrintStdOut (const Option *o, char *argv[]) { return true; } -static bool ppFaultHunterRul(const Option *o, char *argv[]) { - faulthunter_rul = argv[0]; - return true; -} - const Option OPTIONS_OBJ [] = { { false, "-makerul", 0, "", 1, OT_NONE, ppMakeRul, NULL, "Making rul file based on input list file."}, { false, "-makeconfig", 0, "", 1, OT_NONE, ppMakeCfg, NULL, "Making config file based on input rul file."}, @@ -183,7 +177,6 @@ const Option OPTIONS_OBJ [] = { { false, "-out", 1, "file", 0, OT_WC, ppOut, NULL, "Specify the name of the output file. The list of rule violations will be dumped in it.\n" "Either this or the -printstdout switch has to be provided."}, { false, "-printstdout", 0, "", 0, OT_NONE, ppPrintStdOut, NULL, "Dump the detected rule violations to the standard output."}, - { false, "-faulthunterrul", 1, "rulfile", 0, OT_WC, ppFaultHunterRul, NULL, "Name of the FaultHunter rul file."}, CL_EXPORTRUL COMMON_CL_ARGS }; @@ -274,7 +267,7 @@ int main(int argc, char *argv[]) { rul_str = getExecutableProgramDir() + rul_str; PMDStrategy pmd_strategy; if(makerul){ - pmd_strategy.makeRul(file_names, rul_str, rulConfig, rul_options, faulthunter_rul); + pmd_strategy.makeRul(file_names, rul_str, rulConfig, rul_options); }else if(makeconfig){ pmd_strategy.makeConfig(file_names, rul_str, rulConfig, config); } else if(makecsv){ @@ -295,8 +288,6 @@ int main(int argc, char *argv[]) { if(f != stdout) { fclose(f); } - - pmd_strategy.addLicenseTypeToTheGraphHeader(EXECUTABLE_NAME); if (!graph_filename.empty()) pmd_strategy.saveGraph(graph_filename, exportRul); diff --git a/cl/PMD2Graph/messages.h b/cl/PMD2Graph/messages.h index ebb7f1d..58da4e1 100644 --- a/cl/PMD2Graph/messages.h +++ b/cl/PMD2Graph/messages.h @@ -46,7 +46,6 @@ #define CMSG_PMD2GRAPH_ERROR_WRITING_XML_FILE WriteMsg::mlError, "Error: An error occurred while writing XML file\n" //MetricTree.cpp messages -#define CMSG_PMD2GRAPH_USING_CONFIG WriteMsg::mlNormal, "Using configuration: \"%s\"\n" #define CMSG_PMD2GRAPH_LOADING_LIM WriteMsg::mlNormal, "Loading LIM ASG file \"%s\"\n" #define CMSG_PMD2GRAPH_LOADING_LIM_FILTER WriteMsg::mlNormal, "Loading filter file \"%s\"\n" #define CMSG_PMD2GRAPH_FILTER_FILE_IS_DEPRECATED WriteMsg::mlWarning, "Warning: Filter file (%s) is older than the input file. Filter file is not used.\n" diff --git a/cl/Pylint2Graph/CMakeLists.txt b/cl/Pylint2Graph/CMakeLists.txt new file mode 100644 index 0000000..47f4b88 --- /dev/null +++ b/cl/Pylint2Graph/CMakeLists.txt @@ -0,0 +1,20 @@ +set (PROGRAM_NAME Pylint2Graph) + +set (SOURCES + src/main.cpp + src/Pylint2Graph.cpp + src/PylintRulMaker.cpp + src/PylintRunner.cpp + + inc/messages.h + inc/Pylint2Graph.h + inc/PylintRulMaker.h + inc/PylintRunner.h +) + +add_executable(${PROGRAM_NAME} ${SOURCES}) +add_dependencies(${PROGRAM_NAME} ${COLUMBUS_GLOBAL_DEPENDENCY}) +target_link_libraries(${PROGRAM_NAME} python lim2graph graphsupport lim graph rul common csi strtable io ${COMMON_EXTERNAL_LIBRARIES}) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} Pylint.rul) +add_copy_next_to_the_binary_dependency(${PROGRAM_NAME} Pylint.conf) +set_visual_studio_project_folder(${PROGRAM_NAME} TRUE) diff --git a/cl/Pylint2Graph/Pylint.conf b/cl/Pylint2Graph/Pylint.conf new file mode 100644 index 0000000..bb20265 --- /dev/null +++ b/cl/Pylint2Graph/Pylint.conf @@ -0,0 +1,32 @@ + +[MESSAGES CONTROL] + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=similarities,master + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=no + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +msg-template=:{abspath}:{line}:{column}: [{msg_id}({symbol})] {msg} + diff --git a/cl/Pylint2Graph/Pylint.rul b/cl/Pylint2Graph/Pylint.rul new file mode 100644 index 0000000..d147dbe --- /dev/null +++ b/cl/Pylint2Graph/Pylint.rul @@ -0,0 +1,6855 @@ + + + + + Pylint + + + + + + + + true + true + summarized + async + + true + Async Rules + Async Rules + Async Rules + + + + Minor + + + + + + + true + true + summarized + basic + + true + Basic Rules + Basic Rules + Basic Rules + + + + Minor + + + + + + + true + true + summarized + classes + + true + Class Rules + Class Rules + Class Rules + + + + Minor + + + + + + + true + true + summarized + design + + true + Design Rules + Design Rules + Design Rules + + + + Minor + + + + + + + true + true + summarized + exceptions + + true + Exception Rules + Exception Rules + Exception Rules + + + + Minor + + + + + + + true + true + summarized + format + + true + Format Rules + Format Rules + Format Rules + + + + Minor + + + + + + + true + true + summarized + imports + + true + Import Rules + Import Rules + Import Rules + + + + Minor + + + + + + + true + true + summarized + iterable_check + + true + Iterable Check Rules + Iterable Check Rules + Iterable Check Rules + + + + Minor + + + + + + + true + true + summarized + len + + true + Len Rules + Len Rules + Len Rules + + + + Minor + + + + + + + true + true + summarized + logging + + true + Logging Rules + Logging Rules + Logging Rules + + + + Minor + + + + + + + true + true + summarized + miscellaneous + + true + Miscellaneous Rules + Miscellaneous Rules + Miscellaneous Rules + + + + Minor + + + + + + + true + true + summarized + newstyle + + true + Newstyle Rules + Newstyle Rules + Newstyle Rules + + + + Minor + + + + + + + true + true + false + apply-builtin + Python3 Rules + + true + Apply Builtin + Used when the apply built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the apply built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + apply built-in referenced + + + + Major + + + + + + + true + true + false + anomalous-backslash-in-string + String Constant Rules + + true + Anomalous Backslash In String + Used when a backslash is in a literal string but not as an escape. + <p>Used when a backslash is in a literal string but not as an escape.</p> + Anomalous backslash in string: '%s'. String constant might be missing an r prefix. + + + + Major + + + + + + + true + true + false + abstract-class-instantiated + Basic Rules + + true + Abstract Class Instantiated + Used when an abstract class with `abc.ABCMeta` as metaclass has abstract methods and is instantiated. + <p>Used when an abstract class with <code>abc.ABCMeta</code> as metaclass has abstract methods and is instantiated.</p> + Abstract class %r with abstract methods instantiated + + + + Critical + + + + + + + true + true + false + arguments-differ + Class Rules + + true + Arguments Differ + Used when a method has a different number of arguments than in the implemented interface or in an overridden method. + <p>Used when a method has a different number of arguments than in the implemented interface or in an overridden method.</p> + Parameters differ from %s %r method + + + + Major + + + + + + + true + true + false + attribute-defined-outside-init + Class Rules + + true + Attribute Defined Outside Init + Used when an instance attribute is defined outside the __init__ method. + <p>Used when an instance attribute is defined outside the __init__ method.</p> + Attribute %r defined outside __init__ + + + + Major + + + + + + + false + true + false + astroid-error + Pylint Checker Rules + + true + Astroid Error + Used when an unexpected error occurred while building the Astroid representation. This is usually accompanied by a traceback. Please report such errors! + Used when an unexpected error occurred while building the Astroid representation. This is usually accompanied by a traceback. Please report such errors! + %s: %s + + + + Blocker + + + + + + + true + true + false + assignment-from-none + Typecheck Rules + + true + Assignment From None + Used when an assignment is done on a function call but the inferred function returns nothing but None. + <p>Used when an assignment is done on a function call but the inferred function returns nothing but None.</p> + Assigning to function call which only returns None + + + + Critical + + + + + + + true + true + false + assignment-from-no-return + Typecheck Rules + + true + Assignment From No Return + Used when an assignment is done on a function call but the inferred function doesn't return anything. + <p>Used when an assignment is done on a function call but the inferred function doesn’t return anything.</p> + Assigning to function call which doesn't return + + + + Critical + + + + + + + true + true + false + abstract-method + Class Rules + + true + Abstract Method + Used when an abstract method (i.e. raise NotImplementedError) is not overridden in concrete class. + <p>Used when an abstract method (i.e. raise NotImplementedError) is not overridden in concrete class.</p> + Method %r is abstract in class %r but is not overridden + + + + Major + + + + + + + true + true + false + access-member-before-definition + Class Rules + + true + Access Member Before Definition + Used when an instance member is accessed before it's actually assigned. + <p>Used when an instance member is accessed before it’s actually assigned.</p> + Access to member %r before its definition line %s + + + + Critical + + + + + + + true + true + false + assigning-non-slot + Class Rules + + true + Assigning Non Slot + Used when assigning to an attribute not defined in the class slots. + <p>Used when assigning to an attribute not defined in the class slots.</p> + Assigning to attribute %r not defined in class slots + + + + Critical + + + + + + + true + true + false + assert-on-tuple + Basic Rules + + true + Assert On Tuple + A call of assert on a tuple will always evaluate to true if the tuple is not empty, and will always evaluate to false if it is. + <p>A call of assert on a tuple will always evaluate to true if the tuple is not empty, and will always evaluate to false if it is.</p> + Assert called on a 2-uple. Did you mean 'assert x,y'? + + + + Major + + + + + + + true + true + false + assign-to-new-keyword + Basic Rules + + true + Assign To New Keyword + Used when assignment will become invalid in future Python release due to introducing new keyword. + <p>Used when assignment will become invalid in future Python release due to introducing new keyword.</p> + Name %s will become a keyword in Python %s + + + + Major + + + + + + + true + true + false + anomalous-unicode-escape-in-string + String Constant Rules + + true + Anomalous Unicode Escape In String + Used when an escape like \u is encountered in a byte string where it has no effect. + <p>Used when an escape like \u is encountered in a byte string where it has no effect.</p> + Anomalous Unicode escape in byte string: '%s'. String constant might be missing an r or u prefix. + + + + Major + + + + + + + true + true + false + backtick + Python3 Rules + + true + Backtick + Used when the deprecated "``" (backtick) operator is used instead of the str() function. This message can't be emitted when using Python >= 3.0. + <p>Used when the deprecated “``” (backtick) operator is used instead of the str() function. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of the `` operator + + + + Critical + + + + + + + true + true + false + bad-continuation + Format Rules + + true + Bad Continuation + TODO + <p>TODO</p> + Wrong %s indentation%s%s. + + + + Minor + + + + + + + true + true + false + bad-classmethod-argument + Class Rules + + true + Bad Classmethod Argument + Used when a class method has a first argument named differently than the value specified in valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from regular instance methods. + <p>Used when a class method has a first argument named differently than the value specified in valid-classmethod-first-arg option (default to “cls”), recommended to easily differentiate them from regular instance methods.</p> + Class method %s should have %s as first argument + + + + Minor + + + + + + + true + true + false + boolean-datetime + Stdlib Rules + + true + Boolean Datetime + Using datetime.time in a boolean context can hide subtle bugs when the time they represent matches midnight UTC. This behaviour was fixed in Python 3.5. See http://bugs.python.org/issue13936 for reference. This message can't be emitted when using Python >= 3.5. + <p>Using datetime.time in a boolean context can hide subtle bugs when the time they represent matches midnight UTC. This behaviour was fixed in Python 3.5. See <a href="http://bugs.python.org/issue13936" class="uri">http://bugs.python.org/issue13936</a> for reference. This message can’t be emitted when using Python &gt;= 3.5.</p> + Using datetime.time in a boolean context. + + + + Major + + + + + + + true + true + false + bare-except + Exception Rules + + true + Bare Except + Used when an except clause doesn't specify exceptions type to catch. + <p>Used when an except clause doesn’t specify exceptions type to catch.</p> + No exception type(s) specified + + + + Major + + + + + + + true + true + false + bad-exception-context + Exception Rules + + true + Bad Exception Context + Used when using the syntax "raise ... from ...", where the exception context is not an exception, nor None. This message can't be emitted when using Python < 3.0. + <p>Used when using the syntax “raise … from …”, where the exception context is not an exception, nor None. This message can’t be emitted when using Python &lt; 3.0.</p> + Exception context set to something which is not an exception, nor None + + + + Critical + + + + + + + true + true + false + bad-except-order + Exception Rules + + true + Bad Except Order + Used when except clauses are not in the correct order (from the more specific to the more generic). If you don't fix the order, some exceptions may not be caught by the most specific handler. + <p>Used when except clauses are not in the correct order (from the more specific to the more generic). If you don’t fix the order, some exceptions may not be catched by the most specific handler.</p> + Bad except clauses order (%s) + + + + Critical + + + + + + + true + true + false + bad-format-character + String Rules + + true + Bad Format Character + Used when a unsupported format character is used in a format string. + <p>Used when a unsupported format character is used in a format string.</p> + Unsupported format character %r (%#02x) at index %d + + + + Critical + + + + + + + true + true + false + bad-format-string + String Rules + + true + Bad Format String + Used when a PEP 3101 format string is invalid. This message can't be emitted when using Python < 2.7. + <p>Used when a PEP 3101 format string is invalid. This message can’t be emitted when using Python &lt; 2.7.</p> + Invalid format string + + + + Major + + + + + + + true + true + false + bad-format-string-key + String Rules + + true + Bad Format String Key + Used when a format string that uses named conversion specifiers is used with a dictionary whose keys are not all strings. + <p>Used when a format string that uses named conversion specifiers is used with a dictionary whose keys are not all strings.</p> + Format string dictionary key should be a string, not %s + + + + Major + + + + + + + true + true + false + bad-indentation + Format Rules + + true + Bad Indentation + Used when an unexpected number of indentation's tabulations or spaces has been found. + <p>Used when an unexpected number of indentation’s tabulations or spaces has been found.</p> + Bad indentation. Found %s %s, expected %s + + + + Major + + + + + + + false + true + false + bad-inline-option + Pylint Checker Rules + + true + Bad Inline Option + Used when an inline option is either badly formatted or can't be used inside modules. + Used when an inline option is either badly formatted or can't be used inside modules. + Unable to consider inline option %r + + + + Minor + + + + + + + true + true + false + bad-mcs-classmethod-argument + Class Rules + + true + Bad Mcs Classmethod Argument + Used when a metaclass class method has a first argument named differently than the value specified in valid-metaclass-classmethod-first-arg option (default to "mcs"), recommended to easily differentiate them from regular instance methods. + <p>Used when a metaclass class method has a first argument named differently than the value specified in valid-metaclass-classmethod-first-arg option (default to “mcs”), recommended to easily differentiate them from regular instance methods.</p> + Metaclass class method %s should have %s as first argument + + + + Minor + + + + + + + true + true + false + bad-mcs-method-argument + Class Rules + + true + Bad Mcs Method Argument + Used when a metaclass method has a first argument named differently than the value specified in valid-classmethod-first-arg option (default to "cls"), recommended to easily differentiate them from regular instance methods. + <p>Used when a metaclass method has a first agument named differently than the value specified in valid-classmethod-first-arg option (default to “cls”), recommended to easily differentiate them from regular instance methods.</p> + Metaclass method %s should have %s as first argument + + + + Minor + + + + + + + true + true + false + blacklisted-name + Basic Rules + + true + Blacklisted Name + Used when the name is listed in the black list (unauthorized names). + <p>Used when the name is listed in the black list (unauthorized names).</p> + Black listed name "%s" + + + + Minor + + + + + + + true + true + false + binary-op-exception + Exception Rules + + true + Binary Op Exception + Used when the exception to catch is of the form "except A or B:". If intending to catch multiple, rewrite as "except (A, B):". + <p>Used when the exception to catch is of the form “except A or B:”. If intending to catch multiple, rewrite as “except (A, B):”.</p> + Exception to catch is the result of a binary "%s" operation + + + + Major + + + + + + + true + true + false + bad-open-mode + Stdlib Rules + + true + Bad Open Mode + Python supports: r, w, a[, x] modes with b, +, and U (only with r) options. See http://docs.python.org/2/library/functions.html#open. + <p>Python supports: r, w, a[, x] modes with b, +, and U (only with r) options. See <a href="http://docs.python.org/2/library/functions.html#open" class="uri">http://docs.python.org/2/library/functions.html#open</a>.</p> + "%s" is not a valid mode for open. + + + + Major + + + + + + + false + true + false + bad-option-value + Pylint Checker Rules + + true + Bad Option Value + Used when a bad value for an inline option is encountered. + Used when a bad value for an inline option is encountered. + Bad option value %r + + + + Critical + + + + + + + true + true + false + bad-python3-import + Python3 Rules + + true + Bad Python3 Import + Used when importing a module that no longer exists in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when importing a module that no longer exists in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Module moved in Python 3 + + + + Major + + + + + + + true + true + false + bad-reversed-sequence + Basic Rules + + true + Bad Reversed Sequence + Used when the first argument to reversed() builtin isn't a sequence (does not implement __reversed__, nor __getitem__ and __len__. + <p>Used when the first argument to reversed() builtin isn’t a sequence (does not implement __reversed__, nor __getitem__ and __len__.</p> + The first reversed() argument is not a sequence + + + + Critical + + + + + + + true + true + false + bad-staticmethod-argument + Class Rules + + true + Bad Staticmethod Argument + Used when a static method has "self" or a value specified in valid-classmethod-first-arg option or valid-metaclass-classmethod-first-arg option as first argument. + <p>Used when a static method has “self” or a value specified in valid-classmethod-first-arg option or valid-metaclass-classmethod-first-arg option as first argument.</p> + Static method with %r as first argument + + + + Major + + + + + + + true + true + false + bad-super-call + Newstyle Rules + + true + Bad Super Call + Used when another argument than the current class is given as first argument of the super builtin. + <p>Used when another argument than the current class is given as first argument of the super builtin.</p> + Bad first argument %r given to super() + + + + Critical + + + + + + + true + true + false + bad-str-strip-call + String Rules + + true + Bad Str Strip Call + The argument to a str.{l,r,}strip call contains a duplicate character. + <p>The argument to a str.{l,r,}strip call contains a duplicate character.</p> + Suspicious argument in %s.%s call + + + + Critical + + + + + + + true + true + false + bad-thread-instantiation + Stdlib Rules + + true + Bad Thread Instantiation + The warning is emitted when a threading.Thread class is instantiated without the target function being passed. By default, the first parameter is the group param, not the target param. + <p>The warning is emitted when a threading.Thread class is instantiated without the target function being passed. By default, the first parameter is the group param, not the target param.</p> + threading.Thread needs the target function + + + + Major + + + + + + + true + true + false + bad-whitespace + Format Rules + + true + Bad Whitespace + Used when a wrong number of spaces is used around an operator, bracket or block opener. + <p>Used when a wrong number of spaces is used around an operator, bracket or block opener.</p> + %s space %s %s %s + + + + Minor + + + + + + + true + true + false + basestring-builtin + Python3 Rules + + true + Basestring Builtin + Used when the basestring built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the basestring built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + basestring built-in referenced + + + + Major + + + + + + + true + true + false + broad-except + Exception Rules + + true + Broad Except + Used when an except catches a too general exception, possibly burying unrelated errors. + <p>Used when an except catches a too general exception, possibly burying unrelated errors.</p> + Catching too general exception %s + + + + Major + + + + + + + true + true + false + buffer-builtin + Python3 Rules + + true + Buffer Builtin + Used when the buffer built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the buffer built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + buffer built-in referenced + + + + Major + + + + + + + true + true + false + cmp-builtin + Python3 Rules + + true + Cmp Builtin + Used when the cmp built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the cmp built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + cmp built-in referenced + + + + Major + + + + + + + true + true + false + c-extension-no-member + Typecheck Rules + + true + C Extension No Member + Used when a variable is accessed for non-existent member of C extension. Due to unavailability of source static analysis is impossible, but it may be performed by introspecting living objects in run-time. + <p>Used when a variable is accessed for non-existent member of C extension. Due to unavailability of source static analysis is impossible, but it may be performed by introspecting living objects in run-time.</p> + %s %r has not %r member%s, but source is unavailable. Consider adding this module to extension-pkg-whitelist if you want to perform analysis based on run-time introspection of living objects. + + + + Minor + + + + + + + true + true + false + cyclic-import + Import Rules + + true + Cyclic Import + Used when a cyclic import between two or more modules is detected. + <p>Used when a cyclic import between two or more modules is detected.</p> + Cyclic import (%s) + + + + Minor + + + + + + + true + true + false + consider-iterating-dictionary + Refactoring Rules + + true + Consider Iterating Dictionary + Emitted when the keys of a dictionary are iterated through the .keys() method. It is enough to just iterate through the dictionary itself, as in "for key in dictionary". + <p>Emitted when the keys of a dictionary are iterated through the .keys() method. It is enough to just iterate through the dictionary itself, as in “for key in dictionary”.</p> + Consider iterating the dictionary directly instead of calling .keys() + + + + Minor + + + + + + + true + true + false + continue-in-finally + Basic Rules + + true + Continue In Finally + Emitted when the `continue` keyword is found inside a finally clause, which is a SyntaxError. + <p>Emitted when the <code>continue</code> keyword is found inside a finally clause, which is a SyntaxError.</p> + 'continue' not supported inside 'finally' clause + + + + Critical + + + + + + + true + true + false + cmp-method + Python3 Rules + + true + Cmp Method + Used when a __cmp__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __cmp__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __cmp__ method defined + + + + Major + + + + + + + true + true + false + consider-merging-isinstance + Refactoring Rules + + true + Consider Merging Isinstance + Used when multiple consecutive isinstance calls can be merged into one. + <p>Used when multiple consecutive isinstance calls can be merged into one.</p> + Consider merging these isinstance calls to isinstance(%s, (%s)) + + + + Minor + + + + + + + true + true + false + catching-non-exception + Exception Rules + + true + Catching Non Exception + Used when a class which doesn't inherit from Exception is used as an exception in an except clause. + <p>Used when a class which doesn’t inherit from BaseException is used as an exception in an except clause.</p> + Catching an exception which doesn't inherit from Exception: %s + + + + Critical + + + + + + + true + true + false + consider-using-enumerate + Refactoring Rules + + true + Consider Using Enumerate + Emitted when code that iterates with range and len is encountered. Such code can be simplified by using the enumerate builtin. + <p>Emitted when code that iterates with range and len is encountered. Such code can be simplified by using the enumerate builtin.</p> + Consider using enumerate instead of iterating with range and len + + + + Minor + + + + + + + true + true + false + consider-using-ternary + Refactoring Rules + + true + Consider Using Ternary + Used when one of known pre-python 2.5 ternary syntax is used. + <p>Used when one of known pre-python 2.5 ternary syntax is used.</p> + Consider using ternary (%s) + + + + Minor + + + + + + + true + true + false + cell-var-from-loop + Variable Rules + + true + Cell Var From Loop + A variable used in a closure is defined in a loop. This will result in all closures using the same value for the closed-over variable. + <p>A variable used in a closure is defined in a loop. This will result in all closures using the same value for the closed-over variable.</p> + Cell variable %s defined in loop + + + + Major + + + + + + + true + true + false + confusing-with-statement + Basic Rules + + true + Confusing With Statement + Emitted when a `with` statement component returns multiple values and uses name binding with `as` only for a part of those values, as in with ctx() as a, b. This can be misleading, since it's not clear if the context manager returns a tuple or if the node without a name binding is another context manager. + <p>Emitted when a <code>with</code> statement component returns multiple values and uses name binding with <code>as</code> only for a part of those values, as in with ctx() as a, b. This can be misleading, since it’s not clear if the context manager returns a tuple or if the node without a name binding is another context manager.</p> + Following "as" with another context manager looks like a tuple. + + + + Major + + + + + + + true + true + false + coerce-builtin + Python3 Rules + + true + Coerce Builtin + Used when the coerce built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the coerce built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + coerce built-in referenced + + + + Major + + + + + + + true + true + false + coerce-method + Python3 Rules + + true + Coerce Method + Used when a __coerce__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __coerce__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __coerce__ method defined + + + + Major + + + + + + + true + true + false + duplicate-argument-name + Basic Rules + + true + Duplicate Argument Name + Duplicate argument names in function definitions are syntax errors. + <p>Duplicate argument names in function definitions are syntax errors.</p> + Duplicate argument name %s in function definition + + + + Critical + + + + + + + true + true + false + duplicate-bases + Class Rules + + true + Duplicate Bases + Used when a class has duplicate bases. + <p>Used when a class has duplicate bases.</p> + Duplicate bases for class %r + + + + Critical + + + + + + + false + true + false + duplicate-code + Similarity Rules + + true + Duplicate Code + Indicates that a set of similar lines has been detected among multiple file. This usually means that the code should be refactored to avoid this duplication. + Indicates that a set of similar lines has been detected among multiple file. This usually means that the code should be refactored to avoid this duplication. + Similar lines in %s files + + + + Minor + + + + + + + true + true + false + dangerous-default-value + Basic Rules + + true + Dangerous Default Value + Used when a mutable value as list or dictionary is detected in a default value for an argument. + <p>Used when a mutable value as list or dictionary is detected in a default value for an argument.</p> + Dangerous default value %s as argument + + + + Major + + + + + + + true + true + false + duplicate-except + Exception Rules + + true + Duplicate Except + Used when an except catches a type that was already caught by a previous handler. + <p>Used when an except catches a type that was already caught by a previous handler.</p> + Catching previously caught exception type %s + + + + Major + + + + + + + true + true + false + deprecated-itertools-function + Python3 Rules + + true + Deprecated Itertools Function + Used when accessing a function on itertools that has been removed in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when accessing a function on itertools that has been removed in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Accessing a deprecated function on the itertools module + + + + Major + + + + + + + true + true + false + dict-iter-method + Python3 Rules + + true + Dict Iter Method + Used for calls to dict.iterkeys(), itervalues() or iteritems() (Python 3 lacks these methods). This message can't be emitted when using Python >= 3.0. + <p>Used for calls to dict.iterkeys(), itervalues() or iteritems() (Python 3 lacks these methods). This message can’t be emitted when using Python &gt;= 3.0.</p> + Calling a dict.iter*() method + + + + Major + + + + + + + true + true + false + dict-items-not-iterating + Python3 Rules + + true + Dict Items Not Iterating + Used when dict.items is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when dict.items is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + dict.items referenced when not iterating + + + + Major + + + + + + + true + true + false + duplicate-key + Basic Rules + + true + Duplicate Key + Used when a dictionary expression binds the same key multiple times. + <p>Used when a dictionary expression binds the same key multiple times.</p> + Duplicate key %r in dictionary + + + + Major + + + + + + + true + true + false + dict-keys-not-iterating + Python3 Rules + + true + Dict Keys Not Iterating + Used when dict.keys is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when dict.keys is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + dict.keys referenced when not iterating + + + + Major + + + + + + + true + true + false + deprecated-lambda + Basic Rules + + true + Deprecated Lambda + Used when a lambda is the first argument to "map" or "filter". It could be clearer as a list comprehension or generator expression. This message can't be emitted when using Python >= 3.0. + <p>Used when a lambda is the first argument to “map” or “filter”. It could be clearer as a list comprehension or generator expression. This message can’t be emitted when using Python &gt;= 3.0.</p> + map/filter on lambda could be replaced by comprehension + + + + Major + + + + + + + true + true + false + delslice-method + Python3 Rules + + true + Delslice Method + Used when a __delslice__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __delslice__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __delslice__ method defined + + + + Major + + + + + + + false + true + false + deprecated-pragma + Pylint Checker Rules + + true + Deprecated Pragma + Some inline pylint options have been renamed or reworked, only the most recent form should be used. NOTE:skip-all is only available with pylint >= 0.26. + Some inline pylint options have been renamed or reworked, only the most recent form should be used. NOTE:skip-all is only available with pylint >= 0.26. + Pragma "%s" is deprecated, use "%s" instead + + + + Minor + + + + + + + true + true + false + deprecated-string-function + Python3 Rules + + true + Deprecated String Function + Used when accessing a string function that has been deprecated in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when accessing a string function that has been deprecated in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Accessing a function method on the string module + + + + Major + + + + + + + true + true + false + deprecated-str-translate-call + Python3 Rules + + true + Deprecated Str Translate Call + Used when using the deprecated deletechars parameters from str.translate. Usere.sub to remove the desired characters. This message can't be emitted when using Python >= 3.0. + <p>Used when using the deprecated deletechars parameters from str.translate. Usere.sub to remove the desired characters. This message can’t be emitted when using Python &gt;= 3.0.</p> + Using str.translate with deprecated deletechars parameters + + + + Major + + + + + + + true + true + false + deprecated-types-field + Python3 Rules + + true + Deprecated Types Field + Used when accessing a field on types that has been removed in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when accessing a field on types that has been removed in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Accessing a deprecated fields on the types module + + + + Major + + + + + + + true + true + false + dict-view-method + Python3 Rules + + true + Dict View Method + Used for calls to dict.viewkeys(), viewvalues() or viewitems() (Python 3 lacks these methods). This message can't be emitted when using Python >= 3.0. + <p>Used for calls to dict.viewkeys(), viewvalues() or viewitems() (Python 3 lacks these methods). This message can’t be emitted when using Python &gt;= 3.0.</p> + Calling a dict.view*() method + + + + Major + + + + + + + true + true + false + dict-values-not-iterating + Python3 Rules + + true + Dict Values Not Iterating + Used when dict.values is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when dict.values is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + dict.values referenced when not iterating + + + + Major + + + + + + + true + true + false + deprecated-module + Import Rules + + true + Deprecated Module + Used a module marked as deprecated is imported. + <p>Used a module marked as deprecated is imported.</p> + Uses of a deprecated module %r + + + + Major + + + + + + + true + true + false + deprecated-method + Stdlib Rules + + true + Deprecated Method + The method is marked as deprecated and will be removed in a future version of Python. Consider looking for an alternative in the documentation. + <p>The method is marked as deprecated and will be removed in a future version of Python. Consider looking for an alternative in the documentation.</p> + Using deprecated method %s() + + + + Major + + + + + + + true + true + false + div-method + Python3 Rules + + true + Div Method + Used when a __div__ method is defined. Using `__truediv__` and setting__div__ = __truediv__ should be preferred.(method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __div__ method is defined. Using <code>__truediv__</code> and setting__div__ = __truediv__ should be preferred.(method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __div__ method defined + + + + Major + + + + + + + true + true + false + execfile-builtin + Python3 Rules + + true + Execfile Builtin + Used when the execfile built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the execfile built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + execfile built-in referenced + + + + Major + + + + + + + true + true + false + empty-docstring + Basic Rules + + true + Empty Docstring + Used when a module, function, class or method has an empty docstring (it would be too easy ;). + <p>Used when a module, function, class or method has an empty docstring (it would be too easy ;).</p> + Empty %s docstring + + + + Minor + + + + + + + true + true + false + exception-message-attribute + Python3 Rules + + true + Exception Message Attribute + Used when the message attribute is accessed on an Exception. Use str(exception) instead. This message can't be emitted when using Python >= 3.0. + <p>Used when the message attribute is accessed on an Exception. Use str(exception) instead. This message can’t be emitted when using Python &gt;= 3.0.</p> + Exception.message removed in Python 3 + + + + Major + + + + + + + true + true + false + expression-not-assigned + Basic Rules + + true + Expression Not Assigned + Used when an expression that is not a function call is assigned to nothing. Probably something else was intended. + <p>Used when an expression that is not a function call is assigned to nothing. Probably something else was intended.</p> + Expression "%s" is assigned to nothing + + + + Major + + + + + + + true + true + false + eval-used + Basic Rules + + true + Eval Used + Used when you use the "eval" function, to discourage its usage. Consider using `ast.literal_eval` for safely evaluating strings containing Python expressions from untrusted sources. + <p>Used when you use the “eval” function, to discourage its usage. Consider using <code>ast.literal_eval</code> for safely evaluating strings containing Python expressions from untrusted sources.</p> + Use of eval + + + + Major + + + + + + + true + true + false + eq-without-hash + Python3 Rules + + true + Eq Without Hash + Used when a class implements __eq__ but not __hash__. In Python 2, objects get object.__hash__ as the default implementation, in Python 3 objects get None as their default __hash__ implementation if they also implement __eq__. This message can't be emitted when using Python >= 3.0. + <p>Used when a class implements __eq__ but not __hash__. In Python 2, objects get object.__hash__ as the default implementation, in Python 3 objects get None as their default __hash__ implementation if they also implement __eq__. This message can’t be emitted when using Python &gt;= 3.0.</p> + Implementing __eq__ without also implementing __hash__ + + + + Major + + + + + + + true + true + false + exec-used + Basic Rules + + true + Exec Used + Used when you use the "exec" statement (function for Python 3), to discourage its usage. That doesn't mean you cannot use it! + <p>Used when you use the “exec” statement (function for Python 3), to discourage its usage. That doesn’t mean you can not use it!</p> + Use of exec + + + + Major + + + + + + + false + true + false + fatal + Pylint Checker Rules + + true + Fatal + Used when an error occurred preventing the analysis of a module (unable to find it for instance). + Used when an error occurred preventing the analysis of a module (unable to find it for instance). + + + + + Blocker + + + + + + + true + true + false + file-builtin + Python3 Rules + + true + File Builtin + Used when the file built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the file built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + file built-in referenced + + + + Major + + + + + + + true + true + false + filter-builtin-not-iterating + Python3 Rules + + true + Filter Builtin Not Iterating + Used when the filter built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the filter built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + filter built-in referenced when not iterating + + + + Major + + + + + + + true + true + false + format-combined-specification + String Rules + + true + Format Combined Specification + Used when a PEP 3101 format string contains both automatic field numbering (e.g. '{}') and manual field specification (e.g. '{0}'). This message can't be emitted when using Python < 2.7. + <p>Usen when a PEP 3101 format string contains both automatic field numbering (e.g. ‘{}’) and manual field specification (e.g. ‘{0}’). This message can’t be emitted when using Python &lt; 2.7.</p> + Format string contains both automatic field numbering and manual field specification + + + + Major + + + + + + + false + true + false + file-ignored + Pylint Checker Rules + + true + File Ignored + Used to inform that the file will not be checked. + Used to inform that the file will not be checked. + Ignoring entire file + + + + Minor + + + + + + + true + true + false + format-needs-mapping + String Rules + + true + Format Needs Mapping + Used when a format string that uses named conversion specifiers is used with an argument that is not a mapping. + <p>Used when a format string that uses named conversion specifiers is used with an argument that is not a mapping.</p> + Expected mapping for format string, not %s + + + + Critical + + + + + + + true + true + false + function-redefined + Basic Rules + + true + Function Redefined + Used when a function / class / method is redefined. + <p>Used when a function / class / method is redefined.</p> + %s already defined line %s + + + + Critical + + + + + + + true + true + false + fixme + Miscellaneous Rules + + true + Fixme + Used when a warning note as FIXME or XXX is detected. + <p>Used when a warning note as FIXME or XXX is detected.</p> + + + + + Major + + + + + + + true + true + false + global-at-module-level + Variable Rules + + true + Global At Module Level + Used when you use the "global" statement at the module level since it has no effect. + <p>Used when you use the “global” statement at the module level since it has no effect.</p> + Using the global statement at the module level + + + + Major + + + + + + + true + true + false + getslice-method + Python3 Rules + + true + Getslice Method + Used when a __getslice__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __getslice__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __getslice__ method defined + + + + Major + + + + + + + true + true + false + global-statement + Variable Rules + + true + Global Statement + Used when you use the "global" statement to update a global variable. Pylint just try to discourage this usage. That doesn't mean you cannot use it! + <p>Used when you use the “global” statement to update a global variable. Pylint just try to discourage this usage. That doesn’t mean you can not use it!</p> + Using the global statement + + + + Major + + + + + + + true + true + false + global-variable-not-assigned + Variable Rules + + true + Global Variable Not Assigned + Used when a variable is defined through the "global" statement but no assignment to this variable is done. + <p>Used when a variable is defined through the “global” statement but no assignment to this variable is done.</p> + Using global for %r but no assignment is done + + + + Major + + + + + + + true + true + false + global-variable-undefined + Variable Rules + + true + Global Variable Undefined + Used when a variable is defined through the "global" statement but the variable is not defined in the module scope. + <p>Used when a variable is defined through the “global” statement but the variable is not defined in the module scope.</p> + Global variable %r undefined at the module level + + + + Major + + + + + + + true + true + false + hex-method + Python3 Rules + + true + Hex Method + Used when a __hex__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __hex__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __hex__ method defined + + + + Major + + + + + + + true + true + false + invalid-all-object + Variable Rules + + true + Invalid All Object + Used when an invalid (non-string) object occurs in __all__. + <p>Used when an invalid (non-string) object occurs in __all__.</p> + Invalid object %r in __all__, must contain only strings + + + + Critical + + + + + + + true + true + false + input-builtin + Python3 Rules + + true + Input Builtin + Used when the input built-in is referenced (backwards-incompatible semantics in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the input built-in is referenced (backwards-incompatible semantics in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + input built-in referenced + + + + Major + + + + + + + true + true + false + invalid-characters-in-docstring + Spelling Rules + + true + Invalid Characters In Docstring + Used when a word in docstring cannot be checked by enchant. + <p>Used when a word in docstring cannot be checked by enchant.</p> + Invalid characters %r in a docstring + + + + Minor + + + + + + + false + true + false + import-error + Import Rules + + true + Import Error + Used when pylint has been unable to import a module. + Used when pylint has been unable to import a module. + Unable to import %s + + + + Critical + + + + + + + true + true + false + invalid-encoded-data + Miscellaneous Rules + + true + Invalid Encoded Data + Used when a source line cannot be decoded using the specified source file encoding. This message can't be emitted when using Python >= 3.0. + <p>Used when a source line cannot be decoded using the specified source file encoding. This message can’t be emitted when using Python &gt;= 3.0.</p> + Cannot decode using encoding "%s", unexpected byte at position %d + + + + Major + + + + + + + true + true + false + invalid-format-index + String Rules + + true + Invalid Format Index + Used when a PEP 3101 format string uses a lookup specifier ({a[1]}), but the argument passed for formatting doesn't contain or doesn't have that key as an attribute. This message can't be emitted when using Python < 2.7. + <p>Used when a PEP 3101 format string uses a lookup specifier ({a[1]}), but the argument passed for formatting doesn’t contain or doesn’t have that key as an attribute. This message can’t be emitted when using Python &lt; 2.7.</p> + Using invalid lookup key %r in format specifier %r + + + + Major + + + + + + + true + true + false + init-is-generator + Basic Rules + + true + Init Is Generator + Used when the special class method __init__ is turned into a generator by a yield in its body. + <p>Used when the special class method __init__ is turned into a generator by a yield in its body.</p> + __init__ method is a generator + + + + Critical + + + + + + + true + true + false + invalid-length-returned + Class Rules + + true + Invalid Length Returned + Used when an __len__ method returns something which is not a non-negative integer. + <p>Used when an __len__ method returns something which is not a non-negative integer.</p> + __len__ does not return non-negative integer + + + + Critical + + + + + + + true + true + false + inconsistent-mro + Class Rules + + true + Inconsistent Mro + Used when a class has an inconsistent method resolution order. + <p>Used when a class has an inconsistent method resolutin order.</p> + Inconsistent method resolution order for class %r + + + + Critical + + + + + + + true + true + false + invalid-name + Basic Rules + + true + Invalid Name + Used when the name doesn't conform to naming rules associated to its type (constant, variable, class...). + <p>Used when the name doesn’t match the regular expression associated to its type (constant, variable, class…).</p> + %s name "%s" doesn't conform to %s + + + + Minor + + + + + + + true + true + false + inherit-non-class + Class Rules + + true + Inherit Non Class + Used when a class inherits from something which is not a class. + <p>Used when a class inherits from something which is not a class.</p> + Inheriting %r, which is not a class. + + + + Critical + + + + + + + true + true + false + inconsistent-return-statements + Refactoring Rules + + true + Inconsistent Return Statements + According to PEP8, if any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable). + <p>According to PEP8, if any return statement returns an expression, any return statements where no value is returned should explicitly state this as return None, and an explicit return statement should be present at the end of the function (if reachable).</p> + Either all return statements in a function should return an expression, or none of them should. + + + + Minor + + + + + + + true + true + false + import-self + Import Rules + + true + Import Self + Used when a module is importing itself. + <p>Used when a module is importing itself.</p> + Module import itself + + + + Major + + + + + + + true + true + false + invalid-star-assignment-target + Basic Rules + + true + Invalid Star Assignment Target + Emitted when a star expression is used as a starred assignment target. This message can't be emitted when using Python < 3.0. + <p>Emitted when a star expression is used as a starred assignment target. This message can’t be emitted when using Python &lt; 3.0.</p> + Starred assignment target must be in a list or tuple + + + + Critical + + + + + + + true + true + false + invalid-str-codec + Python3 Rules + + true + Invalid Str Codec + Used when using str.encode or str.decode with a non-text encoding. Use codecs module to handle arbitrary codecs. This message can't be emitted when using Python >= 3.0. + <p>Used when using str.encode or str.decode with a non-text encoding. Use codecs module to handle arbitrary codecs. This message can’t be emitted when using Python &gt;= 3.0.</p> + non-text encoding used in str.decode + + + + Major + + + + + + + true + true + false + invalid-sequence-index + Typecheck Rules + + true + Invalid Sequence Index + Used when a sequence type is indexed with an invalid type. Valid types are ints, slices, and objects with an __index__ method. + <p>Used when a sequence type is indexed with an invalid type. Valid types are ints, slices, and objects with an __index__ method.</p> + Sequence index is not an int, slice, or instance with __index__ + + + + Critical + + + + + + + true + true + false + import-star-module-level + Python3 Rules + + true + Import Star Module Level + Used when the import star syntax is used somewhere else than the module level. This message can't be emitted when using Python >= 3.0. + <p>Used when the import star syntax is used somewhere else than the module level. This message can’t be emitted when using Python &gt;= 3.0.</p> + Import * only allowed at module level + + + + Critical + + + + + + + true + true + false + invalid-slots-object + Class Rules + + true + Invalid Slots Object + Used when an invalid (non-string) object occurs in __slots__. + <p>Used when an invalid (non-string) object occurs in __slots__.</p> + Invalid object %r in __slots__, must contain only non empty strings + + + + Critical + + + + + + + true + true + false + invalid-unary-operand-type + Typecheck Rules + + true + Invalid Unary Operand Type + Emitted when a unary operand is used on an object which does not support this type of operation. + <p>Emitted when an unary operand is used on an object which does not support this type of operation.</p> + + + + + Critical + + + + + + + true + true + false + idiv-method + Python3 Rules + + true + Idiv Method + Used when a __idiv__ method is defined. Using `__itruediv__` and setting__idiv__ = __itruediv__ should be preferred.(method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __idiv__ method is defined. Using <code>__itruediv__</code> and setting__idiv__ = __itruediv__ should be preferred.(method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __idiv__ method defined + + + + Major + + + + + + + true + true + false + intern-builtin + Python3 Rules + + true + Intern Builtin + Used when the intern built-in is referenced (Moved to sys.intern in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the intern built-in is referenced (Moved to sys.intern in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + intern built-in referenced + + + + Major + + + + + + + true + true + false + indexing-exception + Python3 Rules + + true + Indexing Exception + Indexing exceptions will not work on Python 3. Use `exception.args[index]` instead. This message can't be emitted when using Python >= 3.0. + <p>Indexing exceptions will not work on Python 3. Use <code>exception.args[index]</code> instead. This message can’t be emitted when using Python &gt;= 3.0.</p> + Indexing exceptions will not work on Python 3 + + + + Major + + + + + + + true + true + false + invalid-metaclass + Typecheck Rules + + true + Invalid Metaclass + Emitted whenever we can detect that a class is using, as a metaclass, something which might be invalid for using as a metaclass. + <p>Emitted whenever we can detect that a class is using, as a metaclass, something which might be invalid for using as a metaclass.</p> + Invalid metaclass %r used + + + + Critical + + + + + + + true + true + false + invalid-slots + Class Rules + + true + Invalid Slots + Used when an invalid __slots__ is found in class. Only a string, an iterable or a sequence is permitted. + <p>Used when an invalid __slots__ is found in class. Only a string, an iterable or a sequence is permitted.</p> + Invalid __slots__ object + + + + Critical + + + + + + + true + true + false + invalid-slice-index + Typecheck Rules + + true + Invalid Slice Index + Used when a slice index is not an integer, None, or an object with an __index__ method. + <p>Used when a slice index is not an integer, None, or an object with an __index__ method.</p> + Slice index is not an int, None, or instance with __index__ + + + + Critical + + + + + + + true + true + false + keyword-arg-before-vararg + Typecheck Rules + + true + Keyword Arg Before Vararg + When defining a keyword argument before variable positional arguments, one can end up in having multiple values passed for the aforementioned parameter in case the method is called with keyword arguments. + <p>When defining a keyword argument before variable positional arguments, one can end up in having multiple values passed for the aforementioned parameter in case the method is called with keyword arguments.</p> + Keyword argument before variable positional arguments list in the definition of %s function + + + + Major + + + + + + + true + true + false + len-as-condition + Len Rules + + true + Len As Condition + Used when Pylint detects that len(sequence) is being used inside a condition to determine if a sequence is empty. Instead of comparing the length to 0, rely on the fact that empty sequences are false. + <p>Used when Pylint detects incorrect use of len(sequence) inside conditions.</p> + Do not use `len(SEQUENCE)` to determine if a sequence is empty + + + + Minor + + + + + + + true + true + false + long-builtin + Python3 Rules + + true + Long Builtin + Used when the long built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the long built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + long built-in referenced + + + + Major + + + + + + + true + true + false + literal-comparison + Basic Rules + + true + Literal Comparison + Used when comparing an object to a literal, which is usually what you do not want to do, since you can compare to a different literal than what was expected altogether. + <p>Used when comparing an object to a literal, which is usually what you do not want to do, since you can compare to a different literal than what was expected altogether.</p> + Comparison to literal + + + + Minor + + + + + + + false + true + false + locally-disabled + Pylint Checker Rules + + true + Locally Disabled + Used when an inline option disables a message or a messages category. + Used when an inline option disables a message or a messages category. + Locally disabling %s (%s) + + + + Minor + + + + + + + false + true + false + locally-enabled + Pylint Checker Rules + + true + Locally Enabled + Used when an inline option enables a message or a messages category. + Used when an inline option enables a message or a messages category. + Locally enabling %s (%s) + + + + Minor + + + + + + + true + true + false + logging-format-interpolation + Logging Rules + + true + Logging Format Interpolation + Used when a logging statement has a call form of "logging.<logging method>(format_string.format(format_args...))". Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments. + <p>Used when a logging statement has a call form of “logging.&lt;logging method&gt;(format_string.format(format_args…))”. Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments.</p> + Use % formatting in logging functions and pass the % parameters as arguments + + + + Major + + + + + + + true + true + false + logging-format-truncated + Logging Rules + + true + Logging Format Truncated + Used when a logging statement format string terminates before the end of a conversion specifier. + <p>Used when a logging statement format string terminates before the end of a conversion specifier.</p> + Logging format string ends in middle of conversion specifier + + + + Critical + + + + + + + true + true + false + lowercase-l-suffix + Format Rules + + true + Lowercase L Suffix + Used when a lower case "l" is used to mark a long integer. You should use a upper case "L" since the letter "l" looks too much like the digit "1". This message can't be emitted when using Python >= 3.0. + <p>Used when a lower case “l” is used to mark a long integer. You should use a upper case “L” since the letter “l” looks too much like the digit “1”. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of "l" as long integer identifier + + + + Major + + + + + + + true + true + false + logging-not-lazy + Logging Rules + + true + Logging Not Lazy + Used when a logging statement has a call form of "logging.<logging method>(format_string % (format_args...))". Such calls should leave string interpolation to the logging method itself and be written "logging.<logging method>(format_string, format_args...)" so that the program may avoid incurring the cost of the interpolation in those cases in which no message will be logged. For more, see http://www.python.org/dev/peps/pep-0282/. + <p>Used when a logging statement has a call form of “logging.&lt;logging method&gt;(format_string % (format_args…))”. Such calls should leave string interpolation to the logging method itself and be written “logging.&lt;logging method&gt;(format_string, format_args…)” so that the program may avoid incurring the cost of the interpolation in those cases in which no message will be logged. For more, see <a href="http://www.python.org/dev/peps/pep-0282/" class="uri">http://www.python.org/dev/peps/pep-0282/</a>.</p> + Specify string format arguments as logging function parameters + + + + Major + + + + + + + true + true + false + long-suffix + Python3 Rules + + true + Long Suffix + Used when "l" or "L" is used to mark a long integer. This will not work in Python 3, since `int` and `long` types have merged. This message can't be emitted when using Python >= 3.0. + <p>Used when “l” or “L” is used to mark a long integer. This will not work in Python 3, since <code>int</code> and <code>long</code> types have merged. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of long suffix + + + + Critical + + + + + + + true + true + false + logging-too-few-args + Logging Rules + + true + Logging Too Few Args + Used when a logging format string is given too few arguments. + <p>Used when a logging format string is given too many arguments.</p> + Not enough arguments for logging format string + + + + Critical + + + + + + + true + true + false + line-too-long + Format Rules + + true + Line Too Long + Used when a line is longer than a given number of characters. + <p>Used when a line is longer than a given number of characters.</p> + Line too long (%s/%s) + + + + Minor + + + + + + + true + true + false + logging-too-many-args + Logging Rules + + true + Logging Too Many Args + Used when a logging format string is given too many arguments. + <p>Used when a logging format string is given too few arguments.</p> + Too many arguments for logging format string + + + + Critical + + + + + + + true + true + false + logging-unsupported-format + Logging Rules + + true + Logging Unsupported Format + Used when an unsupported format character is used in a logging statement format string. + <p>Used when an unsupported format character is used in a logging statement format string.</p> + Unsupported logging format character %r (%#02x) at index %d + + + + Critical + + + + + + + true + true + false + lost-exception + Basic Rules + + true + Lost Exception + Used when a break or a return statement is found inside the finally clause of a try...finally block: the exceptions raised in the try clause will be silently swallowed instead of being re-raised. + <p>Used when a break or a return statement is found inside the finally clause of a try…finally block: the exceptions raised in the try clause will be silently swallowed instead of being re-raised.</p> + %s statement in finally block may swallow exception + + + + Major + + + + + + + true + true + false + metaclass-assignment + Python3 Rules + + true + Metaclass Assignment + Used when a metaclass is specified by assigning to __metaclass__ (Python 3 specifies the metaclass as a class statement argument). This message can't be emitted when using Python >= 3.0. + <p>Used when a metaclass is specified by assigning to __metaclass__ (Python 3 specifies the metaclass as a class statement argument). This message can’t be emitted when using Python &gt;= 3.0.</p> + Assigning to a class's __metaclass__ attribute + + + + Major + + + + + + + true + true + false + map-builtin-not-iterating + Python3 Rules + + true + Map Builtin Not Iterating + Used when the map built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the map built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + map built-in referenced when not iterating + + + + Major + + + + + + + true + true + false + misplaced-bare-raise + Exception Rules + + true + Misplaced Bare Raise + Used when a bare raise is not used inside an except clause. This generates an error, since there are no active exceptions to be reraised. An exception to this rule is represented by a bare raise inside a finally clause, which might work, as long as an exception is raised inside the try block, but it is nevertheless a code smell that must not be relied upon. + <p>Used when a bare raise is not used inside an except clause. This generates an error, since there are no active exceptions to be reraised. An exception to this rule is represented by a bare raise inside a finally clause, which might work, as long as an exception is raised inside the try block, but it is nevertheless a code smell that must not be relied upon.</p> + The raise statement is not inside an except clause + + + + Critical + + + + + + + true + true + false + misplaced-comparison-constant + Basic Rules + + true + Misplaced Comparison Constant + Used when the constant is placed on the left side of a comparison. It is usually clearer in intent to place it in the right hand side of the comparison. + <p>Used when the constant is placed on the left sideof a comparison. It is usually clearer in intent to place it in the right hand side of the comparison.</p> + Comparison should be %s + + + + Minor + + + + + + + false + true + false + method-check-failed + Class Rules + + true + Method Check Failed + Used when Pylint has been unable to check methods signature compatibility for an unexpected reason. Please report this kind if you don't make sense of it. + Used when Pylint has been unable to check methods signature compatibility for an unexpected reason. Please report this kind if you don't make sense of it. + Unable to check methods signature (%s / %s) + + + + Blocker + + + + + + + true + true + false + missing-docstring + Basic Rules + + true + Missing Docstring + Used when a module, function, class or method has no docstring.Some special methods like __init__ doesn't necessary require a docstring. + <p>Used when a module, function, class or method has no docstring.Some special methods like __init__ doesn’t necessary require a docstring.</p> + Missing %s docstring + + + + Minor + + + + + + + true + true + false + misplaced-future + Import Rules + + true + Misplaced Future + Python 2.5 and greater require __future__ import to be the first non docstring statement in the module. + <p>Python 2.5 and greater require __future__ import to be the first non docstring statement in the module.</p> + __future__ import is not the first non docstring statement + + + + Major + + + + + + + true + true + false + missing-format-attribute + String Rules + + true + Missing Format Attribute + Used when a PEP 3101 format string uses an attribute specifier ({0.length}), but the argument passed for formatting doesn't have that attribute. This message can't be emitted when using Python < 2.7. + <p>Used when a PEP 3101 format string uses an attribute specifier ({0.length}), but the argument passed for formatting doesn’t have that attribute. This message can’t be emitted when using Python &lt; 2.7.</p> + Missing format attribute %r in format specifier %r + + + + Major + + + + + + + true + true + false + missing-format-argument-key + String Rules + + true + Missing Format Argument Key + Used when a PEP 3101 format string that uses named fields doesn't receive one or more required keywords. This message can't be emitted when using Python < 2.7. + <p>Used when a PEP 3101 format string that uses named fields doesn’t receive one or more required keywords. This message can’t be emitted when using Python &lt; 2.7.</p> + Missing keyword argument %r for format string + + + + Major + + + + + + + true + true + false + missing-final-newline + Format Rules + + true + Missing Final Newline + Used when the last line in a file is missing a newline. + <p>Used when the last line in a file is missing a newline.</p> + Final newline missing + + + + Minor + + + + + + + true + true + false + mixed-format-string + String Rules + + true + Mixed Format String + Used when a format string contains both named (e.g. '%(foo)d') and unnamed (e.g. '%d') conversion specifiers. This is also used when a named conversion specifier contains * for the minimum field width and/or precision. + <p>Used when a format string contains both named (e.g. ‘%(foo)d’) and unnamed (e.g. ‘%d’) conversion specifiers. This is also used when a named conversion specifier contains * for the minimum field width and/or precision.</p> + Mixing named and unnamed conversion specifiers in format string + + + + Critical + + + + + + + true + true + false + missing-format-string-key + String Rules + + true + Missing Format String Key + Used when a format string that uses named conversion specifiers is used with a dictionary that doesn't contain all the keys required by the format string. + <p>Used when a format string that uses named conversion specifiers is used with a dictionary that doesn’t contain all the keys required by the format string.</p> + Missing key %r in format string dictionary + + + + Critical + + + + + + + true + true + false + method-hidden + Class Rules + + true + Method Hidden + Used when a class defines a method which is hidden by an instance attribute from an ancestor class or set by some client code. + <p>Used when a class defines a method which is hidden by an instance attribute from an ancestor class or set by some client code.</p> + An attribute defined in %s line %s hides this method + + + + Critical + + + + + + + true + true + false + mixed-indentation + Format Rules + + true + Mixed Indentation + Used when there are some mixed tabs and spaces in a module. + <p>Used when there are some mixed tabs and spaces in a module.</p> + Found indentation with %ss instead of %ss + + + + Major + + + + + + + true + true + false + missing-kwoa + Typecheck Rules + + true + Missing Kwoa + Used when a function call does not pass a mandatory keyword-only argument. This message can't be emitted when using Python < 3.0. + <p>Used when a function call does not pass a mandatory keyword-only argument. This message can’t be emitted when using Python &lt; 3.0.</p> + Missing mandatory keyword argument %r in %s call + + + + Critical + + + + + + + true + true + false + mixed-line-endings + Format Rules + + true + Mixed Line Endings + Used when there are mixed (LF and CRLF) newline signs in a file. + <p>Used when there are mixed (LF and CRLF) newline signs in a file.</p> + Mixed line endings LF and CRLF + + + + Minor + + + + + + + true + true + false + multiple-statements + Format Rules + + true + Multiple Statements + Used when more than on statement are found on the same line. + <p>Used when more than on statement are found on the same line.</p> + More than one statement on a single line + + + + Minor + + + + + + + true + true + false + missing-super-argument + Newstyle Rules + + true + Missing Super Argument + Used when the super builtin didn't receive an argument. This message can't be emitted when using Python >= 3.0. + <p>Used when the super builtin didn’t receive an argument. This message can’t be emitted when using Python &gt;= 3.0.</p> + Missing argument to super() + + + + Critical + + + + + + + true + true + false + multiple-imports + Import Rules + + true + Multiple Imports + Used when import statement importing multiple modules is detected. + <p>Used when import statement importing multiple modules is detected.</p> + Multiple imports on one line (%s) + + + + Minor + + + + + + + true + true + false + non-ascii-bytes-literal + Python3 Rules + + true + Non Ascii Bytes Literal + Used when non-ascii bytes literals are found in a program. They are no longer supported in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when non-ascii bytes literals are found in a program. They are no longer supported in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Non-ascii bytes literals not supported in 3.x + + + + Critical + + + + + + + true + true + false + not-async-context-manager + Async Rules + + true + Not Async Context Manager + Used when an async context manager is used with an object that does not implement the async context management protocol. This message can't be emitted when using Python < 3.5. + <p>Used when an async context manager is used with an object that does not implement the async context management protocol. This message can’t be emitted when using Python &lt; 3.5.</p> + Async context manager '%s' doesn't implement __aenter__ and __aexit__. + + + + Critical + + + + + + + true + true + false + nonlocal-and-global + Basic Rules + + true + Nonlocal And Global + Emitted when a name is both nonlocal and global. This message can't be emitted when using Python < 3.0. + <p>Emitted when a name is both nonlocal and global. This message can’t be emitted when using Python &lt; 3.0.</p> + Name %r is nonlocal and global + + + + Critical + + + + + + + true + true + false + no-absolute-import + Python3 Rules + + true + No Absolute Import + Used when an import is not accompanied by ``from __future__ import absolute_import`` (default behaviour in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when an import is not accompanied by <code>from __future__ import absolute_import</code> (default behaviour in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + import missing `from __future__ import absolute_import` + + + + Major + + + + + + + true + true + false + not-a-mapping + Iterable Check Rules + + true + Not A Mapping + Used when a non-mapping value is used in place where mapping is expected. + <p>Used when a non-mapping value is used in place wheremapping is expected.</p> + Non-mapping value %s is used in a mapping context + + + + Critical + + + + + + + true + true + false + not-callable + Typecheck Rules + + true + Not Callable + Used when an object being called has been inferred to a non callable object. + <p>Used when an object being called has been inferred to a non callable object.</p> + %s is not callable + + + + Critical + + + + + + + true + true + false + no-classmethod-decorator + Class Rules + + true + No Classmethod Decorator + Used when a class method is defined without using the decorator syntax. + <p>Used when a class method is defined without using the decorator syntax.</p> + Consider using a decorator instead of calling classmethod + + + + Minor + + + + + + + true + true + false + not-context-manager + Typecheck Rules + + true + Not Context Manager + Used when an instance in a with statement doesn't implement the context manager protocol(__enter__/__exit__). + <p>Used when an instance in a with statement doesn’t implement the context manager protocol(__enter__/__exit__).</p> + Context manager '%s' doesn't implement __enter__ and __exit__. + + + + Critical + + + + + + + true + true + false + nonstandard-exception + Exception Rules + + true + Nonstandard Exception + Used when a custom exception class is raised but doesn't inherit from the builtin "Exception" class. This message can't be emitted when using Python >= 3.0. + <p>Used when a custom exception class is raised but doesn’t inherit from the builtin “Exception” class. This message can’t be emitted when using Python &gt;= 3.0.</p> + Exception doesn't inherit from standard "Exception" class + + + + Major + + + + + + + true + true + false + no-else-return + Refactoring Rules + + true + No Else Return + Used in order to highlight an unnecessary block of code following an if containing a return statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a return statement. + <p>Used in order to highlight an unnecessary block of code following an if containing a return statement. As such, it will warn when it encounters an else following a chain of ifs, all of them containing a return statement.</p> + Unnecessary "else" after "return" + + + + Minor + + + + + + + true + true + false + no-init + Class Rules + + true + No Init + Used when a class has no __init__ method, neither its parent classes. + <p>Used when a class has no __init__ method, neither its parent classes.</p> + Class has no __init__ method + + + + Major + + + + + + + true + true + false + not-in-loop + Basic Rules + + true + Not In Loop + Used when break or continue keywords are used outside a loop. + <p>Used when break or continue keywords are used outside a loop.</p> + %r not properly in loop + + + + Critical + + + + + + + true + true + false + non-iterator-returned + Class Rules + + true + Non Iterator Returned + Used when an __iter__ method returns something which is not an iterable (i.e. has no `__next__` method). + <p>Used when an __iter__ method returns something which is not an iterable (i.e. has no <code>next</code> method).</p> + __iter__ returns non-iterator + + + + Critical + + + + + + + true + true + false + no-member + Typecheck Rules + + true + No Member + Used when a variable is accessed for an unexistent member. + <p>Used when a variable is accessed for an unexistent member.</p> + %s %r has no %r member%s + + + + Critical + + + + + + + true + true + false + no-method-argument + Class Rules + + true + No Method Argument + Used when a method which should have the bound instance as first argument has no argument defined. + <p>Used when a method which should have the bound instance as first argument has no argument defined.</p> + Method has no argument + + + + Critical + + + + + + + true + true + false + next-method-called + Python3 Rules + + true + Next Method Called + Used when an object's next() method is called (Python 3 uses the next() built-in function). This message can't be emitted when using Python >= 3.0. + <p>Used when an object’s next() method is called (Python 3 uses the next() built-in function). This message can’t be emitted when using Python &gt;= 3.0.</p> + Called a next() method on an object + + + + Major + + + + + + + true + true + false + next-method-defined + Python3 Rules + + true + Next Method Defined + Used when a next method is defined that would be an iterator in Python 2 but is treated as a normal function in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when a next method is defined that would be an iterator in Python 2 but is treated as a normal function in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + next method defined + + + + Major + + + + + + + true + true + false + no-name-in-module + Variable Rules + + true + No Name In Module + Used when a name cannot be found in a module. + <p>Used when a name cannot be found in a module.</p> + No name %r in module %r + + + + Critical + + + + + + + true + true + false + nonexistent-operator + Basic Rules + + true + Nonexistent Operator + Used when you attempt to use the C-style pre-increment orpre-decrement operator -- and ++, which doesn't exist in Python. + <p>Used when you attempt to use the C-style pre-increment orpre-decrement operator -- and ++, which doesn’t exist in Python.</p> + Use of the non-existent %s operator + + + + Critical + + + + + + + true + true + false + non-parent-init-called + Class Rules + + true + Non Parent Init Called + Used when an __init__ method is called on a class which is not in the direct ancestors for the analysed class. + <p>Used when an __init__ method is called on a class which is not in the direct ancestors for the analysed class.</p> + __init__ method from a non direct base class %r is called + + + + Major + + + + + + + true + true + false + notimplemented-raised + Exception Rules + + true + Notimplemented Raised + Used when NotImplemented is raised instead of NotImplementedError. + <p>Used when NotImplemented is raised instead of NotImplementedError.</p> + NotImplemented raised - should raise NotImplementedError + + + + Critical + + + + + + + true + true + false + no-self-argument + Class Rules + + true + No Self Argument + Used when a method has an attribute different the "self" as first argument. This is considered as an error since this is a so common convention that you shouldn't break it! + <p>Used when a method has an attribute different the “self” as first argument. This is considered as an error since this is a so common convention that you shouldn’t break it!</p> + Method should have "self" as first argument + + + + Critical + + + + + + + true + true + false + no-staticmethod-decorator + Class Rules + + true + No Staticmethod Decorator + Used when a static method is defined without using the decorator syntax. + <p>Used when a static method is defined without using the decorator syntax.</p> + Consider using a decorator instead of calling staticmethod + + + + Minor + + + + + + + true + true + false + no-self-use + Class Rules + + true + No Self Use + Used when a method doesn't use its bound instance, and so could be written as a function. + <p>Used when a method doesn’t use its bound instance, and so could be written as a function.</p> + Method could be a function + + + + Minor + + + + + + + true + true + false + no-value-for-parameter + Typecheck Rules + + true + No Value For Parameter + Used when a function call passes too few arguments. + <p>Used when a function call passes too few arguments.</p> + No value for argument %s in %s call + + + + Critical + + + + + + + true + true + false + nonlocal-without-binding + Basic Rules + + true + Nonlocal Without Binding + Emitted when a nonlocal variable does not have an attached name somewhere in the parent scopes. This message can't be emitted when using Python < 3.0. + <p>Emitted when a nonlocal variable does not have an attached name somewhere in the parent scopes. This message can’t be emitted when using Python &lt; 3.0.</p> + nonlocal name %s found without binding + + + + Critical + + + + + + + true + true + false + not-an-iterable + Iterable Check Rules + + true + Not An Iterable + Used when a non-iterable value is used in place where iterable is expected. + <p>Used when a non-iterable value is used in place whereiterable is expected.</p> + Non-iterable value %s is used in an iterating context + + + + Critical + + + + + + + true + true + false + nonzero-method + Python3 Rules + + true + Nonzero Method + Used when a __nonzero__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __nonzero__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __nonzero__ method defined + + + + Major + + + + + + + true + true + false + old-division + Python3 Rules + + true + Old Division + Used for non-floor division w/o a float literal or ``from __future__ import division`` (Python 3 returns a float for int division unconditionally). This message can't be emitted when using Python >= 3.0. + <p>Used for non-floor division w/o a float literal or <code>from __future__ import division</code> (Python 3 returns a float for int division unconditionally). This message can’t be emitted when using Python &gt;= 3.0.</p> + division w/o __future__ statement + + + + Major + + + + + + + true + true + false + oct-method + Python3 Rules + + true + Oct Method + Used when a __oct__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __oct__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __oct__ method defined + + + + Major + + + + + + + true + true + false + old-ne-operator + Python3 Rules + + true + Old Ne Operator + Used when the deprecated "<>" operator is used instead of "!=". This is removed in Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when the deprecated “&lt;&gt;” operator is used instead of “!=”. This is removed in Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of the <> operator + + + + Critical + + + + + + + true + true + false + old-octal-literal + Python3 Rules + + true + Old Octal Literal + Used when encountering the old octal syntax, removed in Python 3. To use the new syntax, prepend 0o on the number. This message can't be emitted when using Python >= 3.0. + <p>Usen when encountering the old octal syntax, removed in Python 3. To use the new syntax, prepend 0o on the number. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of old octal literal + + + + Critical + + + + + + + true + true + false + old-raise-syntax + Python3 Rules + + true + Old Raise Syntax + Used when the alternate raise syntax 'raise foo, bar' is used instead of 'raise foo(bar)'. This message can't be emitted when using Python >= 3.0. + <p>Used when the alternate raise syntax ‘raise foo, bar’ is used instead of ‘raise foo(bar)’. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use raise ErrorClass(args) instead of raise ErrorClass, args. + + + + Critical + + + + + + + true + true + false + old-style-class + Newstyle Rules + + true + Old Style Class + Used when a class is defined that does not inherit from another class and does not inherit explicitly from "object". This message can't be emitted when using Python >= 3.0. + <p>Used when a class is defined that does not inherit from anotherclass and does not inherit explicitly from “object”. This message can’t be emitted when using Python &gt;= 3.0.</p> + Old-style class defined. + + + + Minor + + + + + + + true + true + false + protected-access + Class Rules + + true + Protected Access + Used when a protected member (i.e. class member with a name beginning with an underscore) is access outside the class or a descendant of the class where it's defined. + <p>Used when a protected member (i.e. class member with a name beginning with an underscore) is access outside the class or a descendant of the class where it’s defined.</p> + Access to a protected member %s of a client class + + + + Major + + + + + + + false + true + false + parse-error + Pylint Checker Rules + + true + Parse Error + Used when an exception occurred while building the Astroid representation which could be handled by astroid. + Used when an exception occurred while building the Astroid representation which could be handled by astroid. + error while code parsing: %s + + + + Blocker + + + + + + + true + true + false + property-on-old-class + Newstyle Rules + + true + Property On Old Class + Used when Pylint detect the use of the builtin "property" on an old style class while this is relying on new style classes features. This message can't be emitted when using Python >= 3.0. + <p>Used when Pylint detect the use of the builtin “property” on an old style class while this is relying on new style classes features. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of "property" on an old style class + + + + Major + + + + + + + true + true + false + pointless-statement + Basic Rules + + true + Pointless Statement + Used when a statement doesn't have (or at least seems to) any effect. + <p>Used when a statement doesn’t have (or at least seems to) any effect.</p> + Statement seems to have no effect + + + + Major + + + + + + + true + true + false + pointless-string-statement + Basic Rules + + true + Pointless String Statement + Used when a string is used as a statement (which of course has no effect). This is a particular case of W0104 with its own message so you can easily disable it if you're using those strings as documentation, instead of comments. + <p>Used when a string is used as a statement (which of course has no effect). This is a particular case of W0104 with its own message so you can easily disable it if you’re using those strings as documentation, instead of comments.</p> + String statement has no effect + + + + Major + + + + + + + true + true + false + parameter-unpacking + Python3 Rules + + true + Parameter Unpacking + Used when parameter unpacking is specified for a function(Python 3 doesn't allow it). This message can't be emitted when using Python >= 3.0. + <p>Used when parameter unpacking is specified for a function(Python 3 doesn’t allow it). This message can’t be emitted when using Python &gt;= 3.0.</p> + Parameter unpacking specified + + + + Critical + + + + + + + true + true + false + print-statement + Python3 Rules + + true + Print Statement + Used when a print statement is used (`print` is a function in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a print statement is used (<code>print</code> is a function in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + print statement used + + + + Critical + + + + + + + true + true + false + reimported + Import Rules + + true + Reimported + Used when a module is reimported multiple times. + <p>Used when a module is reimported multiple times.</p> + Reimport %r (imported line %s) + + + + Major + + + + + + + true + true + false + redefined-argument-from-local + Refactoring Rules + + true + Redefined Argument From Local + Used when a local name is redefining an argument, which might suggest a potential error. This is taken in account only for a handful of name binding operations, such as for iteration, with statement assignment and exception handler assignment. + <p>Used when a local name is redefining an argument, which might suggest a potential error. This is taken in account only for a handful of name binding operations, such as for iteration, with statement assignment and exception handler assignment.</p> + Redefining argument with the local name %r + + + + Minor + + + + + + + true + true + false + return-arg-in-generator + Basic Rules + + true + Return Arg In Generator + Used when a "return" statement with an argument is found outside in a generator function or method (e.g. with some "yield" statements). This message can't be emitted when using Python >= 3.3. + <p>Used when a “return” statement with an argument is found outside in a generator function or method (e.g. with some “yield” statements). This message can’t be emitted when using Python &gt;= 3.3.</p> + Return with argument inside generator + + + + Critical + + + + + + + true + true + false + raw_input-builtin + Python3 Rules + + true + Raw_input Builtin + Used when the raw_input built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the raw_input built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + raw_input built-in referenced + + + + Major + + + + + + + true + true + false + range-builtin-not-iterating + Python3 Rules + + true + Range Builtin Not Iterating + Used when the range built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the range built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + range built-in referenced when not iterating + + + + Major + + + + + + + true + true + false + raising-bad-type + Exception Rules + + true + Raising Bad Type + Used when something which is neither a class, an instance or a string is raised (i.e. a `TypeError` will be raised). + <p>Used when something which is neither a class, an instance or a string is raised (i.e. a <code>TypeError</code> will be raised).</p> + Raising %s while only classes or instances are allowed + + + + Critical + + + + + + + true + true + false + relative-beyond-top-level + Import Rules + + true + Relative Beyond Top Level + Used when a relative import tries to access too many levels in the current package. + <p>Used when a relative import tries to access too many levels in the current package.</p> + Attempted relative import beyond top-level package + + + + Critical + + + + + + + false + true + false + raw-checker-failed + Pylint Checker Rules + + true + Raw Checker Failed + Used to inform that a built-in module has not been checked using the raw checkers. + Used to inform that a built-in module has not been checked using the raw checkers. + Unable to run raw checkers on built-in module %s + + + + Minor + + + + + + + true + true + false + raising-format-tuple + Exception Rules + + true + Raising Format Tuple + Used when passing multiple arguments to an exception constructor, the first of them a string literal containing what appears to be placeholders intended for formatting. + <p>Used when passing multiple arguments to an exception constructor, the first of them a string literal containing what appears to be placeholders intended for formatting.</p> + Exception arguments suggest string formatting might be intended + + + + Major + + + + + + + true + true + false + relative-import + Import Rules + + true + Relative Import + Used when an import relative to the package directory is detected. This message can't be emitted when using Python >= 3.0. + <p>Used when an import relative to the package directory is detected. This message can’t be emitted when using Python &gt;= 3.0.</p> + Relative import %r, should be %r + + + + Major + + + + + + + true + true + false + redefine-in-handler + Variable Rules + + true + Redefine In Handler + Used when an exception handler assigns the exception to an existing name. + <p>Used when an exception handler assigns the exception to an existing name.</p> + Redefining name %r from %s in exception handler + + + + Major + + + + + + + true + true + false + return-in-init + Basic Rules + + true + Return In Init + Used when the special class method __init__ has an explicit return value. + <p>Used when the special class method __init__ has an explicit return value.</p> + Explicit return in __init__ + + + + Critical + + + + + + + true + true + false + repeated-keyword + Typecheck Rules + + true + Repeated Keyword + Emitted when a function call got multiple values for a keyword. + <p>Emitted when a function call got multiple values for a keyword.</p> + Got multiple values for keyword argument %r in function call + + + + Critical + + + + + + + true + true + false + redundant-keyword-arg + Typecheck Rules + + true + Redundant Keyword Arg + Used when a function call would result in assigning multiple values to a function parameter, one value from a positional argument and one from a keyword argument. + <p>Used when a function call would result in assigning multiple values to a function parameter, one value from a positional argument and one from a keyword argument.</p> + Argument %r passed by position and keyword in %s call + + + + Critical + + + + + + + true + true + false + rdiv-method + Python3 Rules + + true + Rdiv Method + Used when a __rdiv__ method is defined. Using `__rtruediv__` and setting__rdiv__ = __rtruediv__ should be preferred.(method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __rdiv__ method is defined. Using <code>__rtruediv__</code> and setting__rdiv__ = __rtruediv__ should be preferred.(method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __rdiv__ method defined + + + + Major + + + + + + + true + true + false + raising-non-exception + Exception Rules + + true + Raising Non Exception + Used when a new style class which doesn't inherit from BaseException is raised. + <p>Used when a new style class which doesn’t inherit from BaseException is raised.</p> + Raising a new style class which doesn't inherit from BaseException + + + + Critical + + + + + + + true + true + false + return-outside-function + Basic Rules + + true + Return Outside Function + Used when a "return" statement is found outside a function or method. + <p>Used when a “return” statement is found outside a function or method.</p> + Return outside function + + + + Critical + + + + + + + true + true + false + redefined-outer-name + Variable Rules + + true + Redefined Outer Name + Used when a variable's name hides a name defined in the outer scope. + <p>Used when a variable’s name hide a name defined in the outer scope.</p> + Redefining name %r from outer scope (line %s) + + + + Major + + + + + + + true + true + false + raising-string + Python3 Rules + + true + Raising String + Used when a string exception is raised. This will not work on Python 3. This message can't be emitted when using Python >= 3.0. + <p>Used when a string exception is raised. This will not work on Python 3. This message can’t be emitted when using Python &gt;= 3.0.</p> + Raising a string exception + + + + Major + + + + + + + true + true + false + redundant-unittest-assert + Stdlib Rules + + true + Redundant Unittest Assert + The first argument of assertTrue and assertFalse is a condition. If a constant is passed as parameter, that condition will be always true. In this case a warning should be emitted. + <p>The first argument of assertTrue and assertFalse is a condition. If a constant is passed as parameter, that condition will be always true. In this case a warning should be emitted.</p> + Redundant use of %s with constant value %r + + + + Major + + + + + + + true + true + false + redefined-builtin + Variable Rules + + true + Redefined Builtin + Used when a variable or function override a built-in. + <p>Used when a variable or function override a built-in.</p> + Redefining built-in %r + + + + Major + + + + + + + true + true + false + reduce-builtin + Python3 Rules + + true + Reduce Builtin + Used when the reduce built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the reduce built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + reduce built-in referenced + + + + Major + + + + + + + true + true + false + reload-builtin + Python3 Rules + + true + Reload Builtin + Used when the reload built-in function is referenced (missing from Python 3). You can use instead imp.reload or importlib.reload. This message can't be emitted when using Python >= 3.0. + <p>Used when the reload built-in function is referenced (missing from Python 3). You can use instead imp.reload or importlib.reload. This message can’t be emitted when using Python &gt;= 3.0.</p> + reload built-in referenced + + + + Major + + + + + + + true + true + false + round-builtin + Python3 Rules + + true + Round Builtin + Used when the round built-in is referenced (backwards-incompatible semantics in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the round built-in is referenced (backwards-incompatible semantics in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + round built-in referenced + + + + Major + + + + + + + true + true + false + standarderror-builtin + Python3 Rules + + true + Standarderror Builtin + Used when the StandardError built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the StandardError built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + StandardError built-in referenced + + + + Major + + + + + + + true + true + false + simplify-boolean-expression + Refactoring Rules + + true + Simplify Boolean Expression + Emitted when redundant pre-python 2.5 ternary syntax is used. + <p>Emitted when redundant pre-python 2.5 ternary syntax is used.</p> + Boolean expression may be simplified to %s + + + + Minor + + + + + + + true + true + false + singleton-comparison + Basic Rules + + true + Singleton Comparison + Used when an expression is compared to singleton values like True, False or None. + <p>Used when an expression is compared to singleton values like True, False or None.</p> + Comparison to %s should be %s + + + + Minor + + + + + + + true + true + false + shallow-copy-environ + Stdlib Rules + + true + Shallow Copy Environ + os.environ is not a dict object but proxy object, so shallow copy has still effects on original object. See https://bugs.python.org/issue15373 for reference. + <p>os.environ is not a dict object but proxy object, so shallow copy has still effects on original object. See <a href="https://bugs.python.org/issue15373" class="uri">https://bugs.python.org/issue15373</a> for reference.</p> + Using copy.copy(os.environ). Use os.environ.copy() instead. + + + + Major + + + + + + + true + true + false + signature-differs + Class Rules + + true + Signature Differs + Used when a method signature is different than in the implemented interface or in an overridden method. + <p>Used when a method signature is different than in the implemented interface or in an overridden method.</p> + Signature differs from %s %r method + + + + Major + + + + + + + false + true + false + syntax-error + Pylint Checker Rules + + true + Syntax Error + Used when a syntax error is raised for a module. + Used when a syntax error is raised for a module. + + + + + Critical + + + + + + + true + true + false + super-init-not-called + Class Rules + + true + Super Init Not Called + Used when an ancestor class method has an __init__ method which is not called by a derived class. + <p>Used when an ancestor class method has an __init__ method which is not called by a derived class.</p> + __init__ method from base class %r is not called + + + + Major + + + + + + + true + true + false + stop-iteration-return + Refactoring Rules + + true + Stop Iteration Return + According to PEP479, the raise of StopIteration to end the loop of a generator may lead to hard to find bugs. This PEP specify that raise StopIteration has to be replaced by a simple return statement. This message can't be emitted when using Python < 3.0. + <p>According to PEP479, the raise of StopIteration to end the loop of a generator may lead to hard to find bugs. This PEP specify that raise StopIteration has to be replaced by a simple return statement. This message can’t be emitted when using Python &lt; 3.0.</p> + Do not raise StopIteration in generator, use return statement instead + + + + Minor + + + + + + + true + true + false + simplifiable-if-statement + Refactoring Rules + + true + Simplifiable If Statement + Used when an if statement can be replaced with 'bool(test)'. + <p>Used when an if statement can be replaced with ‘bool(test)’.</p> + The if statement can be replaced with %s + + + + Minor + + + + + + + true + true + false + setslice-method + Python3 Rules + + true + Setslice Method + Used when a __setslice__ method is defined (method is not used by Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when a __setslice__ method is defined (method is not used by Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + __setslice__ method defined + + + + Major + + + + + + + true + true + false + sys-max-int + Python3 Rules + + true + Sys Max Int + Used when accessing sys.maxint. Use sys.maxsize instead. This message can't be emitted when using Python >= 3.0. + <p>Used when accessing sys.maxint. Use sys.maxsize instead. This message can’t be emitted when using Python &gt;= 3.0.</p> + sys.maxint removed in Python 3 + + + + Major + + + + + + + true + true + false + star-needs-assignment-target + Basic Rules + + true + Star Needs Assignment Target + Emitted when a star expression is not used in an assignment target. This message can't be emitted when using Python < 3.0. + <p>Emitted when a star expression is not used in an assignment target. This message can’t be emitted when using Python &lt; 3.0.</p> + Can use starred expression only in assignment target + + + + Critical + + + + + + + true + true + false + slots-on-old-class + Newstyle Rules + + true + Slots On Old Class + Used when an old style class uses the __slots__ attribute. This message can't be emitted when using Python >= 3.0. + <p>Used when an old style class uses the __slots__ attribute. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of __slots__ on an old style class + + + + Critical + + + + + + + true + true + false + superfluous-parens + Format Rules + + true + Superfluous Parens + Used when a single item in parentheses follows an if, for, or other keyword. + <p>Used when a single item in parentheses follows an if, for, or other keyword.</p> + Unnecessary parens after %r keyword + + + + Minor + + + + + + + true + true + false + single-string-used-for-slots + Class Rules + + true + Single String Used For Slots + Used when a class __slots__ is a simple string, rather than an iterable. + <p>Used when a class __slots__ is a simple string, rather than an iterable.</p> + Class __slots__ should be a non-string iterable + + + + Minor + + + + + + + false + true + false + suppressed-message + Pylint Checker Rules + + true + Suppressed Message + A message was triggered on a line, but suppressed explicitly by a disable= comment in the file. This message is not generated for messages that are ignored due to configuration settings. + A message was triggered on a line, but suppressed explicitly by a disable= comment in the file. This message is not generated for messages that are ignored due to configuration settings. + Suppressed %s (from line %d) + + + + Minor + + + + + + + true + true + false + super-on-old-class + Newstyle Rules + + true + Super On Old Class + Used when an old style class uses the super builtin. This message can't be emitted when using Python >= 3.0. + <p>Used when an old style class uses the super builtin. This message can’t be emitted when using Python &gt;= 3.0.</p> + Use of super on an old style class + + + + Critical + + + + + + + true + true + false + trailing-comma-tuple + Refactoring Rules + + true + Trailing Comma Tuple + In Python, a tuple is actually created by the comma symbol, not by the parentheses. Unfortunately, one can actually create a tuple by misplacing a trailing comma, which can lead to potential weird bugs in your code. You should always use parentheses explicitly for creating a tuple. This message can't be emitted when using Python < 3.0. + <p>In Python, a tuple is actually created by the comma symbol, not by the parentheses. Unfortunately, one can actually create a tuple by misplacing a trailing comma, which can lead to potential weird bugs in your code. You should always use parentheses explicitly for creating a tuple. This message can’t be emitted when using Python &lt; 3.0.</p> + Disallow trailing comma tuple + + + + Minor + + + + + + + true + true + false + too-few-format-args + String Rules + + true + Too Few Format Args + Used when a format string that uses unnamed conversion specifiers is given too few arguments. + <p>Used when a format string that uses unnamed conversion specifiers is given too few arguments.</p> + Not enough arguments for format string + + + + Critical + + + + + + + true + true + false + too-few-public-methods + Design Rules + + true + Too Few Public Methods + Used when class has too few public methods, so be sure it's really worth it. + <p>Used when class has too few public methods, so be sure it’s really worth it.</p> + Too few public methods (%s/%s) + + + + Minor + + + + + + + true + true + false + truncated-format-string + String Rules + + true + Truncated Format String + Used when a format string terminates before the end of a conversion specifier. + <p>Used when a format string terminates before the end of a conversion specifier.</p> + Format string ends in middle of conversion specifier + + + + Critical + + + + + + + true + true + false + too-many-ancestors + Design Rules + + true + Too Many Ancestors + Used when class has too many parent classes, try to reduce this to get a simpler (and so easier to use) class. + <p>Used when class has too many parent classes, try to reduce this to get a simpler (and so easier to use) class.</p> + Too many ancestors (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-branches + Design Rules + + true + Too Many Branches + Used when a function or method has too many branches, making it hard to follow. + <p>Used when a function or method has too many branches, making it hard to follow.</p> + Too many branches (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-boolean-expressions + Design Rules + + true + Too Many Boolean Expressions + Used when a if statement contains too many boolean expressions. + <p>Used when a if statement contains too many boolean expressions.</p> + Too many boolean expressions in if statement (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-format-args + String Rules + + true + Too Many Format Args + Used when a format string that uses unnamed conversion specifiers is given too many arguments. + <p>Used when a format string that uses unnamed conversion specifiers is given too many arguments.</p> + Too many arguments for format string + + + + Critical + + + + + + + true + true + false + too-many-instance-attributes + Design Rules + + true + Too Many Instance Attributes + Used when class has too many instance attributes, try to reduce this to get a simpler (and so easier to use) class. + <p>Used when class has too many instance attributes, try to reduce this to get a simpler (and so easier to use) class.</p> + Too many instance attributes (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-lines + Format Rules + + true + Too Many Lines + Used when a module has too much lines, reducing its readability. + <p>Used when a module has too much lines, reducing its readability.</p> + Too many lines in module (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-nested-blocks + Refactoring Rules + + true + Too Many Nested Blocks + Used when a function or a method has too many nested blocks. This makes the code less understandable and maintainable. + <p>Used when a function or a method has too many nested blocks. This makes the code less understandable and maintainable.</p> + Too many nested blocks (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-public-methods + Design Rules + + true + Too Many Public Methods + Used when class has too many public methods, try to reduce this to get a simpler (and so easier to use) class. + <p>Used when class has too many public methods, try to reduce this to get a simpler (and so easier to use) class.</p> + Too many public methods (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-return-statements + Design Rules + + true + Too Many Return Statements + Used when a function or method has too many return statement, making it hard to follow. + <p>Used when a function or method has too many return statement, making it hard to follow.</p> + Too many return statements (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-statements + Design Rules + + true + Too Many Statements + Used when a function or method has too many statements. You should then split it in smaller functions / methods. + <p>Used when a function or method has too many statements. You should then split it in smaller functions / methods.</p> + Too many statements (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-star-expressions + Basic Rules + + true + Too Many Star Expressions + Emitted when there are more than one starred expressions (`*x`) in an assignment. This is a SyntaxError. This message can't be emitted when using Python < 3.0. + <p>Emitted when there are more than one starred expressions (<code>*x</code>) in an assignment. This is a SyntaxError. This message can’t be emitted when using Python &lt; 3.0.</p> + More than one starred expression in assignment + + + + Critical + + + + + + + true + true + false + trailing-newlines + Format Rules + + true + Trailing Newlines + Used when there are trailing blank lines in a file. + <p>Used when there are trailing blank lines in a file.</p> + Trailing newlines + + + + Minor + + + + + + + true + true + false + trailing-whitespace + Format Rules + + true + Trailing Whitespace + Used when there is whitespace between the end of a line and the newline. + <p>Used when there is whitespace between the end of a line and the newline.</p> + Trailing whitespace + + + + Minor + + + + + + + true + true + false + too-many-arguments + Design Rules + + true + Too Many Arguments + Used when a function or method takes too many arguments. + <p>Used when a function or method takes too many arguments.</p> + Too many arguments (%s/%s) + + + + Minor + + + + + + + true + true + false + too-many-function-args + Typecheck Rules + + true + Too Many Function Args + Used when a function call passes too many positional arguments. + <p>Used when a function call passes too many positional arguments.</p> + Too many positional arguments for %s call + + + + Critical + + + + + + + true + true + false + too-many-locals + Design Rules + + true + Too Many Locals + Used when a function or method has too many local variables. + <p>Used when a function or method has too many local variables.</p> + Too many local variables (%s/%s) + + + + Minor + + + + + + + true + true + false + unreachable + Basic Rules + + true + Unreachable + Used when there is some code behind a "return" or "raise" statement, which will never be accessed. + <p>Used when there is some code behind a “return” or “raise” statement, which will never be accessed.</p> + Unreachable code + + + + Major + + + + + + + true + true + false + unused-argument + Variable Rules + + true + Unused Argument + Used when a function or method argument is not used. + <p>Used when a function or method argument is not used.</p> + Unused argument %r + + + + Major + + + + + + + true + true + false + unsupported-assignment-operation + Typecheck Rules + + true + Unsupported Assignment Operation + Emitted when an object does not support item assignment (i.e. doesn't define __setitem__ method). + <p>Emitted when an object does not support item assignment (i.e. doesn’t define __setitem__ method).</p> + %r does not support item assignment + + + + Critical + + + + + + + true + true + false + undefined-all-variable + Variable Rules + + true + Undefined All Variable + Used when an undefined variable name is referenced in __all__. + <p>Used when an undefined variable name is referenced in __all__.</p> + Undefined variable name %r in __all__ + + + + Critical + + + + + + + true + true + false + unicode-builtin + Python3 Rules + + true + Unicode Builtin + Used when the unicode built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the unicode built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + unicode built-in referenced + + + + Major + + + + + + + true + true + false + used-before-assignment + Variable Rules + + true + Used Before Assignment + Used when a local variable is accessed before it's assignment. + <p>Used when a local variable is accessed before it’s assignment.</p> + Using variable %r before assignment + + + + Critical + + + + + + + true + true + false + unsupported-binary-operation + Typecheck Rules + + true + Unsupported Binary Operation + Emitted when a binary arithmetic operation between two operands is not supported. + <p>Emitted when a binary arithmetic operation between two operands is not supported.</p> + + + + + Critical + + + + + + + true + true + false + using-cmp-argument + Python3 Rules + + true + Using Cmp Argument + Using the cmp argument for list.sort or the sorted builtin should be avoided, since it was removed in Python 3. Using either `key` or `functools.cmp_to_key` should be preferred. This message can't be emitted when using Python >= 3.0. + <p>Using the cmp argument for list.sort or the sorted builtin should be avoided, since it was removed in Python 3. Using either <code>key</code> or <code>functools.cmp_to_key</code> should be preferred. This message can’t be emitted when using Python &gt;= 3.0.</p> + Using the cmp argument for list.sort / sorted + + + + Major + + + + + + + true + true + false + using-constant-test + Basic Rules + + true + Using Constant Test + Emitted when a conditional statement (If or ternary if) uses a constant value for its test. This might not be what the user intended to do. + <p>Emitted when a conditional statement (If or ternary if) uses a constant value for its test. This might not be what the user intended to do.</p> + Using a conditional statement with a constant value + + + + Major + + + + + + + true + true + false + unsupported-delete-operation + Typecheck Rules + + true + Unsupported Delete Operation + Emitted when an object does not support item deletion (i.e. doesn't define __delitem__ method). + <p>Emitted when an object does not support item deletion (i.e. doesn’t define __delitem__ method).</p> + %r does not support item deletion + + + + Critical + + + + + + + true + true + false + useless-else-on-loop + Basic Rules + + true + Useless Else On Loop + Loops should only have an else clause if they can exit early with a break statement, otherwise the statements under else should be on the same scope as the loop itself. + <p>Loops should only have an else clause if they can exit early with a break statement, otherwise the statements under else should be on the same scope as the loop itself.</p> + Else clause on loop without a break statement + + + + Major + + + + + + + true + true + false + unused-format-string-argument + String Rules + + true + Unused Format String Argument + Used when a PEP 3101 format string that uses named fields is used with an argument that is not required by the format string. This message can't be emitted when using Python < 2.7. + <p>Used when a PEP 3101 format string that uses named fields is used with an argument that is not required by the format string. This message can’t be emitted when using Python &lt; 2.7.</p> + Unused format argument %r + + + + Major + + + + + + + true + true + false + unused-format-string-key + String Rules + + true + Unused Format String Key + Used when a format string that uses named conversion specifiers is used with a dictionary that contains keys not required by the format string. + <p>Used when a format string that uses named conversion specifiers is used with a dictionary that contains keys not required by the format string.</p> + Unused key %r in format string dictionary + + + + Major + + + + + + + true + true + false + unpacking-in-except + Python3 Rules + + true + Unpacking In Except + Python3 will not allow implicit unpacking of exceptions in except clauses. See http://www.python.org/dev/peps/pep-3110/. This message can't be emitted when using Python >= 3.0. + <p>Python3 will not allow implicit unpacking of exceptions in except clauses. See <a href="http://www.python.org/dev/peps/pep-3110/" class="uri">http://www.python.org/dev/peps/pep-3110/</a>. This message can’t be emitted when using Python &gt;= 3.0.</p> + Implicit unpacking of exceptions is not supported in Python 3 + + + + Critical + + + + + + + false + true + false + unrecognized-inline-option + Pylint Checker Rules + + true + Unrecognized Inline Option + Used when an unknown inline option is encountered. + Used when an unknown inline option is encountered. + Unrecognized file option %r + + + + Critical + + + + + + + true + true + false + unexpected-keyword-arg + Typecheck Rules + + true + Unexpected Keyword Arg + Used when a function call passes a keyword argument that doesn't correspond to one of the function's parameter names. + <p>Used when a function call passes a keyword argument that doesn’t correspond to one of the function’s parameter names.</p> + Unexpected keyword argument %r in %s call + + + + Critical + + + + + + + true + true + false + unnecessary-lambda + Basic Rules + + true + Unnecessary Lambda + Used when the body of a lambda expression is a function call on the same argument list as the lambda itself; such lambda expressions are in all but a few cases replaceable with the function being called in the body of the lambda. + <p>Used when the body of a lambda expression is a function call on the same argument list as the lambda itself; such lambda expressions are in all but a few cases replaceable with the function being called in the body of the lambda.</p> + Lambda may not be necessary + + + + Major + + + + + + + true + true + false + unexpected-line-ending-format + Format Rules + + true + Unexpected Line Ending Format + Used when there is different newline than expected. + <p>Used when there is different newline than expected.</p> + Unexpected line ending format. There is '%s' while it should be '%s'. + + + + Minor + + + + + + + true + true + false + undefined-loop-variable + Variable Rules + + true + Undefined Loop Variable + Used when an loop variable (i.e. defined by a for loop or a list comprehension or a generator expression) is used outside the loop. + <p>Used when an loop variable (i.e. defined by a for loop or a list comprehension or a generator expression) is used outside the loop.</p> + Using possibly undefined loop variable %r + + + + Major + + + + + + + true + true + false + unsupported-membership-test + Typecheck Rules + + true + Unsupported Membership Test + Emitted when an instance in membership test expression doesn't implement membership protocol (__contains__/__iter__/__getitem__). + <p>Emitted when an instance in membership test expression doesn’timplement membership protocol (__contains__/__iter__/__getitem__).</p> + Value '%s' doesn't support membership test + + + + Critical + + + + + + + true + true + false + unneeded-not + Basic Rules + + true + Unneeded Not + Used when a boolean expression contains an unneeded negation. + <p>Used when a boolean expression contains an unneeded negation.</p> + Consider changing "%s" to "%s" + + + + Minor + + + + + + + true + true + false + unpacking-non-sequence + Variable Rules + + true + Unpacking Non Sequence + Used when something which is not a sequence is used in an unpack assignment. + <p>Used when something which is not a sequence is used in an unpack assignment.</p> + Attempting to unpack a non-sequence%s + + + + Critical + + + + + + + true + true + false + unsubscriptable-object + Typecheck Rules + + true + Unsubscriptable Object + Emitted when a subscripted value doesn't support subscription(i.e. doesn't define __getitem__ method). + <p>Emitted when a subscripted value doesn’t support subscription(i.e. doesn’t define __getitem__ method).</p> + Value '%s' is unsubscriptable + + + + Critical + + + + + + + true + true + false + unnecessary-pass + Basic Rules + + true + Unnecessary Pass + Used when a "pass" statement that can be avoided is encountered. + <p>Used when a “pass” statement that can be avoided is encountered.</p> + Unnecessary pass statement + + + + Major + + + + + + + true + true + false + used-prior-global-declaration + Basic Rules + + true + Used Prior Global Declaration + Emitted when a name is used prior a global declaration, which results in an error since Python 3.6. This message can't be emitted when using Python < 3.6. + <p>Emitted when a name is used prior a global declaration, which results in an error since Python 3.6. This message can’t be emitted when using Python &lt; 3.6.</p> + Name %r is used prior to global declaration + + + + Critical + + + + + + + true + true + false + unnecessary-semicolon + Format Rules + + true + Unnecessary Semicolon + Used when a statement is ended by a semi-colon (";"), which isn't necessary (that's python, not C ;). + <p>Used when a statement is ended by a semi-colon (“;”), which isn’t necessary (that’s python, not C ;).</p> + Unnecessary semicolon + + + + Major + + + + + + + true + true + false + useless-super-delegation + Class Rules + + true + Useless Super Delegation + Used whenever we can detect that an overridden method is useless, relying on super() delegation to do the same thing as another method from the MRO. + <p>Used whenever we can detect that an overridden method is useless, relying on super() delegation to do the same thing as another method from the MRO.</p> + Useless super delegation in method %r + + + + Major + + + + + + + true + true + false + unexpected-special-method-signature + Class Rules + + true + Unexpected Special Method Signature + Emitted when a special method was defined with an invalid number of parameters. If it has too few or too many, it might not work at all. + <p>Emitted when a special method was defined with an invalid number of parameters. If it has too few or too many, it might not work at all.</p> + The special method %r expects %s param(s), %d %s given + + + + Critical + + + + + + + true + true + false + unidiomatic-typecheck + Basic Rules + + true + Unidiomatic Typecheck + The idiomatic way to perform an explicit typecheck in Python is to use isinstance(x, Y) rather than type(x) == Y, type(x) is Y. Though there are unusual situations where these give different results. + <p>The idiomatic way to perform an explicit typecheck in Python is to use isinstance(x, Y) rather than type(x) == Y, type(x) is Y. Though there are unusual situations where these give different results.</p> + Using type() instead of isinstance() for a typecheck. + + + + Minor + + + + + + + true + true + false + unbalanced-tuple-unpacking + Variable Rules + + true + Unbalanced Tuple Unpacking + Used when there is an unbalanced tuple unpacking in assignment. + <p>Used when there is an unbalanced tuple unpacking in assignment.</p> + Possible unbalanced tuple unpacking with sequence%s: left side has %d label(s), right side has %d value(s) + + + + Critical + + + + + + + true + true + false + undefined-variable + Variable Rules + + true + Undefined Variable + Used when an undefined variable is accessed. + <p>Used when an undefined variable is accessed.</p> + Undefined variable %r + + + + Critical + + + + + + + true + true + false + unused-wildcard-import + Variable Rules + + true + Unused Wildcard Import + Used when an imported module or variable is not used from a `'from X import *'` style import. + <p>Used when an imported module or variable is not used from a <code>'from X import *'</code> style import.</p> + Unused import %s from wildcard import + + + + Major + + + + + + + true + true + false + unichr-builtin + Python3 Rules + + true + Unichr Builtin + Used when the unichr built-in is referenced (Use chr in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the unichr built-in is referenced (Use chr in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + unichr built-in referenced + + + + Major + + + + + + + true + true + false + unused-import + Variable Rules + + true + Unused Import + Used when an imported module or variable is not used. + <p>Used when an imported module or variable is not used.</p> + Unused %s + + + + Major + + + + + + + true + true + false + unused-variable + Variable Rules + + true + Unused Variable + Used when a variable is defined but not used. + <p>Used when a variable is defined but not used.</p> + Unused variable %r + + + + Major + + + + + + + true + true + false + ungrouped-imports + Import Rules + + true + Ungrouped Imports + Used when imports are not grouped by packages. + <p>Used when imports are not grouped by packages.</p> + Imports from package %s are not grouped + + + + Minor + + + + + + + false + true + false + useless-suppression + Pylint Checker Rules + + true + Useless Suppression + Reported when a message is explicitly disabled for a line or a block of code, but never triggered. + Reported when a message is explicitly disabled for a line or a block of code, but never triggered. + Useless suppression of %s + + + + Minor + + + + + + + true + true + false + wildcard-import + Import Rules + + true + Wildcard Import + Used when `from module import *` is detected. + <p>Used when <code>from module import *</code> is detected.</p> + Wildcard import %s + + + + Major + + + + + + + true + true + false + wrong-import-order + Import Rules + + true + Wrong Import Order + Used when PEP8 import order is not respected (standard imports first, then third-party libraries, then local imports). + <p>Used when PEP8 import order is not respected (standard imports first, then third-party libraries, then local imports).</p> + %s should be placed before %s + + + + Minor + + + + + + + true + true + false + wrong-import-position + Import Rules + + true + Wrong Import Position + Used when code and imports are mixed. + <p>Used when code and imports are mixed.</p> + Import "%s" should be placed at the top of the module + + + + Minor + + + + + + + true + true + false + wrong-spelling-in-comment + Spelling Rules + + true + Wrong Spelling In Comment + Used when a word in comment is not spelled correctly. + <p>Used when a word in comment is not spelled correctly.</p> + Wrong spelling of a word '%s' in a comment: + + + + Minor + + + + + + + true + true + false + wrong-spelling-in-docstring + Spelling Rules + + true + Wrong Spelling In Docstring + Used when a word in docstring is not spelled correctly. + <p>Used when a word in docstring is not spelled correctly.</p> + Wrong spelling of a word '%s' in a docstring: + + + + Minor + + + + + + + true + true + false + xrange-builtin + Python3 Rules + + true + Xrange Builtin + Used when the xrange built-in function is referenced (missing from Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the xrange built-in function is referenced (missing from Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + xrange built-in referenced + + + + Major + + + + + + + true + true + false + yield-inside-async-function + Async Rules + + true + Yield Inside Async Function + Used when an `yield` or `yield from` statement is found inside an async function. This message can't be emitted when using Python < 3.5. + <p>Used when an <code>yield</code> or <code>yield from</code> statement is found inside an async function. This message can’t be emitted when using Python &lt; 3.5.</p> + Yield inside async function + + + + Critical + + + + + + + true + true + false + yield-outside-function + Basic Rules + + true + Yield Outside Function + Used when a "yield" statement is found outside a function or method. + <p>Used when a “yield” statement is found outside a function or method.</p> + Yield outside function + + + + Critical + + + + + + + true + true + false + zip-builtin-not-iterating + Python3 Rules + + true + Zip Builtin Not Iterating + Used when the zip built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can't be emitted when using Python >= 3.0. + <p>Used when the zip built-in is referenced in a non-iterating context (returns an iterator in Python 3). This message can’t be emitted when using Python &gt;= 3.0.</p> + zip built-in referenced when not iterating + + + + Major + + + + + + + false + true + summarized + master + + true + Pylint Checker Rules + Pylint Checker Rules + Pylint Checker Rules + + + + Minor + + + + + + + true + true + summarized + python3 + + true + Python3 Rules + Python3 Rules + Python3 Rules + + + + Minor + + + + + + + true + true + summarized + refactoring + + true + Refactoring Rules + Refactoring Rules + Refactoring Rules + + + + Minor + + + + + + + false + true + summarized + similarities + + true + Similarity Rules + Similarity Rules + Similarity Rules + + + + Minor + + + + + + + true + true + summarized + spelling + + true + Spelling Rules + Spelling Rules + Spelling Rules + + + + Minor + + + + + + + true + true + summarized + stdlib + + true + Stdlib Rules + Stdlib Rules + Stdlib Rules + + + + Minor + + + + + + + true + true + summarized + string_constant + + true + String Constant Rules + String Constant Rules + String Constant Rules + + + + Minor + + + + + + + true + true + summarized + string + + true + String Rules + String Rules + String Rules + + + + Minor + + + + + + + true + true + summarized + typecheck + + true + Typecheck Rules + Typecheck Rules + Typecheck Rules + + + + Minor + + + + + + + true + true + summarized + variables + + true + Variable Rules + Variable Rules + Variable Rules + + + + Minor + + + + + diff --git a/cl/Pylint2Graph/inc/Pylint2Graph.h b/cl/Pylint2Graph/inc/Pylint2Graph.h new file mode 100644 index 0000000..11e301f --- /dev/null +++ b/cl/Pylint2Graph/inc/Pylint2Graph.h @@ -0,0 +1,55 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYLINT2GRAPH_H_ +#define _PYLINT2GRAPH_H_ + +#include + +#include +#include +#include +#include +#include + +class Pylint2Graph { + public: + Pylint2Graph(const std::string& rulFile, const std::string& rulConfig, std::ostream& out, const std::string& changePathFrom = "", const std::string& changePathTo = ""); + virtual ~Pylint2Graph(); + + void buildGraph(const std::string& limFileName); + void convertResults(const std::string& pylintResultsFile); + void saveResultGraph(const std::string& outGraphFile, bool exportRul); + + protected: + void addWarningToNode(const std::string& path, int line, int col, int endline, int endcol, const std::string& warningID, const std::string& warningText); + + protected: + std::ostream& out; + std::string changePathFrom; + std::string changePathTo; + columbus::RefDistributorStrTable strTable; + columbus::lim::asg::Factory limFact; + columbus::rul::RulHandler* rulHandler; + columbus::graph::Graph graph; + columbus::graphsupport::GraphRangeIndexer& graphIndexer; +}; + +#endif diff --git a/cl/Pylint2Graph/inc/PylintRulMaker.h b/cl/Pylint2Graph/inc/PylintRulMaker.h new file mode 100644 index 0000000..ea79d00 --- /dev/null +++ b/cl/Pylint2Graph/inc/PylintRulMaker.h @@ -0,0 +1,34 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYLINTRULMAKER_H_ +#define _PYLINTRULMAKER_H_ + +#include + +class PylintRulMaker { + public: + PylintRulMaker(); + virtual ~PylintRulMaker(); + + void makeRul(const std::string& messagesFileName, const std::string& idsFileName, const std::string& rulFile); +}; + +#endif diff --git a/cl/Pylint2Graph/inc/PylintRunner.h b/cl/Pylint2Graph/inc/PylintRunner.h new file mode 100644 index 0000000..f4880d3 --- /dev/null +++ b/cl/Pylint2Graph/inc/PylintRunner.h @@ -0,0 +1,35 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYLINTRUNNER_H_ +#define _PYLINTRUNNER_H_ + +#include +#include + +class PylintRunner { + public: + PylintRunner(); + virtual ~PylintRunner(); + + void run(const std::string& projectBaseDir, const std::string& pythonBinary, const std::string& pylintDir, const std::string& pylintrc, const std::string& outputFile, const std::list& pylintOptions); +}; + +#endif diff --git a/cl/Pylint2Graph/inc/messages.h b/cl/Pylint2Graph/inc/messages.h new file mode 100644 index 0000000..ac09d24 --- /dev/null +++ b/cl/Pylint2Graph/inc/messages.h @@ -0,0 +1,49 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYLINT2GRAPH_MESSAGES_H_ +#define _PYLINT2GRAPH_MESSAGES_H_ + +#define CMSG_WRONG_INPUT WriteMsg::mlError, "Error: Exactly 1 input text file is required, which contains the pylint rule violations.\n" +#define CMSG_RUNPYLINT_OPTION_ERROR WriteMsg::mlError, "Error: When using -runpylint, the -pythonBinary, -pylintdir, -pylintrc, -projectbasedir and -pylintout options also must be specified\n" +#define CMSG_CANNOT_OPEN_FILE WriteMsg::mlError, "Error: Cannot open file: %s\n" +#define CMSG_PYTHON_BIN_ERROR WriteMsg::mlError, "Error: Python 2.7/3.x binary is not specified correctly.\n" + +// PylintRunner.cpp +#define CMSG_ERROR_ENVSET_FAILURE WriteMsg::mlError, "Error: Failed to set '%s' environment variable!\n" +#define CMSG_PYLINT_NO_INPUT WriteMsg::mlWarning, "Warning: There are no input packages to analyze.\n" +#define CMSG_PYLINT_NON_ZERO_EXIT WriteMsg::mlError, "Error: pylint returned non-zero exit code: %d.\n" + +// PylintRulMaker.cpp +#define CMSG_PYLINTRULMAKER_REGEXP_ERROR WriteMsg::mlDebug, "Debug: Cannot recognize rule definition:\n %s\n" + +// Pylint2Graph.cpp +#define CMSG_PYLINT2GRAPH_USING_CONFIG WriteMsg::mlNormal, "Using configuration: \"%s\"\n" +#define CMSG_PYLINT2GRAPH_LOADING_LIM WriteMsg::mlNormal, "Loading LIM ASG file \"%s\"\n" +#define CMSG_PYLINT2GRAPH_LOADING_LIM_FILTER WriteMsg::mlNormal, "Loading filter file \"%s\"\n" +#define CMSG_PYLINT2GRAPH_FILTER_FILE_IS_DEPRECATED WriteMsg::mlWarning, "Warning: Filter file (%s) is older than the input file. Filter file is not used.\n" +#define CMSG_PYLINT2GRAPH_LOAD_LIM_EXCEPTION WriteMsg::mlError, "Error: LIM ASG file (%s) cannot be loaded: %s : %s\n" +#define CMSG_PYLINT2GRAPH_LOAD_FILTER_EXCEPTION WriteMsg::mlError, "Error: Filter file (%s) cannot be loaded: %s : %s\n" +#define CMSG_PYLINT2GRAPH_MISSING_RULE WriteMsg::mlWarning, "Warning: There is no rule named '%s' in the rul file, this warning will be ignored: path:%s line:%d text:'%s'\n" +#define CMSG_PYLINT2GRAPH_NO_NODE_FOUND_AT_PATH WriteMsg::mlWarning, "Warning: Warning '%s' cannot be added as no node found at [path:%s line:%d col:%d endline:%d endcol:%d]\n" +#define CMSG_PYLINT2GRAPH_WARNING_ALREADY_ADDED WriteMsg::mlWarning, "Warning: Warning '%s' has already been added. (node:%s path:%s line:%d col:%d endline:%d endcol:%d text:'%s')\n" +#define CMSG_PYLINT2GRAPH_REGEXP_ERROR WriteMsg::mlDebug, "Debug: Cannot recognize rule violation:\n %s\n" + +#endif diff --git a/cl/Pylint2Graph/src/Pylint2Graph.cpp b/cl/Pylint2Graph/src/Pylint2Graph.cpp new file mode 100644 index 0000000..4a56634 --- /dev/null +++ b/cl/Pylint2Graph/src/Pylint2Graph.cpp @@ -0,0 +1,247 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/Pylint2Graph.h" +#include "../inc/PylintRulMaker.h" +#include "../inc/messages.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace common; +using namespace columbus; +using namespace columbus::graph; + + +struct PylintWarning { + PylintWarning() + : path(), lineNum(0), colNum(0), ruleId(), text() {} + PylintWarning(string path, int lineNum, int colNum, string ruleId, string text) + : path(path), lineNum(lineNum), colNum(colNum), ruleId(ruleId), text(text) {} + ~PylintWarning() {} + + string path; + int lineNum; + int colNum; + string ruleId; + string text; + + bool operator<(const PylintWarning& other) const { + if (path != other.path) + return path < other.path; + else if (lineNum != other.lineNum) + return lineNum < other.lineNum; + else if (colNum != other.colNum) + return colNum < other.colNum; + else if (ruleId != other.ruleId) + return ruleId < other.ruleId; + else if (text != other.text) + return text < other.text; + return false; + } +}; + + +Pylint2Graph::Pylint2Graph(const string& rulFile, const string& rulConfig, ostream& out, const string& changePathFrom /* = "" */, const string& changePathTo /* = "" */) : + out(out), + changePathFrom(changePathFrom), + changePathTo(changePathTo), + limFact(strTable, "", columbus::lim::asg::limLangOther), + rulHandler(new columbus::rul::RulHandler(rulFile, rulConfig, "eng", "ISO-8859-1")), + graphIndexer(graphsupport::GraphRangeIndexer::getGraphRangeIndexerInstance()) +{ +} + +Pylint2Graph::~Pylint2Graph() { + if (rulHandler) + delete rulHandler; +} + +void Pylint2Graph::buildGraph(const string& limFileName) { + list header; + WriteMsg::write(CMSG_PYLINT2GRAPH_LOADING_LIM, limFileName.c_str()); + //load lim + try { + limFact.load(limFileName, header); + } catch (const lim::asg::LimException& ex) { + WriteMsg::write(CMSG_PYLINT2GRAPH_LOAD_LIM_EXCEPTION, limFileName.c_str(), ex.getLocation().c_str(), ex.getMessage().c_str()); + exit(EXIT_FAILURE); + } + //load filter + string filterFileName = common::replaceExtension(limFileName, ".flim"); + if (common::pathFileExists(filterFileName, false)) { + WriteMsg::write(CMSG_PYLINT2GRAPH_LOADING_LIM_FILTER, filterFileName.c_str()); + if (fileTimeCmp(filterFileName, limFileName) == -1) { + WriteMsg::write(CMSG_PYLINT2GRAPH_FILTER_FILE_IS_DEPRECATED, filterFileName.c_str()); + } else { + try { + limFact.loadFilter(filterFileName); + } catch (const lim::asg::LimException& ex) { + WriteMsg::write(CMSG_PYLINT2GRAPH_LOAD_FILTER_EXCEPTION, filterFileName.c_str(), ex.getLocation().c_str(), ex.getMessage().c_str()); + exit(EXIT_FAILURE); + } + } + } + + WriteMsg::write(CMSG_PYLINT2GRAPH_USING_CONFIG, rulHandler->getConfig().c_str()); + + lim2graph::convertBaseGraph(limFact, graph, /*edges=*/ true, /*attributes=*/ true, /*components=*/ true, /*variants=*/ false, /*instances=*/ false); + graphIndexer.turnOn(graph); +} + + +void Pylint2Graph::convertResults(const string& pylintResultsFile) { + const boost::regex regexpWarn(":(.*):(\\d+):(\\d+): \\[(\\w+)\\((\\w+[-\\w]*)\\)\\] (.*)"); + + set warnings; + + ifstream input(pylintResultsFile.c_str()); + if (input.is_open()) { + string line; + + while (input.good()) { + + getline(input, line); + + if (!line.empty()) { + + if (line.find("*****") == 0) { + // nothing to do + + } else if (line[0] == ':') { + boost::smatch match; + + if (boost::regex_search(line, match, regexpWarn)) { // TODO multi line warnings are not handled + string path = match[1]; + string lineNum = match[2]; + string colNum = match[3]; + string id = match[4]; + string name = match[5]; + string text = match[6]; + + common::trim(text); + + int iline = atoi(lineNum.c_str()); + int icol = atoi(colNum.c_str()) + 1; + + string ruleId; + + try { + ruleId = rulHandler->getRuleIdByOriginalId(name); + } catch (const rul::RulHandlerException&) { + WriteMsg::write(CMSG_PYLINT2GRAPH_MISSING_RULE, name.c_str(), path.c_str(), iline, text.c_str()); + continue; + } + + common::changePath(path, changePathFrom, changePathTo); + + warnings.insert(PylintWarning(path, iline, icol, ruleId, text)); + + } else { + WriteMsg::write(CMSG_PYLINT2GRAPH_REGEXP_ERROR, line.c_str()); + } + } + } + } + + input.close(); + } + + // add sorted warnings + for (set::const_iterator it = warnings.begin(), itEnd = warnings.end(); it != itEnd; ++it) { + const PylintWarning& warning = *it; + addWarningToNode(warning.path, warning.lineNum, warning.colNum, warning.lineNum, warning.colNum, warning.ruleId, warning.text); + } +} + +void Pylint2Graph::saveResultGraph(const string& outGraphFile, bool exportRul) { + if (exportRul) { + graphsupport::buildRulToGraph(graph, *rulHandler); + } + + // summarize warnings + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_COMPONENT, graph::Edge::edtDirectional), true); + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_COMPONENTTREE, graph::Edge::edtReverse), false); + graphsupport::cumSum(graph, graph::Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_LOGICALTREE, graph::Edge::edtReverse), false); + + // create group metrics + columbus::graphsupport::createGroupMetrics(graph, *rulHandler); + + graph.saveBinary(outGraphFile); +} + +void Pylint2Graph::addWarningToNode(const string& path, int line, int col, int endline, int endcol, const string& warningID, const string& warningText) { + if (!rulHandler->getIsEnabled(warningID)) { + return; // rule is not enabled + } + + list nodes; + + graphIndexer.findNodesByRange(graph, path, line, INT_MIN, endline, INT_MAX, nodes); + + int minDist = INT_MAX; + Node node; + for (list::iterator it = nodes.begin(); it != nodes.end(); ++it) { + vector positions; + graphsupport::getPositionAttributes(*it, positions); + for (vector::iterator pos = positions.begin(); pos != positions.end(); ++pos) { + int dist = abs(line - pos->line) + abs(endline - pos->endline); + if(dist < minDist) { + node = *it; + minDist = dist; + } + } + } + + if (node == Graph::invalidNode) { // could not find the node by path, skip this warning + WriteMsg::write(CMSG_PYLINT2GRAPH_NO_NODE_FOUND_AT_PATH, warningID.c_str(), path.c_str(), line, col, endline, endcol); + + } else { + // if the found node is attribute, we use that parent + if (node.getType().getType() == graphsupport::graphconstants::NTYPE_LIM_ATTRIBUTE) { + Edge::EdgeIterator edgeIt = node.findOutEdges(Edge::EdgeType(graphsupport::graphconstants::ETYPE_LIM_LOGICALTREE, Edge::edtReverse)); + if (edgeIt.hasNext()) { + node = edgeIt.next().getToNode(); + } + } + + if (node != Graph::invalidNode) { + if (graphsupport::addWarningOnce(graph, node, warningID, path, line, col, endline, endcol, warningText)) { + out << path << "(" << line << "): " << warningID << ": " << warningText << endl; + } else { + WriteMsg::write(CMSG_PYLINT2GRAPH_WARNING_ALREADY_ADDED, warningID.c_str(), node.getUID().c_str(), path.c_str(), line, col, endline, endcol, warningText.c_str()); + } + } + } +} diff --git a/cl/Pylint2Graph/src/PylintRulMaker.cpp b/cl/Pylint2Graph/src/PylintRulMaker.cpp new file mode 100644 index 0000000..ff9a27a --- /dev/null +++ b/cl/Pylint2Graph/src/PylintRulMaker.cpp @@ -0,0 +1,362 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/PylintRulMaker.h" +#include "../inc/messages.h" + +#include +#include +#include + +#include +#include +#include +#include + +using namespace std; +using namespace common; +using namespace columbus; + +static const string RULE_PREFIX = "PYLINT_"; + +typedef boost::bimap RuleId2NameMap; +static RuleId2NameMap ruleIdMap; // rule id (without prefix) <-> original pylint rule name + +static void makeCamelCase(string& name) { + if (name.empty()) + return; + + name[0] = ::toupper(name[0]); + for (size_t i = 1, len = name.size(); i < len; ++i) { + if (name[i - 1] == ' ') + name[i] = ::toupper(name[i]); + } +} + +static string convertDisplayName(const string& ruleName) { + if (ruleName.empty()) + return ""; + + string name = ruleName; + replace(name.begin(), name.end(), '-', ' '); + makeCamelCase(name); + + return name; +} + +static string convertGroupName(const string& groupName) { + if (groupName.empty()) + return ""; + + string name = groupName; + replace(name.begin(), name.end(), '_', ' '); + + if (name == "classes") { + name = "class"; + } else if (name == "miscellaneous") { + name = "miscellaneous"; + } else if (name == "similarities") { + name = "similarity"; + } else if (name == "master") { + name = "pylint checker"; + } else if (name[name.size() - 1] == 's') { + name.erase(name.size() - 1); + } + + makeCamelCase(name); + name += " Rules"; + + return name; +} + +static string convertPriority(const string& id) { + char c = id[0]; + switch (c) { + case 'I': return "Minor"; // info + case 'C': return "Minor"; // convention + case 'R': return "Minor"; // refactor + case 'W': return "Major"; // warning + case 'E': return "Critical"; // error + case 'F': return "Blocker"; // fatal + default: return ""; + } +} + +static void setShortName(const std::string& origname, const std::string& rulename, std::string& shortname, int small = 0, int ext = 0) { + int tsmall = small; + for (unsigned int i = 0; i < rulename.size(); i++) { + if ( (rulename[i] >= 'A' && rulename[i] <= 'Z') + || (rulename[i] >= '0' && rulename[i] <= '9')) + shortname += rulename[i]; + else if (rulename[i] >= 'a' && rulename[i] <= 'z' && tsmall > 0) { + shortname += rulename[i]; + tsmall--; + } + } + if (ext > 0) + shortname += toString(ext); + if (shortname.empty()) + setShortName(origname, rulename, shortname, ++small); + else { + RuleId2NameMap::left_const_iterator it1 = ruleIdMap.left.find(shortname); + RuleId2NameMap::left_const_iterator it2 = ruleIdMap.left.end(); + if (it1 != it2) { + shortname.clear(); + if (tsmall > 0) + setShortName(origname, rulename, shortname, ++small, ++ext); + else + setShortName(origname, rulename, shortname, ++small); + } else { + ruleIdMap.insert(RuleId2NameMap::value_type(shortname, origname)); + } + } +} + +static string convertRuleId(const string& origName, const string& dispName) { + string shortName; + setShortName(origName, dispName, shortName); + return shortName; +} + +struct PylintRule { + PylintRule() + : name(), id(), group(), desc(), warn() {} + PylintRule(string name, string id, string group, string desc, string warn) + : name(name), id(id), group(group), desc(desc), warn(warn) {} + ~PylintRule() {} + + string name; + string id; + string group; + string desc; + string warn; + + bool operator<(const PylintRule& other) const { + if (name != other.name) + return name < other.name; + // other members are not used for comparison + return false; + } +}; + +PylintRulMaker::PylintRulMaker() { +} + +PylintRulMaker::~PylintRulMaker() { +} + +void PylintRulMaker::makeRul(const string& messagesFileName, const string& idsFileName, const string& rulFile) { + ruleIdMap.clear(); + + // load existing ids + if (!idsFileName.empty()) { + ifstream input(idsFileName.c_str()); + if (input.is_open()) { + string line; + while (input.good()) { + getline(input, line); + if (!line.empty()) { + vector items; + common::split(line, items, ';'); + if (items.size() == 2) { + ruleIdMap.insert(RuleId2NameMap::value_type(items[0], items[1])); + } + } + } + input.close(); + } + } + + rul::RulHandler rulHandler("Default", "eng"); + rulHandler.setToolDescription("ID", "Pylint"); + + set rules; + map > groupMembers; + + const boost::regex regexpRule(":(\\w+[-\\w]*):(\\w+[-\\w]*) \\((\\w+)\\):(?: \\*(.*)\\*)?"); + + // read file and convert rules + ifstream input(messagesFileName.c_str()); + if (input.is_open()) { + string line; + string def, desc; + + while (input.good()) { + getline(input, line); + + if (line.empty() || line[0] == ':') { + + if (!def.empty()) { + boost::smatch match; + + if (boost::regex_search(def, match, regexpRule)) { + string group = match[1]; + string name = match[2]; + string id = match[3]; + string warn = match[4]; + + rules.insert(PylintRule(name, id, group, desc, warn)); + + } else { + WriteMsg::write(CMSG_PYLINTRULMAKER_REGEXP_ERROR, def.c_str()); + } + + def = ""; + desc = ""; + } + } + + if (line.empty()) { + continue; + } else if (line[0] == ':') { + def = line; + } else { + common::trim(line, " "); + if (!desc.empty() && *desc.rbegin() != '-') { + desc += " "; + } + desc += line; + } + + } + + input.close(); + + } else { + WriteMsg::write(CMSG_CANNOT_OPEN_FILE, messagesFileName.c_str()); + exit(EXIT_FAILURE); + } + + // create rules + for (set::const_iterator it = rules.begin(), itEnd = rules.end(); it != itEnd; ++it) { + const PylintRule& rule = *it; + + string prio = convertPriority(rule.id); + string dispName = convertDisplayName(rule.name); + string ruleId; + bool isEnabled = true; + string helpText = rule.desc; + + RuleId2NameMap::right_const_iterator nameIt = ruleIdMap.right.find(rule.name); + if (nameIt != ruleIdMap.right.end()) { + // the rule already exists in a previous version + ruleId = nameIt->second; + } else { + // new rule, generate an id for it + ruleId = convertRuleId(rule.name, dispName); + ruleIdMap.insert(RuleId2NameMap::value_type(ruleId, rule.name)); + } + + ruleId = RULE_PREFIX + ruleId; + + groupMembers[rule.group].insert(ruleId); + + // these rules are disabled by default + if (rule.name == "import-error" || rule.name == "method-check-failed" || rule.name == "unresolved-interface") { + isEnabled = false; + } + + // fix helptext + { + // helper func for escaping markdown / html spec chars : < { } [] \ _ + auto escapeSpecChars = [&](const boost::smatch& what) { + std::string out = what[0]; + if (!out.empty() && out[0] != '`') { + const boost::regex re("([_<\\{\\}\\[\\]\\\\])"); + out = boost::regex_replace(out, re, "\\\\\\1"); + boost::replace_all(out, "--", "\\-\\-"); + } + return out; + }; + + // escape spec chars which are not inside a code block (between 2 ` or ``) + const boost::regex reCode("`[^`]+`|[^`]+"); + helpText = boost::regex_replace(helpText, reCode, escapeSpecChars); + + // add < and > around links + const boost::regex reUrl("(http[s]?://[^ ]+)([^\\.! ])"); + helpText = boost::regex_replace(helpText, reUrl, "<\\1\\2>"); + } + + rulHandler.defineMetric(ruleId); + rulHandler.createConfiguration(ruleId, "Default"); + rulHandler.setIsEnabled(ruleId, isEnabled); + rulHandler.setIsVisible(ruleId, true); + rulHandler.setGroupType(ruleId, "false"); + rulHandler.createLanguage(ruleId, "eng"); + rulHandler.setHasWarningText(ruleId, true); + rulHandler.setSettingValue(ruleId, "Priority", prio, true); + rulHandler.setDisplayName(ruleId, dispName); + rulHandler.setDescription(ruleId, rule.desc); + rulHandler.setHelpText(ruleId, helpText); + rulHandler.setWarningText(ruleId, rule.warn); + rulHandler.setOriginalId(ruleId, rule.name); + } + + // rewrite ids file + { + ofstream output((idsFileName + "_out").c_str()); + if (output.is_open()) { + // sort by ids + for (RuleId2NameMap::left_const_iterator it = ruleIdMap.left.begin(); it != ruleIdMap.left.end(); ++it) { + output << it->first << ";" << it->second << "\n"; + } + output.close(); + } + } + + // create groups + for (map >::const_iterator git = groupMembers.begin(), gitEnd = groupMembers.end(); git != gitEnd; ++git) { + string pylintGroupName = git->first; + string groupName = convertGroupName(pylintGroupName); + + rulHandler.defineMetric(groupName); + rulHandler.createConfiguration(groupName, "Default"); + rulHandler.createLanguage(groupName, "Default", "eng"); + rulHandler.setIsEnabled(groupName, true); + rulHandler.setIsVisible(groupName, true); + rulHandler.setGroupType(groupName, "summarized"); + rulHandler.setHasWarningText(groupName, true); + rulHandler.setSettingValue(groupName, "Priority", "Minor", true); + rulHandler.setDisplayName(groupName, groupName); + rulHandler.setDescription(groupName, groupName); + rulHandler.setHelpText(groupName, groupName); + rulHandler.setOriginalId(groupName, pylintGroupName); + + // disable these groups and their rules by default + // similarities - copy-paste detector, similar to DCF + // master - pylint's main checker component (analyzer errors, info messages, etc.) + bool isDisabledByDefault = false; + if (pylintGroupName == "similarities" || pylintGroupName == "master") { + isDisabledByDefault = true; + rulHandler.setIsEnabled(groupName, false); + } + + for (set::const_iterator rit = git->second.begin(), ritEnd = git->second.end(); rit != ritEnd; ++rit) { + rulHandler.addMetricGroupMembers(*rit, groupName); + if (isDisabledByDefault) { + rulHandler.setIsEnabled(*rit, false); + } + } + } + + // save rul + rulHandler.saveRul(rulFile); +} diff --git a/cl/Pylint2Graph/src/PylintRunner.cpp b/cl/Pylint2Graph/src/PylintRunner.cpp new file mode 100644 index 0000000..7eab5fe --- /dev/null +++ b/cl/Pylint2Graph/src/PylintRunner.cpp @@ -0,0 +1,74 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "../inc/PylintRunner.h" +#include "../inc/messages.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace common; +using namespace columbus; + + +PylintRunner::PylintRunner() { +} + +PylintRunner::~PylintRunner() { +} + +void PylintRunner::run(const string& projectBaseDir, const string& pythonBinary, const string& pylintDir, const string& pylintrc, const string& outputFile, const std::list& pylintOptions) { + list packagePaths; + + columbus::python::collectPythonPackages(projectBaseDir, "", packagePaths); + + if (packagePaths.empty()) { + WriteMsg::write(CMSG_PYLINT_NO_INPUT); + ofstream ofs(outputFile.c_str(), ofstream::trunc); + return; + } + + string pylintScript = (boost::filesystem::path(pylintDir) / "bin" / "pylint").string(); + + vector sv; + sv.push_back("-B"); // don't create .py[co] files + sv.push_back(pylintScript); + sv.push_back("--rcfile=" + pylintrc); + for (const string& s : pylintOptions) + sv.push_back(s); + for (list::const_iterator it = packagePaths.begin(); it != packagePaths.end(); ++it) { + sv.push_back(*it); + } + + common::pathDeleteFile(outputFile); + + int ret = common::run(pythonBinary, sv, outputFile, outputFile); + if (ret != 0) { + WriteMsg::write(CMSG_PYLINT_NON_ZERO_EXIT, ret); + exit(EXIT_FAILURE); + } +} diff --git a/cl/Pylint2Graph/src/main.cpp b/cl/Pylint2Graph/src/main.cpp new file mode 100644 index 0000000..c8d29ea --- /dev/null +++ b/cl/Pylint2Graph/src/main.cpp @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + + +#define PROGRAM_NAME "Pylint2Graph" +#define EXECUTABLE_NAME "Pylint2Graph" + +#include +#include +#include + +#include "../inc/messages.h" +#include "../inc/PylintRulMaker.h" +#include "../inc/PylintRunner.h" +#include "../inc/Pylint2Graph.h" + +using namespace std; +using namespace common; +using namespace columbus; + + +static bool makeRul = false; +static string pylintMessagesTxt; +static string pylintIdsTxt; +static string outGraph; +static string outTxt; +static string changepathfrom; +static string changepathto; +static string limFile; +static string rulFile = "Pylint.rul"; +static string rulConfig = "Default"; +static bool exportRul; +static bool runPylint = false; +static string pythonBinary; +static string pylintDir; +static string pylintrc; +static string projectBaseDir; +static string pylintOut; +static list pylintOptions; +static list inputFiles; + +static bool ppMakeRul(const Option *o, char *argv[]) { + makeRul = true; + pylintMessagesTxt = argv[0]; + return true; +} + +static bool ppIds(const Option *o, char *argv[]) { + pylintIdsTxt = argv[0]; + return true; +} + +static bool ppGraph(const Option *o, char *argv[]) { + outGraph = argv[0]; + return true; +} + +static bool ppOut(const common::Option *o, char *argv[]) { + outTxt = argv[0]; + return true; +} + +static bool ppLimFile(const Option *o, char *argv[]) { + limFile = argv[0]; + return true; +} + +static bool ppRul(const Option *o, char *argv[]) { + rulFile = argv[0]; + return true; +} + +static bool ppRulConfig(const Option *o, char *argv[]) { + rulConfig = argv[0]; + return true; +} + +static bool ppExportRul(const Option *o, char *argv[]) { + exportRul = true; + return true; +} + +static bool ppRunPylint(const Option *o, char *argv[]) { + runPylint = true; + return true; +} + +static bool ppPythonBinary(const Option *o, char *argv[]) { + pythonBinary = argv[0]; + return true; +} + +static bool ppPylintDir(const Option *o, char *argv[]) { + pylintDir = argv[0]; + return true; +} + +static bool ppPylintrc(const Option *o, char *argv[]) { + pylintrc = argv[0]; + return true; +} + +static bool ppProjectBaseDir(const Option *o, char *argv[]) { + projectBaseDir = argv[0]; + return true; +} + +static bool ppPylintOut(const Option *o, char *argv[]) { + pylintOut = argv[0]; + return true; +} + +bool ppPylintOptions(const common::Option *o, char *argv[]) { + pylintOptions.push_back(argv[0]); + return true; +} + +static void ppFile(char *filename) { + inputFiles.push_back(filename); +} + +const common::Option OPTIONS_OBJ [] = { + // options for making rul file + { false, "-makerul", 1, "pylint_messages.txt", 0, OT_WS, ppMakeRul, NULL, "Makes rul file from the pylint messages file."}, + { false, "-ids", 1, "pylint_ids.txt", 0, OT_WS, ppIds, NULL, "File which contains previous rule ids." }, + // options for running pylint + { false, "-runpylint", 0, "", 0, OT_NONE, ppRunPylint, NULL, "Runs Pylint checker."}, + { false, "-pythonBinary", 1, "file", 0, OT_WC, ppPythonBinary, NULL, "Path of the Python 2.7/3.x binary."}, + { false, "-pylintdir", 1, "directory", 0, OT_WC, ppPylintDir, NULL, "Directory of the Pylint checker. It will be added to the PYTHONPATH environment variable."}, + { false, "-pylintrc", 1, "file", 0, OT_WC, ppPylintrc, NULL, "Configuration file for Pylint."}, + { false, "-projectbasedir", 1, "directory", 0, OT_WC, ppProjectBaseDir, NULL, "Base directory of the input project."}, + { false, "-pylintout", 1, "file", 0, OT_WC, ppPylintOut, NULL, "Output file for the Pylint results."}, + { false, "-pylintOptions", 1, "string", 0, OT_WC, ppPylintOptions, NULL, "Passes command line options to Pylint. Options with arguments can be passed with successive -pylintOptions options."}, + // options for collecting pylint results + { false, "-graph", 1, "filename", 0, OT_WC, ppGraph, NULL, "Save binary graph output to the given file."}, + { false, "-out", 1, "filename", 0, OT_WC, ppOut, NULL, "If it is specified then the list of rule violations will be written into this file." + " Otherwise they will be dumped to the standard output."}, + CL_LIM + CL_RUL_AND_RULCONFIG("Pylint.rul") + CL_EXPORTRUL + COMMON_CL_ARGS +}; + + +int main(int argc, char* argv[]) { + MAIN_BEGIN + + MainInit(argc, argv, "-"); + + if (!common::pathIsAbsolute(rulFile.c_str())) { + rulFile = getExecutableProgramDir() + rulFile; + } + + if (!makeRul && !runPylint) { + if (inputFiles.size() != 1) { + WriteMsg::write(CMSG_WRONG_INPUT); + clError(); + } + } + + updateMemoryStat(true); + + if (runPylint) { + if (pythonBinary.empty() || pylintDir.empty() || pylintrc.empty() || projectBaseDir.empty() || pylintOut.empty()) { + WriteMsg::write(CMSG_RUNPYLINT_OPTION_ERROR); + exit(EXIT_FAILURE); + } + } + + if (makeRul) { + PylintRulMaker pylintRulMaker; + pylintRulMaker.makeRul(pylintMessagesTxt, pylintIdsTxt, rulFile); + + } else if (runPylint) { + PylintRunner runner; + runner.run(projectBaseDir, pythonBinary, pylintDir, pylintrc, pylintOut, pylintOptions); + + updateMemoryStat(); + + } else { + std::ostream* out = &cout; + std::ofstream ofs; + + if (!outTxt.empty()) { + ofs.open(outTxt.c_str()); + if (!ofs.is_open()) { + WriteMsg::write(CMSG_CANNOT_OPEN_FILE, outTxt.c_str()); + } else { + out = &ofs; + } + } + + updateMemoryStat(); + + Pylint2Graph pylint2Graph(rulFile, rulConfig, *out, changepathfrom, changepathto); + pylint2Graph.buildGraph(limFile); + pylint2Graph.convertResults(inputFiles.front()); + + updateMemoryStat(); + + if (!outGraph.empty()) + pylint2Graph.saveResultGraph(outGraph, exportRul); + } + + MAIN_END + + return 0; +} diff --git a/inc/ReleaseVersion.h b/inc/ReleaseVersion.h index 9c12d9d..8ae5307 100644 --- a/inc/ReleaseVersion.h +++ b/inc/ReleaseVersion.h @@ -23,6 +23,6 @@ #include "columbus_config.h" -static const char CopyRightMessage[] = "Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged "; +static const char CopyRightMessage[] = "Copyright (c) 2004-2018 Department of Software Engineering - University of Szeged "; #endif diff --git a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.2.2.1.xml b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.2.2.1.xml index 9a5722f..30f9cdd 100644 --- a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.2.2.1.xml +++ b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.2.2.1.xml @@ -5,7 +5,7 @@ org.apache.maven.plugins OpenStaticAnalyzer-maven-plugin - 8.2 + 2.0 maven-plugin OpenStaticAnalyzer-maven-plugin Maven Plugin diff --git a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.0.5.xml b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.0.5.xml index 0f4e7ca..d5d1536 100644 --- a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.0.5.xml +++ b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.0.5.xml @@ -5,7 +5,7 @@ org.apache.maven.plugins OpenStaticAnalyzer-maven-plugin - 8.2 + 2.0 maven-plugin OpenStaticAnalyzer-maven-plugin Maven Plugin diff --git a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.1.0.xml b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.1.0.xml index b8267da..6c89035 100644 --- a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.1.0.xml +++ b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/pom.3.1.0.xml @@ -5,7 +5,7 @@ org.apache.maven.plugins OpenStaticAnalyzer-maven-plugin - 8.2 + 2.0 maven-plugin OpenStaticAnalyzer-maven-plugin Maven Plugin diff --git a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/src/main/java/com/columbus/maven/plugins/AbstractColumbusMojo.java b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/src/main/java/com/columbus/maven/plugins/AbstractColumbusMojo.java index e702c30..6cf73c1 100644 --- a/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/src/main/java/com/columbus/maven/plugins/AbstractColumbusMojo.java +++ b/java/columbus-toolchain-maven-plugin/columbus-maven-plugin/src/main/java/com/columbus/maven/plugins/AbstractColumbusMojo.java @@ -57,7 +57,7 @@ public abstract class AbstractColumbusMojo extends protected static final String MY_PLUGIN_NAME = "OpenStaticAnalyzer-maven-plugin"; protected static final String MY_PLUGIN_PREFIX = "OpenStaticAnalyzer"; protected static final String MY_PLUGIN_GROUP_NAME = "org.apache.maven.plugins"; - protected static final String MY_PLUGIN_VERSION = "8.2"; + protected static final String MY_PLUGIN_VERSION = "2.0"; /** * Collect the given groupid when export the results of analysis. */ diff --git a/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.bat b/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.bat index 8fe42bc..f2a1dbf 100644 --- a/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.bat +++ b/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.bat @@ -69,27 +69,27 @@ for /f "tokens=3*" %%a in ('mvn --version') do ( goto:eof :hackalias -call mvn org.apache.maven.plugins:OpenStaticAnalyzer-maven-plugin:8.2:installyourself +call mvn org.apache.maven.plugins:OpenStaticAnalyzer-maven-plugin:2.0:installyourself goto:eof :oldmaven echo Installing plugin for Maven 2.2.1 ... -call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2-V2.pom +call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0-V2.pom goto:eof :newmaven echo Installing plugin for Maven 3.0.5 ... -call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2-V3.pom +call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0-V3.pom goto:eof :newermaven echo Installing plugin for Maven 3.1.1 ... -call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2-V31.pom +call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0-V31.pom goto:eof :maven322 echo Installing plugin for Maven 3.2.2 ... -call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-8.2-V31.pom +call mvn install:install-file -Dfile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=WindowsWrapper\WrapperBins\Tools\OpenStaticAnalyzer-maven-plugin-2.0-V31.pom goto:eof diff --git a/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.sh b/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.sh index 3303da3..bdb49f6 100755 --- a/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.sh +++ b/java/columbus-toolchain-maven-plugin/ext/maveninstall/installMavenWrapper.sh @@ -20,21 +20,21 @@ then then echo ${NOTTESTEDMSG} fi - mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2-V2.pom + mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V2.pom else if test "${mainver}" = "3.0" then if test "${ver}" != "3.0.5" then echo echo ${NOTTESTEDMSG} fi - mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2-V3.pom + mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V3.pom else if test "${mainver}" = "3.1" then if test "${ver}" != "3.1.1" then echo ${NOTTESTEDMSG} fi - mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2-V31.pom + mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V31.pom else if test "${mainver}" = "3.2" then if test "${ver}" != "3.2.2" @@ -44,7 +44,7 @@ then echo ${NOTTESTEDMSG} fi fi - mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-8.2-V31.pom + mvn install:install-file -Dfile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0.jar -DpomFile=LinuxWrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V31.pom else echo "Error! Your maven version is not supported yet!" exit 1 @@ -53,7 +53,7 @@ fi fi fi -mvn org.apache.maven.plugins:OpenStaticAnalyzer-maven-plugin:8.2:installyourself +mvn org.apache.maven.plugins:OpenStaticAnalyzer-maven-plugin:2.0:installyourself echo "Maven plugin has been successfully installed." exit 0 diff --git a/java/columbus-toolchain-maven-plugin/maven-agent/pom.xml b/java/columbus-toolchain-maven-plugin/maven-agent/pom.xml index 9bed580..c5ef1ba 100644 --- a/java/columbus-toolchain-maven-plugin/maven-agent/pom.xml +++ b/java/columbus-toolchain-maven-plugin/maven-agent/pom.xml @@ -4,7 +4,7 @@ hu.u-szeged.OpenStaticAnalyzer maven-agent jar - 8.2 + 2.0 maven-agent http://maven.apache.org diff --git a/java/columbus-toolchain-maven-plugin/pom.xml b/java/columbus-toolchain-maven-plugin/pom.xml index 4e611b0..7a21f82 100644 --- a/java/columbus-toolchain-maven-plugin/pom.xml +++ b/java/columbus-toolchain-maven-plugin/pom.xml @@ -5,7 +5,7 @@ hu.u-szeged.OpenStaticAnalyzer plugin-agragator - 8.2 + 2.0 pom This is the mutiple project @@ -55,17 +55,17 @@ - + + tofile="${env.OSA_DIR}/${wrapperos}Wrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V3.pom"/> + tofile="${env.OSA_DIR}/${wrapperos}Wrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V31.pom"/> + tofile="${env.OSA_DIR}/${wrapperos}Wrapper/WrapperBins/Tools/OpenStaticAnalyzer-maven-plugin-2.0-V2.pom"/> diff --git a/java/lib/langtools b/java/lib/langtools index f53aaf5..260c1b6 160000 --- a/java/lib/langtools +++ b/java/lib/langtools @@ -1 +1 @@ -Subproject commit f53aaf53cca7a2ccc595b1c156ded930bd2cf1af +Subproject commit 260c1b6c40faa2c7d5770104e601ffd08a799aa2 diff --git a/lib/controller/inc/Properties.h b/lib/controller/inc/Properties.h index 75aaabc..b58d5c9 100644 --- a/lib/controller/inc/Properties.h +++ b/lib/controller/inc/Properties.h @@ -29,7 +29,7 @@ namespace controller struct BaseProperties { BaseProperties() - : maxThreads (1) + : maxThreads (0) , verbose (false) {} boost::filesystem::path logDir; // Absolute path of the directory of the log files diff --git a/lib/controller/inc/Task.h b/lib/controller/inc/Task.h index 00c0e31..bc8b0b5 100644 --- a/lib/controller/inc/Task.h +++ b/lib/controller/inc/Task.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include "Properties.h" @@ -106,7 +106,7 @@ class Task void addDependsOn(const std::string& taskName); const std::vector& getDependsOn() const; virtual const std::string& getName() const = 0; - std::string getLog() const; + bool openLogFile(); protected: @@ -141,7 +141,7 @@ class Task static void copyBinaryExecutable(const boost::filesystem::path& source, const boost::filesystem::path& dest, const std::string& binaryName); static void copyDirectory(const boost::filesystem::path& source, const boost::filesystem::path& dest, const std::string& dirName); static int exec (const boost::filesystem::path& program, const std::vector& args, const boost::filesystem::path& log ); - static int exec (const boost::filesystem::path& program, const std::vector& args, std::stringstream& std_out_err); + static int exec (const boost::filesystem::path& program, const std::vector& args, std::ostream& std_out_err); static void createDirectories(const boost::filesystem::path& dir, ExecutionLogger& logger); void checkedExec(const boost::filesystem::path& program, const std::vector& args, ExecutionLogger& logger, bool critical = true); @@ -149,8 +149,8 @@ class Task void addMessageLevelNumber(std::vector& args, unsigned verbose, unsigned normal); std::vector dependsOn; - std::stringstream logstream; const BaseProperties& properties; + std::ofstream logstream; friend class ExecutionLogger; }; diff --git a/lib/controller/src/Controller.cpp b/lib/controller/src/Controller.cpp index a1d0771..1f96f7e 100644 --- a/lib/controller/src/Controller.cpp +++ b/lib/controller/src/Controller.cpp @@ -218,34 +218,26 @@ int Controller::executeTasks(ExecutionMode executionMode) for(vector::iterator s_it = it->second.begin(); s_it != it->second.end(); s_it++) { Task* task = getTask(*s_it); + if (!task->openLogFile()) + { + string logfilename = (_props.logDir / (task->getName() + ".log")).string(); + WriteMsg::write(WriteMsg::mlError, "Can not open log file for writing: %s\n", logfilename.c_str()); + } runningTasks.push_back(make_pair(task, Task::ExecutionResult())); threadPool.add(columbus::thread::ThreadPool::PtrTask(new Worker(runningTasks.back().first, &runningTasks.back().second, threadPool.getTaskLockMutex()))); } threadPool.wait(); - for(TaskResultVector::const_iterator taskIt = runningTasks.begin(); taskIt != runningTasks.end(); taskIt++) { - const Task* task = taskIt->first; - const Task::ExecutionResult& result = taskIt->second; - - string logfilename = (_props.logDir / (task->getName() + ".log")).string(); - FILE* logfile = fopen(logfilename.c_str(), "wb"); - string log = task->getLog(); - if (logfile != NULL) { - fwrite(log.c_str(), log.size(), 1 , logfile); - fclose(logfile); - } else { - WriteMsg::write(WriteMsg::mlError, "Can not open log file for writing: %s\n", logfilename.c_str()); - WriteMsg::write(WriteMsg::mlError, "The log is printed to the stdout:\n%s\n", log.c_str()); - } + for(const auto& taskResultPair : runningTasks) + { + const Task::ExecutionResult& result = taskResultPair.second; - if (result.hasCriticalError()) { + if (result.hasCriticalError()) failed = true; - } - - if (result.hasError() && executionMode == EM_FAIL_ON_ANY_ERROR) { + + if (result.hasError() && executionMode == EM_FAIL_ON_ANY_ERROR) failed = true; - } } } } diff --git a/lib/controller/src/Task.cpp b/lib/controller/src/Task.cpp index ddcbab5..086abd0 100644 --- a/lib/controller/src/Task.cpp +++ b/lib/controller/src/Task.cpp @@ -38,7 +38,6 @@ namespace columbus namespace controller { - void Task::addMessageLevel(std::vector& args) { if (properties.verbose) { args.push_back("-ml:4"); @@ -54,7 +53,7 @@ void Task::addMessageLevelNumber(std::vector& args, unsigned verbos } -int Task::exec(const boost::filesystem::path& program, const std::vector& args, std::stringstream& std_out_err) { +int Task::exec(const boost::filesystem::path& program, const std::vector& args, std::ostream& std_out_err) { if (WriteMsg::getMessageLevel() >= WriteMsg::mlDebug) { std_out_err << "[" << common::getCurrentTimeAndDate("%Y-%m-%d %H:%M:%S") << "]"; std_out_err << current_path().string() << "> " << program.string(); @@ -88,6 +87,12 @@ const vector& Task::getDependsOn() const return dependsOn; } +bool Task::openLogFile() +{ + logstream.open((properties.logDir / (getName() + ".log")).string(), ios_base::binary); + return logstream.is_open(); +} + void Task::copyAllFiles(const path& source,const path& dest) { if( exists( path (source)) ) @@ -118,11 +123,6 @@ void Task::copyDirectory(const path& source, const path& dest, const string& dir } } -string Task::getLog() const { - return logstream.str(); -} - - Task::ExecutionLogger::ExecutionLogger(Task* task, ExecutionResult& result) : task(task), result(result) { task->logstream << "[" << common::getCurrentTimeAndDate("%Y-%m-%d %H:%M:%S") << "] Start:" << task->getName() << "\n"; } diff --git a/lib/limmetrics/CMakeLists.txt b/lib/limmetrics/CMakeLists.txt index 64529ce..b66ab5e 100644 --- a/lib/limmetrics/CMakeLists.txt +++ b/lib/limmetrics/CMakeLists.txt @@ -56,11 +56,8 @@ set (SOURCES inc/RulParser.h ) -function (add_language_config LANG) - add_library (${LIBNAME}_${LANG} STATIC ${SOURCES}) - set_schema_language_compiler_settings(${LIBNAME}_${LANG} ${LANG}) - add_dependencies (${LIBNAME}_${LANG} lim) - set_visual_studio_project_folder(${LIBNAME}_${LANG} FALSE) -endfunction() +add_library (${LIBNAME} STATIC ${SOURCES}) +add_dependencies (${LIBNAME} lim) +add_pch_generation(${LIBNAME} lim) +set_visual_studio_project_folder(${LIBNAME} FALSE) -add_language_config(java) diff --git a/lib/limmetrics/src/metrics/LCOM5.cpp b/lib/limmetrics/src/metrics/LCOM5.cpp index ed603e4..80414a4 100644 --- a/lib/limmetrics/src/metrics/LCOM5.cpp +++ b/lib/limmetrics/src/metrics/LCOM5.cpp @@ -226,15 +226,15 @@ namespace columbus { namespace lim { namespace metrics { logical::Class *classOfAttribute = (logical::Class*)(&(*it)); if(classOfAttribute->getAggregated() != NULL) classOfAttribute = (logical::Class*)(classOfAttribute->getAggregated()); - - if (parentClasses.find(classOfAttribute) != parentClasses.end() || classOfAttribute->getId() == actClassId) { - elementInComponent.nextElement = &actualElement; + if (parentClasses.find(classOfAttribute) != parentClasses.end() || classOfAttribute->getId() == actClassId) { - actualAttributes.insert(elementAttributes.begin(), elementAttributes.end()); - isConnected = true; - break; - } + elementInComponent.nextElement = &actualElement; + + actualAttributes.insert(elementAttributes.begin(), elementAttributes.end()); + isConnected = true; + break; + } } } @@ -256,14 +256,14 @@ namespace columbus { namespace lim { namespace metrics { logical::Class *classOfMethod = (logical::Class*)(&(*it)); if(classOfMethod->getAggregated() != NULL) classOfMethod = (logical::Class*)(classOfMethod->getAggregated()); - - if (parentClasses.find(classOfMethod) != parentClasses.end()) { - elementInComponent.nextElement = &actualElement; + if (parentClasses.find(classOfMethod) != parentClasses.end()) { - actualMethods.insert(elementMethods.begin(), elementMethods.end()); - break; - } + elementInComponent.nextElement = &actualElement; + + actualMethods.insert(elementMethods.begin(), elementMethods.end()); + break; + } } } diff --git a/lib/python/CMakeLists.txt b/lib/python/CMakeLists.txt new file mode 100644 index 0000000..4fb2833 --- /dev/null +++ b/lib/python/CMakeLists.txt @@ -0,0 +1,217 @@ +set (LIBNAME python) + +set (SOURCES + src/Factory.cpp + inc/Factory.h + src/Filter.cpp + inc/Filter.h + src/Types.cpp + inc/Types.h + src/ListIterator.cpp + inc/ListIterator.h + src/PythonException.cpp + inc/PythonException.h + src/Common.cpp + inc/Common.h + src/ReverseEdges.cpp + inc/ReverseEdges.h + src/Range.cpp + inc/Range.h + src/algorithms/Algorithm.cpp + inc/algorithms/Algorithm.h + src/algorithms/AlgorithmPreorder.cpp + inc/algorithms/AlgorithmPreorder.h + src/visitors/Visitor.cpp + inc/visitors/Visitor.h + src/visitors/VisitorAbstractNodes.cpp + inc/visitors/VisitorAbstractNodes.h + src/visitors/VisitorPYTHONML.cpp + inc/visitors/VisitorPYTHONML.h + src/visitors/VisitorFilter.cpp + inc/visitors/VisitorFilter.h + src/visitors/VisitorReverseEdges.cpp + inc/visitors/VisitorReverseEdges.h + src/visitors/VisitorSave.cpp + inc/visitors/VisitorSave.h + src/visitors/VisitorSubtreeCollector.cpp + inc/visitors/VisitorSubtreeCollector.h + src/visitors/VisitorSimpleEdge.cpp + inc/visitors/VisitorSimpleEdge.h + src/python.cpp + inc/python.h + src/base/Base.cpp + inc/base/Base.h + src/base/Comment.cpp + inc/base/Comment.h + src/base/Docstring.cpp + inc/base/Docstring.h + src/base/Named.cpp + inc/base/Named.h + src/base/Positioned.cpp + inc/base/Positioned.h + src/expression/ArgumentList.cpp + inc/expression/ArgumentList.h + src/expression/AttributeRef.cpp + inc/expression/AttributeRef.h + src/expression/Binary.cpp + inc/expression/Binary.h + src/expression/BinaryArithmetic.cpp + inc/expression/BinaryArithmetic.h + src/expression/BinaryLogical.cpp + inc/expression/BinaryLogical.h + src/expression/Call.cpp + inc/expression/Call.h + src/expression/DictComp.cpp + inc/expression/DictComp.h + src/expression/Dictionary.cpp + inc/expression/Dictionary.h + src/expression/Ellipsis.cpp + inc/expression/Ellipsis.h + src/expression/Expression.cpp + inc/expression/Expression.h + src/expression/ExpressionList.cpp + inc/expression/ExpressionList.h + src/expression/ExtSlice.cpp + inc/expression/ExtSlice.h + src/expression/FloatNumber.cpp + inc/expression/FloatNumber.h + src/expression/Generator.cpp + inc/expression/Generator.h + src/expression/GeneratorExpression.cpp + inc/expression/GeneratorExpression.h + src/expression/Identifier.cpp + inc/expression/Identifier.h + src/expression/IfExpression.cpp + inc/expression/IfExpression.h + src/expression/ImagNumber.cpp + inc/expression/ImagNumber.h + src/expression/Index.cpp + inc/expression/Index.h + src/expression/IntegerLiteral.cpp + inc/expression/IntegerLiteral.h + src/expression/KeyValue.cpp + inc/expression/KeyValue.h + src/expression/Keyword.cpp + inc/expression/Keyword.h + src/expression/Lambda.cpp + inc/expression/Lambda.h + src/expression/List.cpp + inc/expression/List.h + src/expression/ListComp.cpp + inc/expression/ListComp.h + src/expression/Literal.cpp + inc/expression/Literal.h + src/expression/LongInteger.cpp + inc/expression/LongInteger.h + src/expression/Set.cpp + inc/expression/Set.h + src/expression/SetComp.cpp + inc/expression/SetComp.h + src/expression/Slice.cpp + inc/expression/Slice.h + src/expression/Slicing.cpp + inc/expression/Slicing.h + src/expression/StringConversion.cpp + inc/expression/StringConversion.h + src/expression/StringLiteral.cpp + inc/expression/StringLiteral.h + src/expression/Subscription.cpp + inc/expression/Subscription.h + src/expression/Unary.cpp + inc/expression/Unary.h + src/expression/UnaryOperation.cpp + inc/expression/UnaryOperation.h + src/expression/YieldExpression.cpp + inc/expression/YieldExpression.h + src/module/Module.cpp + inc/module/Module.h + src/module/Object.cpp + inc/module/Object.h + src/module/Package.cpp + inc/module/Package.h + src/statement/Alias.cpp + inc/statement/Alias.h + src/statement/Assert.cpp + inc/statement/Assert.h + src/statement/Assign.cpp + inc/statement/Assign.h + src/statement/AugAssign.cpp + inc/statement/AugAssign.h + src/statement/BaseSpecifier.cpp + inc/statement/BaseSpecifier.h + src/statement/Break.cpp + inc/statement/Break.h + src/statement/ClassDef.cpp + inc/statement/ClassDef.h + src/statement/CompoundStatement.cpp + inc/statement/CompoundStatement.h + src/statement/Continue.cpp + inc/statement/Continue.h + src/statement/Delete.cpp + inc/statement/Delete.h + src/statement/Exec.cpp + inc/statement/Exec.h + src/statement/For.cpp + inc/statement/For.h + src/statement/FunctionDef.cpp + inc/statement/FunctionDef.h + src/statement/Global.cpp + inc/statement/Global.h + src/statement/Handler.cpp + inc/statement/Handler.h + src/statement/If.cpp + inc/statement/If.h + src/statement/ImportFrom.cpp + inc/statement/ImportFrom.h + src/statement/ImportStatement.cpp + inc/statement/ImportStatement.h + src/statement/Iteration.cpp + inc/statement/Iteration.h + src/statement/Parameter.cpp + inc/statement/Parameter.h + src/statement/Pass.cpp + inc/statement/Pass.h + src/statement/Print.cpp + inc/statement/Print.h + src/statement/Raise.cpp + inc/statement/Raise.h + src/statement/Return.cpp + inc/statement/Return.h + src/statement/SimpleStatement.cpp + inc/statement/SimpleStatement.h + src/statement/Statement.cpp + inc/statement/Statement.h + src/statement/Suite.cpp + inc/statement/Suite.h + src/statement/TargetList.cpp + inc/statement/TargetList.h + src/statement/Try.cpp + inc/statement/Try.h + src/statement/TryExcept.cpp + inc/statement/TryExcept.h + src/statement/TryFinal.cpp + inc/statement/TryFinal.h + src/statement/While.cpp + inc/statement/While.h + src/statement/With.cpp + inc/statement/With.h + src/type/DictType.cpp + inc/type/DictType.h + src/type/ReferenceType.cpp + inc/type/ReferenceType.h + src/type/SequenceType.cpp + inc/type/SequenceType.h + src/type/SimpleType.cpp + inc/type/SimpleType.h + src/type/Type.cpp + inc/type/Type.h + inc/PythonCollector.h + src/PythonCollector.cpp + inc/messages.h +) + +add_library (${LIBNAME} STATIC ${SOURCES}) +add_dependencies (${LIBNAME} boost) +set_target_properties(${LIBNAME} PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${CMAKE_CURRENT_SOURCE_DIR}/inc/${LIBNAME}.h") +add_pch_generation(${LIBNAME} boost) +set_visual_studio_project_folder(${LIBNAME} TRUE) diff --git a/lib/python/inc/Common.h b/lib/python/inc/Common.h new file mode 100644 index 0000000..7de0393 --- /dev/null +++ b/lib/python/inc/Common.h @@ -0,0 +1,795 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Common_H_ +#define _PYTHON_Common_H_ + +#include "python/inc/python.h" + +/** +* \file Common.h +* \brief Contains declaration of Common namespace. +*/ + +namespace columbus { namespace python { namespace asg { + typedef unsigned int NodeHashType; + /** + * \brief Common contains general graph algorithms and common functions + */ + namespace Common { + /** + * \brief Decides whether the node is base::Comment or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is base::Comment. + */ + bool getIsComment(const base::Base& node); + + /** + * \brief Decides whether the node is base::Docstring or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is base::Docstring. + */ + bool getIsDocstring(const base::Base& node); + + /** + * \brief Decides whether the node is base::Named or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is base::Named. + */ + bool getIsNamed(const base::Base& node); + + /** + * \brief Decides whether the node is base::Positioned or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is base::Positioned. + */ + bool getIsPositioned(const base::Base& node); + + /** + * \brief Decides whether the node is expression::ArgumentList or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ArgumentList. + */ + bool getIsArgumentList(const base::Base& node); + + /** + * \brief Decides whether the node is expression::AttributeRef or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::AttributeRef. + */ + bool getIsAttributeRef(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Binary or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Binary. + */ + bool getIsBinary(const base::Base& node); + + /** + * \brief Decides whether the node is expression::BinaryArithmetic or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::BinaryArithmetic. + */ + bool getIsBinaryArithmetic(const base::Base& node); + + /** + * \brief Decides whether the node is expression::BinaryLogical or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::BinaryLogical. + */ + bool getIsBinaryLogical(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Call or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Call. + */ + bool getIsCall(const base::Base& node); + + /** + * \brief Decides whether the node is expression::DictComp or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::DictComp. + */ + bool getIsDictComp(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Dictionary or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Dictionary. + */ + bool getIsDictionary(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Ellipsis or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Ellipsis. + */ + bool getIsEllipsis(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Expression or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Expression. + */ + bool getIsExpression(const base::Base& node); + + /** + * \brief Decides whether the node is expression::ExpressionList or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ExpressionList. + */ + bool getIsExpressionList(const base::Base& node); + + /** + * \brief Decides whether the node is expression::ExtSlice or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ExtSlice. + */ + bool getIsExtSlice(const base::Base& node); + + /** + * \brief Decides whether the node is expression::FloatNumber or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::FloatNumber. + */ + bool getIsFloatNumber(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Generator or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Generator. + */ + bool getIsGenerator(const base::Base& node); + + /** + * \brief Decides whether the node is expression::GeneratorExpression or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::GeneratorExpression. + */ + bool getIsGeneratorExpression(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Identifier or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Identifier. + */ + bool getIsIdentifier(const base::Base& node); + + /** + * \brief Decides whether the node is expression::IfExpression or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::IfExpression. + */ + bool getIsIfExpression(const base::Base& node); + + /** + * \brief Decides whether the node is expression::ImagNumber or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ImagNumber. + */ + bool getIsImagNumber(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Index or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Index. + */ + bool getIsIndex(const base::Base& node); + + /** + * \brief Decides whether the node is expression::IntegerLiteral or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::IntegerLiteral. + */ + bool getIsIntegerLiteral(const base::Base& node); + + /** + * \brief Decides whether the node is expression::KeyValue or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::KeyValue. + */ + bool getIsKeyValue(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Keyword or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Keyword. + */ + bool getIsKeyword(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Lambda or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Lambda. + */ + bool getIsLambda(const base::Base& node); + + /** + * \brief Decides whether the node is expression::List or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::List. + */ + bool getIsList(const base::Base& node); + + /** + * \brief Decides whether the node is expression::ListComp or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::ListComp. + */ + bool getIsListComp(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Literal or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Literal. + */ + bool getIsLiteral(const base::Base& node); + + /** + * \brief Decides whether the node is expression::LongInteger or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::LongInteger. + */ + bool getIsLongInteger(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Set or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Set. + */ + bool getIsSet(const base::Base& node); + + /** + * \brief Decides whether the node is expression::SetComp or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::SetComp. + */ + bool getIsSetComp(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Slice or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Slice. + */ + bool getIsSlice(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Slicing or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Slicing. + */ + bool getIsSlicing(const base::Base& node); + + /** + * \brief Decides whether the node is expression::StringConversion or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::StringConversion. + */ + bool getIsStringConversion(const base::Base& node); + + /** + * \brief Decides whether the node is expression::StringLiteral or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::StringLiteral. + */ + bool getIsStringLiteral(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Subscription or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Subscription. + */ + bool getIsSubscription(const base::Base& node); + + /** + * \brief Decides whether the node is expression::Unary or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::Unary. + */ + bool getIsUnary(const base::Base& node); + + /** + * \brief Decides whether the node is expression::UnaryOperation or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::UnaryOperation. + */ + bool getIsUnaryOperation(const base::Base& node); + + /** + * \brief Decides whether the node is expression::YieldExpression or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is expression::YieldExpression. + */ + bool getIsYieldExpression(const base::Base& node); + + /** + * \brief Decides whether the node is module::Module or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is module::Module. + */ + bool getIsModule(const base::Base& node); + + /** + * \brief Decides whether the node is module::Object or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is module::Object. + */ + bool getIsObject(const base::Base& node); + + /** + * \brief Decides whether the node is module::Package or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is module::Package. + */ + bool getIsPackage(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Alias or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Alias. + */ + bool getIsAlias(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Assert or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Assert. + */ + bool getIsAssert(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Assign or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Assign. + */ + bool getIsAssign(const base::Base& node); + + /** + * \brief Decides whether the node is statement::AugAssign or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::AugAssign. + */ + bool getIsAugAssign(const base::Base& node); + + /** + * \brief Decides whether the node is statement::BaseSpecifier or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::BaseSpecifier. + */ + bool getIsBaseSpecifier(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Break or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Break. + */ + bool getIsBreak(const base::Base& node); + + /** + * \brief Decides whether the node is statement::ClassDef or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::ClassDef. + */ + bool getIsClassDef(const base::Base& node); + + /** + * \brief Decides whether the node is statement::CompoundStatement or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::CompoundStatement. + */ + bool getIsCompoundStatement(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Continue or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Continue. + */ + bool getIsContinue(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Delete or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Delete. + */ + bool getIsDelete(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Exec or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Exec. + */ + bool getIsExec(const base::Base& node); + + /** + * \brief Decides whether the node is statement::For or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::For. + */ + bool getIsFor(const base::Base& node); + + /** + * \brief Decides whether the node is statement::FunctionDef or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::FunctionDef. + */ + bool getIsFunctionDef(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Global or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Global. + */ + bool getIsGlobal(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Handler or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Handler. + */ + bool getIsHandler(const base::Base& node); + + /** + * \brief Decides whether the node is statement::If or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::If. + */ + bool getIsIf(const base::Base& node); + + /** + * \brief Decides whether the node is statement::ImportFrom or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::ImportFrom. + */ + bool getIsImportFrom(const base::Base& node); + + /** + * \brief Decides whether the node is statement::ImportStatement or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::ImportStatement. + */ + bool getIsImportStatement(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Iteration or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Iteration. + */ + bool getIsIteration(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Parameter or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Parameter. + */ + bool getIsParameter(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Pass or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Pass. + */ + bool getIsPass(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Print or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Print. + */ + bool getIsPrint(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Raise or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Raise. + */ + bool getIsRaise(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Return or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Return. + */ + bool getIsReturn(const base::Base& node); + + /** + * \brief Decides whether the node is statement::SimpleStatement or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::SimpleStatement. + */ + bool getIsSimpleStatement(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Statement or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Statement. + */ + bool getIsStatement(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Suite or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Suite. + */ + bool getIsSuite(const base::Base& node); + + /** + * \brief Decides whether the node is statement::TargetList or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::TargetList. + */ + bool getIsTargetList(const base::Base& node); + + /** + * \brief Decides whether the node is statement::Try or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::Try. + */ + bool getIsTry(const base::Base& node); + + /** + * \brief Decides whether the node is statement::TryExcept or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::TryExcept. + */ + bool getIsTryExcept(const base::Base& node); + + /** + * \brief Decides whether the node is statement::TryFinal or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::TryFinal. + */ + bool getIsTryFinal(const base::Base& node); + + /** + * \brief Decides whether the node is statement::While or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::While. + */ + bool getIsWhile(const base::Base& node); + + /** + * \brief Decides whether the node is statement::With or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is statement::With. + */ + bool getIsWith(const base::Base& node); + + /** + * \brief Decides whether the node is type::DictType or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is type::DictType. + */ + bool getIsDictType(const base::Base& node); + + /** + * \brief Decides whether the node is type::ReferenceType or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is type::ReferenceType. + */ + bool getIsReferenceType(const base::Base& node); + + /** + * \brief Decides whether the node is type::SequenceType or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is type::SequenceType. + */ + bool getIsSequenceType(const base::Base& node); + + /** + * \brief Decides whether the node is type::SimpleType or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is type::SimpleType. + */ + bool getIsSimpleType(const base::Base& node); + + /** + * \brief Decides whether the node is type::Type or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is type::Type. + */ + bool getIsType(const base::Base& node); + + /** + * \brief Decides whether the node is AP spec node or not. + * \param node [in] The node whose kind is examined. + * \return Returns true if the node is AP spec node. + */ + bool getIsAPSpecNode(const base::Base& node); + + /** + * \brief Decides whether the 'base' is one of the base kinds (transitive) of 'what'. + * \param what [in] The examined node kind. + * \param base [in] The base node kind. + * \return Returns true if 'base' is a base kind of 'what'. + */ + bool getIsBaseClassKind(NodeKind what, NodeKind base); + + /** + * \brief Decides whether the node is composite or not. + * \param node [in] The node which is being examined. + * \return Returns true if the node is composite. + */ + bool getIsComposite(const base::Base& node); + + /** + * \brief Decides whether the node is composite or not. + * \param node [in] The node which is being examined. + * \return Returns true if the node is not composite. + */ + bool getIsNotComposite(const base::Base& node); + + /** + * \brief Gives back the string representation of the NodeId. + * \param nodeId [in] The NodeId. + * \return The string representation of the nodeId given in the parameter. + */ + const std::string toString(NodeId nodeId); + + /** + * \brief Gives back the string representation of the AssignmentKind kind. + * \param kind [in] The AssignmentKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(AssignmentKind kind); + + /** + * \brief Gives back the string representation of the BinaryArithmeticKind kind. + * \param kind [in] The BinaryArithmeticKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(BinaryArithmeticKind kind); + + /** + * \brief Gives back the string representation of the BinaryLogicalKind kind. + * \param kind [in] The BinaryLogicalKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(BinaryLogicalKind kind); + + /** + * \brief Gives back the string representation of the OriginKind kind. + * \param kind [in] The OriginKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(OriginKind kind); + + /** + * \brief Gives back the string representation of the ParameterKind kind. + * \param kind [in] The ParameterKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(ParameterKind kind); + + /** + * \brief Gives back the string representation of the SequenceTypeKind kind. + * \param kind [in] The SequenceTypeKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(SequenceTypeKind kind); + + /** + * \brief Gives back the string representation of the SimpleTypeKind kind. + * \param kind [in] The SimpleTypeKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(SimpleTypeKind kind); + + /** + * \brief Gives back the string representation of the UnaryKind kind. + * \param kind [in] The UnaryKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(UnaryKind kind); + + /** + * \brief Gives back the string representation of the NodeKind kind. + * \param kind [in] The NodeKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(NodeKind kind); + + /** + * \brief Gives back the string representation of the EdgeKind kind. + * \param kind [in] The EdgeKind. + * \throw PythonException If the kind is not "valid" PythonException is thrown. + * \return The string representation of the kind given in the parameter. + */ + const std::string toString(EdgeKind kind); + + /** + * \brief Returns true if the node exists and is not filtered out. + * \param id [in] The examined node ID. + * \return True if the node exists and is not filtered out. + */ + bool getIsValid(NodeId id); + + /** + * \brief Minimum of same type node similarity. + */ + extern double SimilarityMinimum; + + /** + * \brief Returns the minimum similarity value of same type nodes. + * \return Minimum of same type node similarity. + */ + double getSimilarityMinimum(); + + /** + * \brief Sets the minimum similarity value of same type nodes. + * \param value [in] Minimum of same type node similarity. + */ + void setSimilarityMinimum(double value); + + /** + * \brief Minimum similarity for string type attributes. + */ + extern double SimilarityMinForStrings; + + /** + * \brief Returns the minimum similarity value for string type attributes. + * \return Minimum similarity for string type attributes. + */ + double getSimilarityMinForStrings(); + + /** + * \brief Sets the minimum similarity value for string type attributes. + * \param value [in] Minimum similarity for string type attributes. + */ + void setSimilarityMinForStrings(double value); + + /** + * \brief Minimum similarity for AP spec edges. + */ + extern double SimilarityMinForEdges; + + /** + * \brief Returns the minimum similarity value for AP spec edges. + * \return Minimum similarity for AP spec edges. + */ + double getSimilarityMinForEdges(); + + /** + * \brief Sets the minimum similarity value for AP spec edges. + * \param value [in] Minimum similarity for AP spec edges. + */ + void setSimilarityMinForEdges(double value); + + const std::string getUniqueName(const base::Base& node); + const std::string getQualifiedName(const base::Base& node); + char* getUniqueNameForComponent(char* compName); + base::Base* getScopeParent(const base::Base& node); + bool getIsMemberNode(const base::Base& node); + } // Common + + +}}} +#endif + diff --git a/lib/python/inc/Constant.h b/lib/python/inc/Constant.h new file mode 100644 index 0000000..937a38b --- /dev/null +++ b/lib/python/inc/Constant.h @@ -0,0 +1,45 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_CONSTANT_H_ +#define _PYTHON_CONSTANT_H_ + +#include "python/inc/python.h" + +/** +* \file Constant.h +* \brief Contains declaration of some predefined constants. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief The API version of the schema. + */ + const std::string APIVersion = "1.2.4"; + + /** + * \brief The binary version of the schema. + */ + const std::string BinaryVersion = "1.2.4"; + + +}}} +#endif + diff --git a/lib/python/inc/Factory.h b/lib/python/inc/Factory.h new file mode 100644 index 0000000..00dd2aa --- /dev/null +++ b/lib/python/inc/Factory.h @@ -0,0 +1,1012 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_FACTORY_H_ +#define _PYTHON_FACTORY_H_ + +#include "python/inc/python.h" + +/** +* \file Factory.h +* \brief Contains declaration of Factory class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Factory, which handles (creates, deletes, sets their properties) nodes. + */ + class Factory { + protected: + + /** \internal \brief Type definition to store pointers to nodes. */ + typedef std::vector Container; + + public: + + class SchemaPointerSorage { + public: + virtual ~SchemaPointerSorage(){}; + virtual void onDestroyNode(const base::Base* node) = 0; + }; + + /** + * \brief Constructor. + * \param st [in] Reference to the StrTable. + */ + Factory(RefDistributorStrTable& st); + + /** + * \brief Copy Constructor. It not implemented so it make a linker error if anybody want copy + */ + Factory(const Factory&); + + /** + * \brief Copy. It not implemented so it make a linker error if anybody want copy + */ + Factory& operator=(const Factory&); + + /** + * \brief Destructor. + */ + virtual ~Factory(); + + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + */ + void swapStringTable(RefDistributorStrTable& newStrTable); + + /** + * \brief Saves the graph. + * \param filename [in] The graph is saved into this file. + * \param header [in] The header information (also will be saved). + */ + void save(const std::string &filename , CsiHeader &header) const; + + /** + * \brief Checks the graph header. + * \param header [in] The header information. + */ + void checkHeader(CsiHeader &header); + + /** + * \brief Loads the graph header. + * \param filename [in] The graph header is loaded from this file. + * \param header [in] The header information. + */ + void loadHeader(const std::string &filename, CsiHeader &header); + + /** + * \brief Loads the graph. + * \param filename [in] The graph is loaded from this file. + * \param header [in] The header information (also will be loaded). + */ + void load(const std::string &filename, CsiHeader &header); + + void clear(); + + /** + * \brief It can register for the node destroing event. + * \param storage [in] The graph is loaded from this file. + */ + void regPointerStorage(SchemaPointerSorage* storage); + + /** + * \brief It can delete storage from destroling alert list. + * \param storage [in] The graph is loaded from this file. + */ + void unregPointerStorage(SchemaPointerSorage* storage); + + /** + * \brief Gives back a pointer to the root node. + * \return The pointer to the root node. + */ + module::Package* getRoot() const; + + /** + * \brief Decides whether it is a valid id or not. + * \param id [in] The id whose validity is examined. + * \return Returns true if a node belongs to the id. + */ + bool getExist(NodeId id) const; + + /** + * \brief Gives back a reference to the node. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if there is no node for the id. + * \return Reference to the node. + */ + base::Base& getRef(NodeId id) const; + + /** + * \brief Gives back a pointer to the node. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if there is no node for the id. + * \return Pointer to the node. + */ + base::Base* getPointer(NodeId id) const; + + /** + * \brief Gives back a reference to the StringTable. + * \return Reference to the StringTable. + */ + RefDistributorStrTable& getStringTable() const; + + /** + * \brief Gives back the NodeKind of a node. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if there is no node for the id. + * \return The NodeKind of the node. + */ + NodeKind getNodeKind(NodeId id) const; + + /** + * \brief Deletes the node with the given ID and every node in it's subtree. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if there is no node for the id. + */ + void destroyNode(NodeId id); + + /** + * \brief Deletes the node with the given ID without it's subtree. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if there is no node for the id. + */ + void destroyThisNodeOnly(NodeId id); + + + // ******************** ConstIterator ******************** + + /** + * \brief Nested constant iterator class which enumerates the nodes in the ASG. + */ + class ConstIterator { + private: + + /** + * \internal + * \brief Constructor for ConstIterator. + * \param cont [in] Pointer to the Container + * \param fact [in] Pointer to the Factory. + */ + ConstIterator(const Container* cont, const Factory* fact); + + public: + + /** + * \brief Examines the existence of the next node. + * \return Returns true if a next node exists. + */ + bool hasNext() const; + + /** + * \brief Returns a constant reference of the next node (base::Base). + * \return Reference of the next node. + */ + const base::Base& next(); + + private: + + /** \internal \brief Pointer to the Container. */ + const Container* container; + + /** \internal \brief Pointer to the Factory. */ + const Factory* factory; + + /** \internal \brief Iterator which stores the actual positon. */ + Container::const_iterator i; + + friend class Factory; + }; + + + // ******************** iterator ******************** + + /** + * \brief Nested constant iterator class which enumerates the nodes in the ASG. + */ + class const_iterator { + private: + + /** + * \internal + * \brief Constructor for ConstIterator. + * \param cont [in] Pointer to the Container + * \param fact [in] Pointer to the Factory. + */ + const_iterator(Container::const_iterator it,const Factory* fact):containerIt(it),fact(fact){while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++;} + + Container::const_iterator containerIt; + const Factory* fact; + public: + + const_iterator(const const_iterator& otherit) :containerIt (otherit.containerIt),fact(otherit.fact){} + const_iterator& operator++() {containerIt++; while (containerIt != fact->container.end() && ((*containerIt == NULL) || fact->getIsFiltered(*containerIt))) containerIt++; return *this;} + const_iterator operator++(int) {const_iterator tmp(*this); operator++(); return tmp;} + bool operator==(const const_iterator& rhs) {return containerIt==rhs.containerIt;} + bool operator!=(const const_iterator& rhs) {return containerIt!=rhs.containerIt;} + const base::Base* operator*() {return *containerIt;} + friend class Factory; + }; + + /** + * \brief Get the iterator for the nodes + * \return An iterator to the nodes. + */ + const const_iterator begin() const{return const_iterator(container.begin(),this);} + + /** + * \brief Get the iterator for the nodes. + * \return An iterator to the nodes. + */ + const const_iterator end() const {return const_iterator(container.end(),this);} + + /** + * \brief Creates and returns a constant iterator, which enumerates the nodes in the ASG. + * \return An iterator to the nodes. + */ + const ConstIterator constIterator() const; + + /** + * \brief Tells whether the ASG has nodes (O(n)). + * \return Returns true if there is not any node. + */ + bool isEmpty() const; + + /** + * \brief Returns the number of nodes in the ASG. + * \return The number of nodes in the ASG. + */ + unsigned size() const; + + /** + * \brief get the node individualiy state. + */ + bool isIndividual(NodeId id) const {return container[id] && (container[id]->getParent()==0);} + + + // ******************** Filter ******************** + + /** + * \brief Turns the Filter on. + */ + void turnFilterOn(); + + /** + * \brief Turns the Filter off. + */ + void turnFilterOff(); + + /** + * \brief A solution to turn Filter off safely. + */ + class TurnFilterOffSafely { + public: + + /** + * \brief Constructor to turn Filter off safely. + * \param fact [in] Reference to the Factory. + */ + TurnFilterOffSafely(Factory &fact); + + /** + * \brief Constructor to turn Filter off safely. + * \param fact [in] Reference to the Factory. + */ + TurnFilterOffSafely(const Factory &fact); + + /** + * \brief Destructor which restores the Filter to its original state . + */ + ~TurnFilterOffSafely(); + + private: + /** \internal \brief Prevents dynamic instantiation (but does nothing). */ + void* operator new (size_t) throw(); + + /** \internal \brief Prevents dynamic instantiation (but does nothing). */ + void* operator new[] (size_t) throw(); + + /** \internal \brief Reference to the Factory. */ + Factory& factory; + + /** \internal \brief The original state of the Filter. */ + bool oldState; + + }; + + /** + * \brief Gives back the state of the Filter. + * \return Returns true if the Filter is turned on, otherwise returns false. + */ + bool getIsFilterTurnedOn() const; + + /** + * \brief Initializes the filter (see Filter::initializeFilter() for more details). + */ + void initializeFilter(); + + /** + * \brief Tells whether the given node is filtered or not. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the ASG). + * \return Returns true if the Node is filtered and returns false if it isn't (or the filter mode is turned off). + */ + bool getIsFiltered(NodeId id) const; + + /** + * \brief Tells whether the given node is filtered or not. + * \param node [in] The pointer to the node. + * \return Returns true if the Node is filtered and returns false if it isn't (or the filter mode is turned off). + */ + bool getIsFiltered(const base::Base* node) const; + + /** + * \brief Filters out the given node and all of its descendants. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException id the id is too large (larger than the size of the Filter). + */ + void setFiltered(NodeId id); + + /** + * \brief Sets the state of the node, all of its descendants and all of its ancestors to not filtered. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException id the id is too large (larger than the size of the Filter). + */ + void setNotFiltered(NodeId id); + + /** + * \brief Sets the state of the node and all of its ancestors to not filtered. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException id the id is too large (larger than the size of the Filter). + */ + void setNotFilteredThisNode(NodeId id); + + /** + * \brief Gives back the filter state (python::Filter::FilterStae) of the given node irrespectively of the state of the filter mode. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the ASG). + * \return Returns with the state of the filter. + */ + Filter::FilterState getFilterState(NodeId id) const; + + /** + * \brief Loads the filter. + * \param filename [in] The name of the filter file. + * \throw PythonException Throws PythonException if the filter contains more (or less) node than the factory does. + * \throw IOException Throws IOException if any error happens during the loading. + */ + void loadFilter(const std::string &filename); + + /** + * \brief Saves the filter. + * \param filename [in] The name of the filter file. + * \throw IOException Throws IOException if any error happens during the saving. + */ + void saveFilter(const std::string &filename) const; + + /** + * \internal + * \brief Filter out only the given node (without its children). + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException id the id is too large (larger than the size of the Filter). + */ + void setFilteredThisNodeOnly(NodeId id); + + /** + * \internal + * \brief Set only the given node to not filtered (without its children). + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException id the id is too large (larger than the size of the Filter). + */ + void setNotFilteredThisNodeOnly(NodeId id); + + public: + + + // ******************** ReverseEdges ******************** + + /** + * \brief Creates reverse edges (if it does not exist) and it can be used until disabling it. + */ + void enableReverseEdges(ReverseEdges::FuncPtrWithBaseParameterType newSelector = NULL); + + /** + * \brief Destroyed reverse edges (to use it again it must be rebuilt which takes some time). + */ + void disableReverseEdges(); + + /** + * \brief Gives back the reverse edge container which is assigned to this Factory (creates it if it does not exist). + * \return Returns with the const reference to the ReverseEdges. + */ + const ReverseEdges& getReverseEdges(ReverseEdges::FuncPtrWithBaseParameterType newSelector = NULL); + + /** + * \brief Checks whether the reverse edges has already been created or not. + * \return Returns true if ReverseEdges exists. + */ + bool getExistsReverseEdges() const; + + + // ******************** CreateNode ******************** + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \param ndk [in] The kind of the node. + * \throw PythonException If an invalid (or an abstract) NodeKind is given, PythonException is thrown. + * \return Pointer to the new node. + */ + base::Base* createNode(NodeKind ndk); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ArgumentList* createArgumentListNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::AttributeRef* createAttributeRefNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::BinaryArithmetic* createBinaryArithmeticNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::BinaryLogical* createBinaryLogicalNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Call* createCallNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::DictComp* createDictCompNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Dictionary* createDictionaryNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Ellipsis* createEllipsisNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ExpressionList* createExpressionListNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ExtSlice* createExtSliceNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::FloatNumber* createFloatNumberNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Generator* createGeneratorNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::GeneratorExpression* createGeneratorExpressionNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Identifier* createIdentifierNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::IfExpression* createIfExpressionNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ImagNumber* createImagNumberNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Index* createIndexNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::IntegerLiteral* createIntegerLiteralNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::KeyValue* createKeyValueNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Keyword* createKeywordNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Lambda* createLambdaNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::List* createListNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::ListComp* createListCompNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::LongInteger* createLongIntegerNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Set* createSetNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::SetComp* createSetCompNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Slice* createSliceNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::StringConversion* createStringConversionNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::StringLiteral* createStringLiteralNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::Subscription* createSubscriptionNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::UnaryOperation* createUnaryOperationNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + expression::YieldExpression* createYieldExpressionNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + module::Module* createModuleNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + module::Object* createObjectNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + module::Package* createPackageNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Alias* createAliasNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Assert* createAssertNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Assign* createAssignNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::AugAssign* createAugAssignNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::BaseSpecifier* createBaseSpecifierNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Break* createBreakNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::ClassDef* createClassDefNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Continue* createContinueNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Delete* createDeleteNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Exec* createExecNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::For* createForNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::FunctionDef* createFunctionDefNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Global* createGlobalNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Handler* createHandlerNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::If* createIfNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::ImportFrom* createImportFromNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::ImportStatement* createImportStatementNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Parameter* createParameterNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Pass* createPassNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Print* createPrintNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Raise* createRaiseNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Return* createReturnNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::Suite* createSuiteNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::TargetList* createTargetListNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::TryExcept* createTryExceptNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::TryFinal* createTryFinalNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::While* createWhileNode(); + + /** + * \brief Creates a new node, insert it into the container and return with it. + * \return Reference to the new node. + */ + statement::With* createWithNode(); + + /** + * \brief Flush the node Sizes to the default out + */ + static void printNodeSizes(); + + + // ******************** Unique node builders ******************** + + private: + + /** + * \internal + * \brief Creates a new node, insert it into the container and return with it. + * \param ndk [in] The kind of the node. + * \param id [in] The id of the new node. + * \throw PythonException If an invalid (or an abstract) NodeKind is given, PythonException is thrown. + * \return Reference to the new node. + */ + base::Base& createNode(NodeKind ndk, NodeId id); + + /** + * \internal + * \brief This function is call the alert list. + * \param node [in] The node which is going to destroy. + */ + void alertNodeDestroy(const base::Base* node); + + private: + + + // ******************** Private attributes ******************** + + /** \internal \brief Container where the pointers to nodes are stored. */ + Container container; + + /** \internal \brief Reference to the StringTable. */ + RefDistributorStrTable* strTable; + + /** \internal \brief The Filter of the ASG. */ + Filter *filter; + + /** \internal \brief Stores whether the filter is turned on or off. */ + bool filterOn; + + /** \internal \brief Pointer to the ReverseEdges. */ + ReverseEdges *reverseEdges; + + typedef struct EdgeIdentifier { + EdgeIdentifier(base::Base* edgeBegin, NodeId edgeEnd, EdgeKind edgekind) : edgeBegin(edgeBegin), edgeEnd(edgeEnd), edgekind(edgekind) {} + base::Base* edgeBegin; + NodeId edgeEnd; + EdgeKind edgekind; + } EdgeIdentifier; + + /** \internal \brief The subcripted object for the node destroy. */ + std::list registeredPointerStorage; + + /** \internal \brief Pointer to the root of the ASG. */ + module::Package *root; + + /** \internal \brief List of the ids of the deleted nodes. */ + std::list deletedNodeIdList; + + friend class VisitorFilter; + + friend class base::Base; + friend class base::Comment; + friend class base::Docstring; + friend class base::Named; + friend class base::Positioned; + friend class expression::ArgumentList; + friend class expression::AttributeRef; + friend class expression::Binary; + friend class expression::BinaryArithmetic; + friend class expression::BinaryLogical; + friend class expression::Call; + friend class expression::DictComp; + friend class expression::Dictionary; + friend class expression::Ellipsis; + friend class expression::Expression; + friend class expression::ExpressionList; + friend class expression::ExtSlice; + friend class expression::FloatNumber; + friend class expression::Generator; + friend class expression::GeneratorExpression; + friend class expression::Identifier; + friend class expression::IfExpression; + friend class expression::ImagNumber; + friend class expression::Index; + friend class expression::IntegerLiteral; + friend class expression::KeyValue; + friend class expression::Keyword; + friend class expression::Lambda; + friend class expression::List; + friend class expression::ListComp; + friend class expression::Literal; + friend class expression::LongInteger; + friend class expression::Set; + friend class expression::SetComp; + friend class expression::Slice; + friend class expression::Slicing; + friend class expression::StringConversion; + friend class expression::StringLiteral; + friend class expression::Subscription; + friend class expression::Unary; + friend class expression::UnaryOperation; + friend class expression::YieldExpression; + friend class module::Module; + friend class module::Object; + friend class module::Package; + friend class statement::Alias; + friend class statement::Assert; + friend class statement::Assign; + friend class statement::AugAssign; + friend class statement::BaseSpecifier; + friend class statement::Break; + friend class statement::ClassDef; + friend class statement::CompoundStatement; + friend class statement::Continue; + friend class statement::Delete; + friend class statement::Exec; + friend class statement::For; + friend class statement::FunctionDef; + friend class statement::Global; + friend class statement::Handler; + friend class statement::If; + friend class statement::ImportFrom; + friend class statement::ImportStatement; + friend class statement::Iteration; + friend class statement::Parameter; + friend class statement::Pass; + friend class statement::Print; + friend class statement::Raise; + friend class statement::Return; + friend class statement::SimpleStatement; + friend class statement::Statement; + friend class statement::Suite; + friend class statement::TargetList; + friend class statement::Try; + friend class statement::TryExcept; + friend class statement::TryFinal; + friend class statement::While; + friend class statement::With; + friend class type::DictType; + friend class type::ReferenceType; + friend class type::SequenceType; + friend class type::SimpleType; + friend class type::Type; + + protected: + std::map simpleType; + std::map sequenceType; + std::map referenceType; + NodeId dictType; + + public: + + type::SimpleType& createSimpleType(SimpleTypeKind kind); + + type::SequenceType& createSequenceType(SequenceTypeKind kind); + + type::DictType& createDictType(); + + type::ReferenceType& createReferenceType(NodeId refersTo); + + base::Docstring& createDocstring(); + + base::Comment& createComment(); + + }; // Factory + + +}}} +#endif + diff --git a/lib/python/inc/Filter.h b/lib/python/inc/Filter.h new file mode 100644 index 0000000..f6833e9 --- /dev/null +++ b/lib/python/inc/Filter.h @@ -0,0 +1,148 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_FILTER_H_ +#define _PYTHON_FILTER_H_ + +#include "python/inc/python.h" + +/** +* \file Filter.h +* \brief Contains declaration of Filter class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Provides filtering mechanism for the ASG. + */ + class Filter { + public: + + /** + * \brief The possible states of the Filter. + */ + enum FilterState { + + /** \brief The node is filtered. */ + Filtered, + + /** \brief The node and all of its anchestors are not filtered. */ + NotFiltered + }; + + protected: + + /** + * \internal + * \brief Constructor. + * \param fact [in] Reference to the Factory. + */ + Filter(Factory& fact); + + /** + * \brief Initializes the Filter. + */ + void initializeFilter(); + + /** + * \brief Tells whether the node is filtered or not. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + * \return Returns true if the node with the given id is filtered. + */ + bool getIsFiltered(NodeId id) const; + + /** + * \brief Filters out the given node and all of its descendants. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + */ + void setFiltered(NodeId id); + + /** + * \brief Sets the state of the node, all of its descendants and all of its ancestors to not filtered. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + */ + void setNotFiltered(NodeId id); + + /** + * \brief Sets the state of the node and all of its ancestors to not filtered. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + */ + void setNotFilteredThisNode(NodeId id); + + /** + * \internal + * \brief Filter out only the given node (without its children). + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + */ + void setFilteredThisNodeOnly(NodeId id); + + /** + * \internal + * \brief Sets the state of the given node (without its children) to not filtered. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + */ + void setNotFilteredThisNodeOnly(NodeId id); + + /** + * \internal + * \brief Gives back the state of the node. + * \param id [in] The id of the node. + * \throw PythonException Throws PythonException if the id is too large (larger than the size of the Filter). + * \return Returns the state of the node. + */ + FilterState getFilterState(NodeId id) const; + + /** + * \internal + * \brief Saves the filter. + * \param io [in] The filter is saved into "io". + */ + void save(io::BinaryIO *io) const; + + /** + * \internal + * \brief Loads the filter. + * \param io [in] The filter is loaded from "io". + */ + void load(io::BinaryIO *io); + + /** \internal \brief Type definition for Container. */ + typedef std::vector Container; + + /** \internal \brief Contains the states of the nodes. */ + Container container; + + /** \internal \brief Reference to the factory. */ + Factory& factory; + + friend class Factory; + + }; // Filter + + +}}} +#endif + diff --git a/lib/python/inc/Forwards.h b/lib/python/inc/Forwards.h new file mode 100644 index 0000000..ed9302e --- /dev/null +++ b/lib/python/inc/Forwards.h @@ -0,0 +1,151 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Forwards_H_ +#define _PYTHON_Forwards_H_ + +/** +* \file Forwards.h +* \brief Contains forward declarations of the classes. +*/ + +namespace columbus { namespace python { namespace asg { + + class Algorithm; + class AlgorithmPreorder; + class ReverseEdges; + + class Visitor; + class VisitorAbstractNodes; + class VisitorPYTHONML; + class VisitorFilter; + class VisitorReverseEdges; + class VisitorSave; + + template + class ListIterator; + class Factory; + class Filter; + class Range; + class RangeListIterator; + + namespace base { + class Base; + class Comment; + class Docstring; + class Named; + class Positioned; + } + + namespace expression { + class ArgumentList; + class AttributeRef; + class Binary; + class BinaryArithmetic; + class BinaryLogical; + class Call; + class DictComp; + class Dictionary; + class Ellipsis; + class Expression; + class ExpressionList; + class ExtSlice; + class FloatNumber; + class Generator; + class GeneratorExpression; + class Identifier; + class IfExpression; + class ImagNumber; + class Index; + class IntegerLiteral; + class KeyValue; + class Keyword; + class Lambda; + class List; + class ListComp; + class Literal; + class LongInteger; + class Set; + class SetComp; + class Slice; + class Slicing; + class StringConversion; + class StringLiteral; + class Subscription; + class Unary; + class UnaryOperation; + class YieldExpression; + } + + namespace module { + class Module; + class Object; + class Package; + } + + namespace statement { + class Alias; + class Assert; + class Assign; + class AugAssign; + class BaseSpecifier; + class Break; + class ClassDef; + class CompoundStatement; + class Continue; + class Delete; + class Exec; + class For; + class FunctionDef; + class Global; + class Handler; + class If; + class ImportFrom; + class ImportStatement; + class Iteration; + class Parameter; + class Pass; + class Print; + class Raise; + class Return; + class SimpleStatement; + class Statement; + class Suite; + class TargetList; + class Try; + class TryExcept; + class TryFinal; + class While; + class With; + } + + namespace type { + class DictType; + class ReferenceType; + class SequenceType; + class SimpleType; + class Type; + } + + +}}} + +#endif + diff --git a/lib/python/inc/ListIterator.h b/lib/python/inc/ListIterator.h new file mode 100644 index 0000000..cb445de --- /dev/null +++ b/lib/python/inc/ListIterator.h @@ -0,0 +1,286 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ListIterator_H_ +#define _PYTHON_ListIterator_H_ + +#include "python/inc/python.h" +#include "common/inc/sllist.h" + +/** +* \file ListIterator.h +* \brief Contains declaration of the internal ListIterator class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Iterator, which can be used to iterate through the edges of the nodes. + */ + template + class ListIteratorBase { + + protected: + + /** \brief Type definition to store node ids in a container. */ + typedef literateprograms::sllist Container; + + /** + * \internal + * \brief Non-public constructor, which creates a usable new iterator. + * \param container [in] The container which stores the ids of the nodes the iteration is going on it. + * \param factory [in] The Factory. + * \param createAsBegin [in] Create iterator begin or end. + */ + ListIteratorBase(const Container *container, const Factory* factory, bool createAsBegin); + + public: + + /** + * \brief Creates an ListIteratorBase by copying the one given in parameter. + * \param otherIt [in] The other ListIteratorBase which initializes this one. + */ + ListIteratorBase(const ListIteratorBase &otherIt); + + /** + * \brief Destructor which safely destroys the ListIteratorBase. + */ + virtual ~ListIteratorBase(); + + /** + * \brief Copies a ListIteratorBase. + * \param otherIt [in] The other ListIteratorBase which initializes this one. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns a reference to a ListIteratorBase. + */ + ListIteratorBase& operator=(const ListIteratorBase& otherIt); + + /** + * \brief This is a * operator of ListIteratorBase. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns a reference to a node. + */ + virtual const T& operator*(); + + /** + * \brief This is a -> operator of ListIteratorBase. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns a pointer to a node. + */ + virtual const T* operator->(); + + /** + * \brief This is a ++ operator of ListIteratorBase. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns a reference to a ListIteratorBase. + */ + virtual ListIteratorBase& operator++(); + + /** + * \brief This is a -- operator of ListIteratorBase. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns a reference to a ListIteratorBase. + */ + virtual ListIteratorBase& operator--(); + + /** + * \brief This is a == operator of ListIteratorBase. + * \param rhs [in] The iterator is compared to it. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Return true if the both iteratis is same + */ + virtual bool operator==(const ListIteratorBase& rhs) const; + + /** + * \brief This is a != operator of ListIteratorBase. + * \param rhs [in] The iterator is compared to it. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Return true if the both iteratis is not same + */ + virtual bool operator!=(const ListIteratorBase& rhs) const; + + /** + * \brief Compares the two iterators. + * \param otherIt [in] The iterator is compared to it. + * \throw PythonInvalidIteratorException If the iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns true if the two iterators would give back the same elements with the next previous() and next() calls. + */ + virtual bool equals(const ListIteratorBase& otherIt) const; + + private: + /** + * \brief Returns the next element in the list. + * \throw PythonNoSuchElementException If the iteration has no next element PythonNoSuchElementException is thrown. + * \throw PythonInvalidIteratorException If the iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns the next element in the list. + * + * This method may be called repeatedly to iterate through the list, or intermixed with calls to previous() to go back and forth. + * (Note that alternating calls to next() and previous() will return the same element repeatedly.) + */ + virtual void next(); + + /** + * \brief Returns the previous element in the list. + * \throw PythonNoSuchElementException If the iteration has no previous element PythonNoSuchElementException is thrown. + * \throw PythonInvalidIteratorException If the iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns the previous element in the list. + * + * This method may be called repeatedly to iterate through the list backwards, or intermixed with calls to next() to go back and forth. + * (Note that alternating calls to next() and previous() will return the same element repeatedly.) + */ + virtual void previous(); + + /** + * \internal + * \brief Searches for the next element. + * \param it [in] The iterator whose next element is searched. + * \return Returns the next element (or the end of the container if there is no next element). + */ + typename Container::const_iterator findNext(const typename Container::const_iterator& it); + + /** + * \internal + * \brief Searches for the next not filtered, element. + * \param it [in] The iterator whose next element is searched. + * \return Returns the next not filtered, element (or the end of the container if there is no next element). + */ + typename Container::const_iterator findNextNotFiltered(const typename Container::const_iterator& it); + + /** + * \internal + * \brief Gives back the next element. + * \throw PythonInvalidIteratorException If the iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns the next element (or the end of the container if there is no next element). + */ + typename Container::const_iterator nextItem(); + + /** + * \internal + * \brief Searches for the previous not deleted element. + * \param it [in] The iterator whose previous element is searched. + * \return Returns the previous not deleted element (or the end of the container if there is no previous element). + */ + typename Container::const_iterator findPrevious(const typename Container::const_iterator& it); + + /** + * \internal + * \brief Searches for the previous not filtered, not filtered, not deleted element. + * \param it [in] The iterator whose previous element is searched. + * \return Returns the previous not filtered, not deleted element (or the end of the container if there is no previous element). + */ + typename Container::const_iterator findPreviousNotFiltered(const typename Container::const_iterator& it); + + /** + * \internal + * \brief Gives back the previous element. + * \throw PythonInvalidIteratorException If the iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns the previous element (or the end of the container if there is no previous element). + */ + typename Container::const_iterator previousItem(); + + protected: + + /** \internal \brief Pointer to the Factory. */ + const Factory* fact; + + /** \internal \brief Pointer to the Container the ids stored in. */ + const Container* container; + + /** \internal \brief Inner iterator of the Container. */ + typename Container::const_iterator it; + + /** \internal \brief Flag for invalidate. */ + bool invalid; + + }; // ListIteratorBase + + /** + * \brief Iterator, which can be used to iterate through the edges of the nodes. + */ + template + class ListIterator : public ListIteratorBase { + + protected: + + /** \brief Type definition to store node ids in a container. */ + typedef typename ListIteratorBase::Container Container; + + /** + * \internal + * \brief Non-public constructor, which creates a usable new iterator. + * \param container [in] The container which stores the ids of the nodes the iteration is going on it. + * \param factory [in] The Factory. + * \param createAsBegin [in] Create iterator begin or end. + */ + ListIterator(const Container *container, const Factory* factory, bool createAsBegin); + + public: + + /** + * \brief Destructor which safely destroys the ListIterator. + */ + virtual ~ListIterator(); + + /** + * \brief Creates an ListIterator by copying the one given in parameter. + * \param otherIt [in] The other ListIterator which initializes this one. + */ + ListIterator(const ListIterator& otherIt); + + /** + * \brief Copies a ListIterator. + * \param otherIt [in] The other ListIterator which initializes this one. + * \throw PythonInvalidIteratorException If the other iterator is invalid PythonInvalidIteratorException is thrown. + * \return Returns a reference to a ListIterator. + */ + ListIterator& operator=(const ListIterator& otherIt); + + friend class ReverseEdges; + + // ---------- List of nodes having edge containers ---------- + + friend class base::Positioned; + friend class expression::ArgumentList; + friend class expression::DictComp; + friend class expression::Dictionary; + friend class expression::ExpressionList; + friend class expression::ExtSlice; + friend class expression::Generator; + friend class expression::GeneratorExpression; + friend class expression::Lambda; + friend class expression::List; + friend class expression::ListComp; + friend class expression::Set; + friend class expression::SetComp; + friend class module::Module; + friend class module::Object; + friend class module::Package; + friend class statement::ClassDef; + friend class statement::FunctionDef; + friend class statement::Global; + friend class statement::ImportStatement; + friend class statement::Suite; + friend class statement::TargetList; + friend class statement::TryExcept; + }; // ListIterator + + +}}} +#endif + diff --git a/lib/python/inc/PythonCollector.h b/lib/python/inc/PythonCollector.h new file mode 100644 index 0000000..afb62cf --- /dev/null +++ b/lib/python/inc/PythonCollector.h @@ -0,0 +1,35 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_COLLECTOR_H_ +#define _PYTHON_COLLECTOR_H_ + +#include +#include + +namespace columbus { namespace python { + + void collectPythonPackages(const std::string& projectBaseDir, const std::string& ignore, std::list& packagePaths); + + void collectPackageFiles(const std::string& projectBaseDir, const std::string& ignore, std::list& filePaths); + +}} + +#endif diff --git a/lib/python/inc/PythonException.h b/lib/python/inc/PythonException.h new file mode 100644 index 0000000..ac59b9a --- /dev/null +++ b/lib/python/inc/PythonException.h @@ -0,0 +1,139 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_EXCEPTION_H_ +#define _PYTHON_EXCEPTION_H_ + +#include "python/inc/python.h" + +/** +* \file PythonException.h +* \brief Contains declaration for the common (base) class of all python Exceptions. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief General (base) class for all python::Exception. + */ + class PythonException : public columbus::Exception { + public: + /** + * \brief Constructor. + * \param location [in] The location of the exception (the "place" where the exception was thrown). + * \param message [in] The cause of the exception. + */ + PythonException(const std::string &location, const std::string &message); + + /** + * \brief Destructor. + */ + virtual ~PythonException(); + + /** + * \brief Gives back the name of the python::PythonException class. + * \return Returns the name of the python::PythonException class. + */ + virtual const std::string getClassName() const; + + }; // PythonException + + + /** + * \brief Thrown by ListIterator if the iterator is invalid. + */ + class PythonInvalidIteratorException : public PythonException { + public: + /** + * \brief Constructor. + * \param location [in] The location of the exception (the "place" where the exception was thrown). + * \param message [in] The cause of the exception. + */ + PythonInvalidIteratorException(const std::string &location, const std::string &message); + + /** + * \brief Destructor. + */ + virtual ~PythonInvalidIteratorException(); + + /** + * \brief Gives back the name of the Python::PythonInvalidIteratorException class. + * \return Returns the name of the Python::PythonInvalidIteratorException class. + */ + virtual const std::string getClassName() const; + + }; // PythonInvalidIteratorException + + + /** + * \brief Thrown by ListIterator if illegal operation is executed on an iterator. + */ + class PythonIllegalStateException : public PythonException { + public: + /** + * \brief Constructor. + * \param location [in] The location of the exception (the "place" where the exception was thrown). + * \param message [in] The cause of the exception. + */ + PythonIllegalStateException(const std::string &location, const std::string &message); + + /** + * \brief Destructor. + */ + virtual ~PythonIllegalStateException(); + + /** + * \brief Gives back the name of the Python::IllegalStateException class. + * \return Returns the name of the Python::IllegalStateException class. + */ + virtual const std::string getClassName() const; + + }; // PythonIllegalStateException + + + /** + * \brief Thrown by ListIterator if next()(or pervious() ) is called and there is no next (previous) element. + */ + class PythonNoSuchElementException : public PythonException { + public: + /** + * \brief Constructor. + * \param location [in] The location of the exception (the "place" where the exception was thrown). + * \param message [in] The cause of the exception. + */ + PythonNoSuchElementException(const std::string &location, const std::string &message); + + /** + * \brief Destructor. + */ + virtual ~PythonNoSuchElementException(); + + /** + * \brief Gives back the name of the python::PythonNoSuchElementException class. + * \return Returns the name of the python::PythonNoSuchElementException class. + */ + virtual const std::string getClassName() const; + + }; // PythonNoSuchElementException + + + +}}} +#endif + diff --git a/lib/python/inc/Range.h b/lib/python/inc/Range.h new file mode 100644 index 0000000..5f55d91 --- /dev/null +++ b/lib/python/inc/Range.h @@ -0,0 +1,141 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_RANGE_H_ +#define _PYTHON_RANGE_H_ + +#include "python/inc/python.h" + +/** +* \file Range.h +* \brief Contains declaration of Range class. +*/ + +namespace columbus { namespace python { namespace asg { + + // ---------- Range ---------- + + class Range { + public: + typedef struct { + Key path; + unsigned line; + unsigned col; + unsigned endLine; + unsigned endCol; + } PositionInfo; + + Range(); + Range(StrTable &strTable); + Range(StrTable &strTable, const std::string& pathString, unsigned line, unsigned col, unsigned endLine, unsigned endCol); + const std::string& getPath() const; + Key getPathKey() const; + + unsigned getLine() const; + unsigned getCol() const; + unsigned getEndLine() const; + unsigned getEndCol() const; + void setPath(const std::string& s); + void setLine(unsigned i); + void setCol(unsigned i); + void setEndLine(unsigned i); + void setEndCol(unsigned i); + protected: + Range(StrTable &strTable, Key pathKey, unsigned line, unsigned col, unsigned endLine, unsigned endCol); + Range(StrTable &strTable, PositionInfo _positionInfo); + void setPathKey(Key pathKey); + + StrTable *strTable; + PositionInfo positionInfo; + + friend class base::Positioned; + friend class Factory; + }; + + + // ---------- RangeListIterator ---------- + + class RangeListIterator { + public: + /** \brief Type definition to store Ranges in a list container. */ + typedef std::list Container; + + /** \brief Type definition to store pointers to RangeListIterators in a list container. */ + typedef std::list IteratorContainer; + + protected: + /** + * \internal + * \brief The possible states of an iterator. + */ + enum op { + op_None, ///< \internal \brief None of the add(), remove(), next() or previous() was called. + op_Add, ///< \internal \brief The last call was an add(). + op_Remove, ///< \internal \brief The last call was a remove(). + op_Next, ///< \internal \brief The last call was a previous(). + op_Previous, ///< \internal \brief The last call was a previous(). + op_Invalidated ///< \internal \brief The node containing the container of the iterator is deleted. + }; + + RangeListIterator(Container *container, IteratorContainer *it); + Container::iterator nextItem() const; + Container::iterator previousItem() const; + Container::iterator safeRemove(const Container::iterator& it); + void invalidate(); + void add(const Range& r); + void remove(); + + public: + RangeListIterator(const RangeListIterator &rli); + RangeListIterator(); + RangeListIterator& operator=(const RangeListIterator &rli); + ~RangeListIterator(); + const Range& next(); + const Range& previous(); + bool hasNext() const; + bool hasPrevious() const; + bool equals(const RangeListIterator& it) const; + + protected: + Container *container; ///< \internal \brief Pointer to the Container. + Container::iterator it; ///< \internal \brief Inner iterator of the Container. + IteratorContainer *iterators; ///< \internal \brief Pointer to the list of the iterators of the Container. + op lastOp; ///< \internal \brief Inner state of the iterator. + + friend class base::Positioned; + }; + + typedef struct { + RangeListIterator::Container container; + RangeListIterator::IteratorContainer iterators; + } RangeList; + + typedef union { + Range::PositionInfo posInfo; + struct { + RangeListIterator::Container *container; + RangeListIterator::IteratorContainer *iterators; + } ranges; + } MultiRange; + + +}}} +#endif + diff --git a/lib/python/inc/ReverseEdges.h b/lib/python/inc/ReverseEdges.h new file mode 100644 index 0000000..ba96021 --- /dev/null +++ b/lib/python/inc/ReverseEdges.h @@ -0,0 +1,284 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_REVERSEEDGES_H_ +#define _PYTHON_REVERSEEDGES_H_ + +#include "python/inc/python.h" + +/** +* \file ReverseEdges.h +* \brief Contains declaration of ReverseEdges class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Collects the inverse relation of any "one way" defined edges. + * The reverse relation tells for a given node the non trivial nodes + * for which it has an incoming edge from. + */ + class ReverseEdges { + public: + + /** \internal \brief Type which will be use to select node types to revers edges. */ + typedef bool(*FuncPtrWithBaseParameterType)(const base::Base*); + + protected: + + /** \internal \brief The nodes of the same edges. */ + typedef ListIterator::Container NodeListType; + + /** \internal \brief Type which represent one node and its edges. */ + typedef std::map NodeEdgesType; + + /** \internal \brief Type which stores for all nodes their reversed edges. */ + typedef std::vector RevEdgesContainer; + + /** + * \internal + * \brief Constructor. + * \param factory [in] Revesred edges stored for this Factory. + */ + ReverseEdges(const Factory* factory, FuncPtrWithBaseParameterType selectorFunction = NULL); + + /** + * \internal + * \brief Destructor. + */ + ~ReverseEdges(); + + private: + + /** + * \internal + * \brief Copy constructor.It not implemented it make linker error so it disable the copy of this object + */ + ReverseEdges(const ReverseEdges&); + + /** + * \internal + * \brief It not implemented it make linker error so it disable the copy of this object. + */ + ReverseEdges& operator=(ReverseEdges); + + public: + + /** + * \brief Gives back a ListIterator for the given node with the given edge kind. + * \param id [in] The id of the node whose edges will be iterated. + * \param edge [in] The kind of the edge. + * \throw PythonException Throws exception if there is node for the id or the edge kind is invalid for this node (it is not invalid if the node can have such edge but it has not got at that moment). + * \return Returns with a iterator which iterates the node's reverse edges of the given kind. + */ + const ListIterator constIteratorBegin(NodeId id, EdgeKind edge) const; + + /** + * \brief Gives back a ListIterator for the given node with the given edge kind. + * \param id [in] The id of the node whose edges will be iterated. + * \param edge [in] The kind of the edge. + * \throw PythonException Throws exception if there is node for the id or the edge kind is invalid for this node (it is not invalid if the node can have such edge but it has not got at that moment). + * \return Returns with a iterator which iterates the node's reverse edges of the given kind. + */ + const ListIterator constIteratorEnd(NodeId id, EdgeKind edge) const; + + /** + * \brief Tells all kind of edges the node actually has. + * \param id [in] The id of the node whose edges we want to know. + * \param edges [out] A vector containing all kind of edges the node has (the vector is cleared before inserting new elements). + * \throw PythonException Throws exception if the node does not exist. + */ + void getAllExistingEdges(NodeId id, std::vector& edges) const; + + /** + * \brief Tells all kind of edges the node actually has. + * \param id [in] The id of the node whose edges we want to know. + * \param edges [out] A set containing all kind of edges the node has (the vector is cleared before inserting new elements). + * \throw PythonException Throws exception if the node does not exist. + */ + void getAllExistingEdges(NodeId id, std::set& edges) const; + + /** + * \brief Tells all kind of edges this kind of node can have. + * \param kind [in] The kind of the node whose edges we want to know. + * \param edges [out] A vector containing all kind of edges this kind of node can have (the vector is cleared before inserting new elements). + * \throw PythonException Throws exception if the kind is invalid. + */ + void getAllPossibleEdges(NodeKind kind, std::vector& edges) const; + + /** + * \brief Tells all kind of edges this kind of node can have. + * \param kind [in] The kind of the node whose edges we want to know. + * \param edges [out] A set containing all kind of edges this kind of node can have (the vector is cleared before inserting new elements). + * \throw PythonException Throws exception if the kind is invalid. + */ + void getAllPossibleEdges(NodeKind kind, std::set& edges) const; + + private: + + /** + * \internal + * \brief Inserts a node (if the node has already been inserted nothing happens, otherwise the node is inserted without its edges). + * \param id [in] The id of the node which will be inserted. + * \throw PythonException Throws Exception if the node does not exist. + */ + void insertNode(NodeId id); + + /** + * \internal + * \brief Removes a node (with out without its edges?). + * \param id [in] The id of the node which will be removed. + * \throw PythonException Throws PythonException if there is no node for the id. + */ + void removeNode(NodeId id); + + /** + * \internal + * \brief Inserts an edge. + * \param from [in] The reversed edge starts from that node (originally it was the target of the edge). + * \param to [in] The target of the reversed edge (originally it was the start of the edge). + * \param edge [in] The kind of the edge. + * \throw PythonException Throws PythonException if the from node is not valid. + */ + void insertEdge(const base::Base* from, const base::Base* to, EdgeKind edge); + + /** + * \internal + * \brief Inserts an edge. + * \param from [in] The reversed edge starts from that node (originally it was the target of the edge). + * \param to [in] The target of the reversed edge (originally it was the start of the edge). + * \param edge [in] The kind of the edge. + * \throw PythonException Throws PythonException if the from node is not valid. + */ + void insertEdge(NodeId from, NodeId to, EdgeKind edge); + + /** + * \internal + * \brief Removes an edge. + * \param from [in] The reversed edge starts from that node (originally it was the target of the edge). + * \param to [in] The target of the reversed edge (originally it was the start of the edge). + * \param edge [in] The kind of the edge. + * \throw PythonException todo. + */ + void removeEdge(NodeId from, NodeId to, EdgeKind edge); + + /** \internal \brief Pointer to the Factory (the edges belong to it). */ + const Factory* fact; + + /** \internal \brief Pointer to selector function. */ + FuncPtrWithBaseParameterType selectorFunc; + + /** \internal \brief The Container (the edges are stored in it). */ + RevEdgesContainer reContainer; + + /** \internal \brief The possible edges by nodes. */ + static bool possibleEdges[83][102]; + + friend class Factory; + friend class VisitorReverseEdges; + + friend class base::Base; + friend class base::Comment; + friend class base::Docstring; + friend class base::Named; + friend class base::Positioned; + friend class expression::ArgumentList; + friend class expression::AttributeRef; + friend class expression::Binary; + friend class expression::BinaryArithmetic; + friend class expression::BinaryLogical; + friend class expression::Call; + friend class expression::DictComp; + friend class expression::Dictionary; + friend class expression::Ellipsis; + friend class expression::Expression; + friend class expression::ExpressionList; + friend class expression::ExtSlice; + friend class expression::FloatNumber; + friend class expression::Generator; + friend class expression::GeneratorExpression; + friend class expression::Identifier; + friend class expression::IfExpression; + friend class expression::ImagNumber; + friend class expression::Index; + friend class expression::IntegerLiteral; + friend class expression::KeyValue; + friend class expression::Keyword; + friend class expression::Lambda; + friend class expression::List; + friend class expression::ListComp; + friend class expression::Literal; + friend class expression::LongInteger; + friend class expression::Set; + friend class expression::SetComp; + friend class expression::Slice; + friend class expression::Slicing; + friend class expression::StringConversion; + friend class expression::StringLiteral; + friend class expression::Subscription; + friend class expression::Unary; + friend class expression::UnaryOperation; + friend class expression::YieldExpression; + friend class module::Module; + friend class module::Object; + friend class module::Package; + friend class statement::Alias; + friend class statement::Assert; + friend class statement::Assign; + friend class statement::AugAssign; + friend class statement::BaseSpecifier; + friend class statement::Break; + friend class statement::ClassDef; + friend class statement::CompoundStatement; + friend class statement::Continue; + friend class statement::Delete; + friend class statement::Exec; + friend class statement::For; + friend class statement::FunctionDef; + friend class statement::Global; + friend class statement::Handler; + friend class statement::If; + friend class statement::ImportFrom; + friend class statement::ImportStatement; + friend class statement::Iteration; + friend class statement::Parameter; + friend class statement::Pass; + friend class statement::Print; + friend class statement::Raise; + friend class statement::Return; + friend class statement::SimpleStatement; + friend class statement::Statement; + friend class statement::Suite; + friend class statement::TargetList; + friend class statement::Try; + friend class statement::TryExcept; + friend class statement::TryFinal; + friend class statement::While; + friend class statement::With; + friend class type::DictType; + friend class type::ReferenceType; + friend class type::SequenceType; + friend class type::SimpleType; + friend class type::Type; + }; // ReverseEdges + + +}}} +#endif + diff --git a/lib/python/inc/Types.h b/lib/python/inc/Types.h new file mode 100644 index 0000000..ef4a70b --- /dev/null +++ b/lib/python/inc/Types.h @@ -0,0 +1,313 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_TYPES_H_ +#define _PYTHON_TYPES_H_ + +/** +* \file Types.h +* \brief Contains declaration of internal types. +*/ + +namespace columbus { namespace python { namespace asg { + enum AssignmentKind { + askAdd, + askSub, + askMult, + askDiv, + askMod, + askPow, + askLShift, + askRShift, + askBitOr, + askBitXor, + askBitAnd, + askFloorDiv, + askLAST + }; + + enum BinaryArithmeticKind { + bakMultiplication, + bakDivision, + bakFloorDivision, + bakModulo, + bakAddition, + bakSubtraction, + bakPow, + bakLShift, + bakRShift, + bakBitOr, + bakBitXor, + bakBitAnd, + bakLAST + }; + + enum BinaryLogicalKind { + blkEq, + blkNotEq, + blkLt, + blkLtE, + blkGt, + blkGtE, + blkIs, + blkIsNot, + blkIn, + blkNotIn, + blkAnd, + blkOr, + blkLAST + }; + + enum OriginKind { + orkAnalyzer, + orkGenerator, + orkLAST + }; + + enum ParameterKind { + pmkNormal, + pmkKwarg, + pmkVararg, + pmkLAST + }; + + enum SequenceTypeKind { + sekString, + sekList, + sekTuple, + sekLAST + }; + + enum SimpleTypeKind { + stkInteger, + stkLong, + stkFloat, + stkImaginary, + stkBoolean, + stkNone, + stkUnknown, + stkLAST + }; + + enum UnaryKind { + unkInvert, + unkNot, + unkPlus, + unkMinus, + unkLAST + }; + + enum NodeKind { + ndkBase, + ndkComment, + ndkDocstring, + ndkNamed, + ndkPositioned, + ndkArgumentList, + ndkAttributeRef, + ndkBinary, + ndkBinaryArithmetic, + ndkBinaryLogical, + ndkCall, + ndkDictComp, + ndkDictionary, + ndkEllipsis, + ndkExpression, + ndkExpressionList, + ndkExtSlice, + ndkFloatNumber, + ndkGenerator, + ndkGeneratorExpression, + ndkIdentifier, + ndkIfExpression, + ndkImagNumber, + ndkIndex, + ndkIntegerLiteral, + ndkKeyValue, + ndkKeyword, + ndkLambda, + ndkList, + ndkListComp, + ndkLiteral, + ndkLongInteger, + ndkSet, + ndkSetComp, + ndkSlice, + ndkSlicing, + ndkStringConversion, + ndkStringLiteral, + ndkSubscription, + ndkUnary, + ndkUnaryOperation, + ndkYieldExpression, + ndkModule, + ndkObject, + ndkPackage, + ndkAlias, + ndkAssert, + ndkAssign, + ndkAugAssign, + ndkBaseSpecifier, + ndkBreak, + ndkClassDef, + ndkCompoundStatement, + ndkContinue, + ndkDelete, + ndkExec, + ndkFor, + ndkFunctionDef, + ndkGlobal, + ndkHandler, + ndkIf, + ndkImportFrom, + ndkImportStatement, + ndkIteration, + ndkParameter, + ndkPass, + ndkPrint, + ndkRaise, + ndkReturn, + ndkSimpleStatement, + ndkStatement, + ndkSuite, + ndkTargetList, + ndkTry, + ndkTryExcept, + ndkTryFinal, + ndkWhile, + ndkWith, + ndkDictType, + ndkReferenceType, + ndkSequenceType, + ndkSimpleType, + ndkType, + ndkLAST + }; + + enum EdgeKind { + edkPositioned_Comments, + edkArgumentList_HasPositionalArguments, + edkArgumentList_HasDictionary, + edkArgumentList_HasKeyword, + edkArgumentList_HasTuple, + edkBinary_HasLeftExpression, + edkBinary_HasRightExpression, + edkCall_HasArgumentList, + edkCall_RefersTo, + edkDictComp_HasKeyValue, + edkDictComp_HasGenerator, + edkDictionary_HasKeyValue, + edkExpression_HasType, + edkExpressionList_HasExpression, + edkExtSlice_HasItem, + edkGenerator_HasCondition, + edkGenerator_HasIter, + edkGenerator_HasTarget, + edkGeneratorExpression_HasExpression, + edkGeneratorExpression_HasGenerator, + edkIdentifier_RefersTo, + edkIfExpression_HasBody, + edkIfExpression_HasElseBody, + edkIfExpression_HasTest, + edkKeyValue_HasKey, + edkKeyValue_HasValue, + edkKeyword_HasKey, + edkKeyword_HasValue, + edkLambda_HasObject, + edkLambda_HasParameter, + edkLambda_HasExpression, + edkList_HasExpression, + edkListComp_HasExpression, + edkListComp_HasGenerator, + edkSet_HasExpression, + edkSetComp_HasExpression, + edkSetComp_HasGenerator, + edkSlice_HasLowerBound, + edkSlice_HasStride, + edkSlice_HasUpperBound, + edkStringConversion_HasExpressionList, + edkSubscription_HasSlicing, + edkUnary_HasExpression, + edkYieldExpression_HasYieldExpression, + edkModule_HasObject, + edkModule_HasStatement, + edkModule_Docstring, + edkObject_RefersTo, + edkObject_HasType, + edkPackage_HasModule, + edkPackage_HasPackage, + edkAlias_RefersTo, + edkAssert_HasMsgExpression, + edkAssert_HasTestExpression, + edkAssign_HasExpression, + edkAssign_HasTargetList, + edkBaseSpecifier_HasName, + edkBaseSpecifier_DerivesFrom, + edkClassDef_HasObject, + edkClassDef_HasBaseSpecifier, + edkClassDef_HasDecorator, + edkClassDef_RefersTo, + edkClassDef_Docstring, + edkCompoundStatement_HasBody, + edkDelete_HasTargetList, + edkExec_HasExpression, + edkExec_HasGlobals, + edkExec_HasLocals, + edkFor_HasExpressionList, + edkFor_HasTargetList, + edkFunctionDef_HasDecorator, + edkFunctionDef_HasObject, + edkFunctionDef_HasParameter, + edkFunctionDef_RefersTo, + edkFunctionDef_ReturnType, + edkFunctionDef_Docstring, + edkGlobal_HasIdentifier, + edkHandler_HasName, + edkHandler_HasExceptBody, + edkHandler_HasType, + edkIf_HasElseBody, + edkIf_HasTestExpression, + edkImportStatement_HasAlias, + edkIteration_HasElseBody, + edkParameter_HasDefaultValue, + edkParameter_RefersTo, + edkPrint_HasExpressionList, + edkPrint_HasDestination, + edkRaise_HasTracebackExpression, + edkRaise_HasTypeExpression, + edkRaise_HasValueExpression, + edkReturn_HasExpression, + edkSuite_HasStatement, + edkTargetList_HasTarget, + edkTryExcept_HasElseBody, + edkTryExcept_HasHandler, + edkTryExcept_HasFinallyBody, + edkTryFinal_HasFinallyBody, + edkWhile_HasTestExpression, + edkWith_HasExpression, + edkWith_HasTargetList, + edkReferenceType_RefersTo, + edkLAST + }; + + +}}} +#endif + diff --git a/lib/python/inc/algorithms/Algorithm.h b/lib/python/inc/algorithms/Algorithm.h new file mode 100644 index 0000000..e2ed853 --- /dev/null +++ b/lib/python/inc/algorithms/Algorithm.h @@ -0,0 +1,69 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ALGORITHM_H_ +#define _PYTHON_ALGORITHM_H_ + +#include "python/inc/python.h" + +/** +* \file Algorithm.h +* \brief Contains declaration of Algorithm class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Common base class for all algorithm classes. + */ + class Algorithm { + public: + /** + * \internal + * \brief The constructor. + */ + Algorithm(){} + + /** + * \internal + * \brief The virtual destructor. + */ + virtual ~Algorithm(){} + + protected: + /** + * \internal + * \brief Increases the depth of the given visitor. + * \param v [in] The visitor class. + */ + void incVisitorDepth(Visitor& v); + + /** + * \internal + * \brief Decreases the depth of the given visitor. + * \param v [in] The visitor class. + */ + void decVisitorDepth(Visitor& v); + + }; // Algorithm + + +}}} +#endif + diff --git a/lib/python/inc/algorithms/AlgorithmPreorder.h b/lib/python/inc/algorithms/AlgorithmPreorder.h new file mode 100644 index 0000000..94c5c8b --- /dev/null +++ b/lib/python/inc/algorithms/AlgorithmPreorder.h @@ -0,0 +1,1298 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ALGORITHMPREORDER_H_ +#define _PYTHON_ALGORITHMPREORDER_H_ + +#include "python/inc/python.h" + +#include + +#include + +/** +* \file AlgorithmPreorder.h +* \brief Contains the class `AlgorithmPreorder' which implements the preorder traversal of the ASG. +* This is the visitor which when visit a node it call itself for all tree edges. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Implements the preorder traversal of the ASG. + */ + class AlgorithmPreorder: public Algorithm , public Visitor{ + private: + /** + * \brief Disable copy of object. + */ + AlgorithmPreorder(const AlgorithmPreorder&); + + /** + * \brief Disable copy of object. + */ + AlgorithmPreorder& operator=(const AlgorithmPreorder&); + + public: + /** + * \brief Constructor. + */ + AlgorithmPreorder(); + + /** + * \brief Virtual destructor. + */ + virtual ~AlgorithmPreorder(); + + /** + * \brief Sets that a node will be visited only once in the visiting. + */ + void setSafeMode(); + + /** + * \brief Sets that the preorder is executed duly the graph (which means that a node can be visited more than once, even if there is a circle in the graph it will be an endless visiting). + */ + void setUnsafeMode(); + + /** + * \brief Set visit cross edge tree. + * \param visit [in] If visit parameter is true, cross edge trees are visited, otherwise they are not visited. + */ + void setVisitCrossEdgeTree(bool visit); + + /** + * \brief Set visit filtered edges. + * \param visit [in] If visit parameter is true, filtered edges are visited, otherwise they are not visited. + */ + void setVisitFilteredEdges(bool visit); + + /** + * \brief Sets whether special nodes (or only used of them) are visited or not. + * \param visit [in] If visit parameter is true, special nodes are visited as well, otherwise they are not visited. + * \param usedOnly [in] If usedOnly parameter is true, only those special nodes are visited that were 'used' during preorder. + */ + void setVisitSpecialNodes(bool visit, bool usedOnly); + + /** + * \brief Set the factory + * \param node [in] The preorder visits only the subtree of this node. + */ + void setFactory(Factory& fact); + + /** + * \brief add visitor + * \param node [in] The preorder visits only the subtree of this node. + */ + void addVisitor(Visitor& visitor); + + /** + * \brief Starts a preorder traversal which visits all nodes + */ + void run(); + + /** + * \brief Starts a preorder traversal, recursively processing all subtres + * \param node [in] The preorder visits only the subtree of this node. + */ + void run(const base::Base& node); + + /** + * \brief Starts a preorder traversal which visits all nodes of the parameter `fact', then recursively processing all subtrees, and at every nodes call the appropriate visit function of the Visitor `visitor' + * \param fact [in] The factory of the ASG. + * \param visitor [in] The visitor which is called to visit the given node or edge. + * \deprecated Please set the visitor with add visitor, set the factory with the set factory function + */ + void run(const Factory& fact, Visitor& visitor); + + /** + * \brief Starts a preorder traversal which visits all nodes of the parameter `fact' by processing the parameter `node', then recursively processing all subtrees, and at every nodes call the appropriate visit function of the Visitor `visitor' + * \param fact [in] The factory of the ASG. + * \param visitor [in] The visitor which is called to visit the given node or edge. + * \param node [in] The preorder visits only the subtree of this node. + * \deprecated Please set the visitor with add visitor, set the factory with the set factory function + */ + void run(const Factory& fact, Visitor& visitor, const base::Base& node); + + /** + * \brief Starts a preorder traversal which visits all nodes of the parameter `fact' by processing the node with the given id, then recursively processing all subtrees, and at every nodes call the appropriate visit function of the Visitor `visitor' + * \param fact [in] The factory of the ASG. + * \param visitor [in] The visitor which is called to visit the given node or edge. + * \param nodeId [in] The preorder visits only the subtree of this node. + * \deprecated Please set the visitor with add visitor, set the factory with the set factory function + */ + void run(const Factory& fact, Visitor& visitor, NodeId nodeId); + + /** + * \brief It set the edge as a tree edge + * \param edgekind [in] The edge which will used as tree edge. + */ + void setCrossEdgeToTraversal(EdgeKind edgekind); + + /** + * \brief Adds the visitor to the stopped visitor set. + * \param visitor [in] The visitor we adds. + */ + void stop(Visitor* visitor); + + /** \internal \brief The visitor functions owerloades */ + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const base::Comment& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Call& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Index& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::List& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Set& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const module::Module& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const module::Object& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const module::Package& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Break& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::For& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Global& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::If& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Print& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Return& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::While& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const statement::With& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const type::DictType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief The node call back the this function that achive the preorder + */ + virtual void visit(const type::SimpleType& node , bool callVirtualBase = true); + + /** \internal \brief End The visitor functions owerloades */ + protected: + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const base::Base& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const base::Comment& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const base::Named& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const base::Positioned& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Binary& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Call& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Expression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Index& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::List& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Literal& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Set& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Slicing& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::Unary& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const module::Module& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const module::Object& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const module::Package& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Break& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::CompoundStatement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::For& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Global& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::If& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Iteration& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Print& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Return& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::SimpleStatement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Statement& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::Try& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::While& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const statement::With& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const type::DictType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const type::SimpleType& node , bool callVirtualBase = true); + + /** + * \internal + * \brief It call the traversal for the edges + * \param node [in] The node with own type + * \param callVirtualBase [in] This paramater is don't used just api copatibility used. + */ + virtual void visitAllEdges(const type::Type& node , bool callVirtualBase = true); + + /** + * \internal + * \brief Starts a preorder traversal. + */ + void mainRun(const Factory* fact, Visitor* visitor, const base::Base* node); + + /** + * \internal + * \brief Prepare for traversal. Modyficcate the filters if need it. Call the startvisit function for the all given vistor. ect.) + */ + void startPreorder(); + + /** + * \internal + * \brief Reset enviroment to the origal state. and call the visitFinish functions + */ + void endPreorder(); + + /** + * \brief Removes the stopped visitors from the visitorList. Sets the needPreorderStop true if the list becomes empty. + */ + void clearStoppedVisitors(); + + /** \internal \brief If it is true, two node are not visited during preorder. */ + bool safeMode; + + /** \internal \brief Stores the ids of the node which are already visited during the actual run. */ + std::vector visitedNodes; + + /** \internal \brief The set of ids of nodes which need to be visited. */ + std::vector unvisitedNodes; + + /** \internal \brief If it is true, it collect the sub trees. */ + bool visitCrossEdgeTree; + + /** \internal \brief If it is true, the preorder is stopped because of a visitor. */ + bool needPreorderStop; + + /** \internal \brief The set of visitors we stop in the next clearStoppedVisitors call. */ + std::set stoppeds; + + /** \internal \brief Determines whether special nodes will be visited or not. */ + bool visitSpecialNodes; + + /** \internal \brief Determines whether only used special nodes will be visited or all of them. */ + bool visitUsedSpecialNodesOnly; + + bool visitFilteredEdge; + + bool originalFilterState; + + const base::Base* apRoot; + + std::list visitorList; + + Factory* fact; + + bool traversaldCrossEdges[102]; + + }; // AlgorithmPreorder + + +}}} +#endif + diff --git a/lib/python/inc/base/Base.h b/lib/python/inc/base/Base.h new file mode 100644 index 0000000..2158ce1 --- /dev/null +++ b/lib/python/inc/base/Base.h @@ -0,0 +1,298 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Base_H_ +#define _PYTHON_Base_H_ + +#include "python/inc/python.h" + +/** +* \file Base.h +* \brief Contains declaration of the base::Base class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace base { + + /** + * \brief Base class, which represents the base::Base node. + * (missing) + * + * Attributes: + * - id (int) : (missing) + * - originKind (OriginKind) : (missing) + */ + class Base { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Base(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Base(); + + public: + + /** + * \brief Gives back the Factory the node belongs to. + * \return Return with a reference to the Factory. + */ + Factory& getFactory() const; + + protected: + + /** + * \internal + * \brief Sets this node the parent of the node given in parameter. + * \param childNode [in] The node whose parent is set to this node. + */ + void setParentEdge(const base::Base *childNode,EdgeKind) const ; + + /** + * \internal + * \brief Removes the parent of the node given in parameter. + * \param childNode [in] The node whose parent is removed. + */ + void removeParentEdge(NodeId childNode) const; + + /** + * \internal + * \brief Removes the parent of the node given in parameter. + * \param childNode [in] The node whose parent is removed. + */ + void removeParentEdge(base::Base *childNode) const ; + + /** + * \internal + * \brief Sets the parent of this node. + * \param parentNode [in] The id of the parent of this node. + * \param edgeKind [in] The edge kind of parent. + */ + void setParent(const base::Base* parentNode,EdgeKind edgeKind) const; + + public: + + /** + * \brief Gives back the pointer of the parent of this node. + * \return Return with the pointer of the parent of this node. + */ + base::Base* getParent() const; + + /** + * \brief Gives back the pointer of the parent of this node. + * \return Return with the pointer of the parent of this node. + */ + EdgeKind getParentEdgeKind() const{return parentEdgeKind;} + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Base & operator=(const Base&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Base(const Base&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the id of the node. + * \return Returns with the id. + */ + NodeId getId() const; + + /** + * \brief Gives back the originKind of the node. + * \return Returns with the originKind. + */ + OriginKind getOriginKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the id of the node. + * \param id [in] The new value of the id. + */ + void setId(NodeId _id); + + /** + * \internal + * \brief Sets the originKind of the node. + * \param originKind [in] The new value of the originKind. + */ + void setOriginKind(OriginKind _originKind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The hash of node has been calculated. */ + mutable bool hashOk : 1; + + /** \internal \brief The id of the `id`. */ + NodeId m_id; + + /** \internal \brief The OriginKind of the node. */ + OriginKind m_originKind; + + /** \internal \brief Edge kind to the parent node. */ + mutable NodeHashType nodeHashCache; + + /** \internal \brief Edge kind to the parent node. */ + mutable EdgeKind parentEdgeKind; + + /** \internal \brief Edge to the parent node. */ + mutable NodeId parent; + + /** \internal \brief The Factory of the node. */ + Factory *factory; + + public: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \return Return true if setting was success. + */ + bool setEdge(EdgeKind edgeKind, base::Base* edgeEnd); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \return Return true if removing was success. + */ + bool removeEdge(EdgeKind edgeKind, base::Base* edgeEnd); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + /** + * \internal + * \brief Reset node hash. + */ + void resetHash(std::set& node) const {hashOk = false;} + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/base/Comment.h b/lib/python/inc/base/Comment.h new file mode 100644 index 0000000..c51e647 --- /dev/null +++ b/lib/python/inc/base/Comment.h @@ -0,0 +1,202 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Comment_H_ +#define _PYTHON_Comment_H_ + +#include "python/inc/python.h" + +/** +* \file Comment.h +* \brief Contains declaration of the base::Comment class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace base { + + /** + * \brief Comment class, which represents the base::Comment node. + * (missing) + * + * Attributes: + * - text (String) : (missing) + */ + class Comment : public Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Comment(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Comment(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Comment & operator=(const Comment&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Comment(const Comment&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the text of the node. + * \return Returns with the text. + */ + const std::string& getText() const; + + /** + * \brief Gives back the Key of text of the node. + * \return Returns with the Key of the text. + */ + Key getTextKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the text of the node. + * \param text [in] The new value of the text. + */ + void setText(const std::string& _text); + + /** + * \internal + * \brief Sets the text of the node. + * \param text [in] The new Key of the text. + */ + void setTextKey(Key _text); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `text`. */ + Key m_text; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/base/Docstring.h b/lib/python/inc/base/Docstring.h new file mode 100644 index 0000000..203801f --- /dev/null +++ b/lib/python/inc/base/Docstring.h @@ -0,0 +1,202 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Docstring_H_ +#define _PYTHON_Docstring_H_ + +#include "python/inc/python.h" + +/** +* \file Docstring.h +* \brief Contains declaration of the base::Docstring class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace base { + + /** + * \brief Docstring class, which represents the base::Docstring node. + * (missing) + * + * Attributes: + * - text (String) : (missing) + */ + class Docstring : public Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Docstring(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Docstring(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Docstring & operator=(const Docstring&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Docstring(const Docstring&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the text of the node. + * \return Returns with the text. + */ + const std::string& getText() const; + + /** + * \brief Gives back the Key of text of the node. + * \return Returns with the Key of the text. + */ + Key getTextKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the text of the node. + * \param text [in] The new value of the text. + */ + void setText(const std::string& _text); + + /** + * \internal + * \brief Sets the text of the node. + * \param text [in] The new Key of the text. + */ + void setTextKey(Key _text); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `text`. */ + Key m_text; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/base/Named.h b/lib/python/inc/base/Named.h new file mode 100644 index 0000000..ed48190 --- /dev/null +++ b/lib/python/inc/base/Named.h @@ -0,0 +1,202 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Named_H_ +#define _PYTHON_Named_H_ + +#include "python/inc/python.h" + +/** +* \file Named.h +* \brief Contains declaration of the base::Named class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace base { + + /** + * \brief Named class, which represents the base::Named node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + */ + class Named : public Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Named(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Named(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Named & operator=(const Named&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Named(const Named&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/base/Positioned.h b/lib/python/inc/base/Positioned.h new file mode 100644 index 0000000..e32ffca --- /dev/null +++ b/lib/python/inc/base/Positioned.h @@ -0,0 +1,260 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Positioned_H_ +#define _PYTHON_Positioned_H_ + +#include "python/inc/python.h" + +/** +* \file Positioned.h +* \brief Contains declaration of the base::Positioned class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace base { + + /** + * \brief Positioned class, which represents the base::Positioned node. + * (missing) + * + * Attributes: + * - position (Range) : (missing) + * + * Edges: + * - comments (base::Comment, multiple) : (missing) + */ + class Positioned : public Base { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Positioned(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Positioned(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Positioned & operator=(const Positioned&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Positioned(const Positioned&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the position of the node. + * \return Returns with the position. + */ + virtual const Range getPosition() const; + + /** + * \brief Compare two node by position attribute of the node. + * \return Returns with the result. + */ + virtual int compareByPosition(const Positioned& other) const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the position of the node. + * \param position [in] The new value of the position. + */ + virtual void setPosition(const Range& _position); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief todo (unknown). */ + MultiRange m_position; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the comments edges. + * \return Returns an iterator for the comments edges. + */ + ListIterator getCommentsListIteratorBegin() const; + + /** + * \brief Gives back iterator for the comments edges. + * \return Returns an iterator for the comments edges. + */ + ListIterator getCommentsListIteratorEnd() const; + + /** + * \brief Tells whether the node has comments edges or not. + * \return Returns true if the node doesn't have any comments edge. + */ + bool getCommentsIsEmpty() const; + + /** + * \brief Gives back how many comments edges the node has. + * \return Returns with the number of comments edges. + */ + unsigned getCommentsSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new comments edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new comments edge. + */ + void addComments(const Comment *node); + + /** + * \brief Adds a new comments edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new comments edge. + */ + void addComments(NodeId id); + + /** + * \brief Remove the comments edge by id from the node. + * \param id [in] The end point of the comments edge. + */ + void removeComments(NodeId id); + + /** + * \brief Remove the comments edge from the node. + * \param node [in] The end point of the comments edge. + */ + void removeComments(Comment *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the comments edge points to. */ + ListIterator::Container commentsContainer; + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/ArgumentList.h b/lib/python/inc/expression/ArgumentList.h new file mode 100644 index 0000000..0f0eded --- /dev/null +++ b/lib/python/inc/expression/ArgumentList.h @@ -0,0 +1,306 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ArgumentList_H_ +#define _PYTHON_ArgumentList_H_ + +#include "python/inc/python.h" + +/** +* \file ArgumentList.h +* \brief Contains declaration of the expression::ArgumentList class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief ArgumentList class, which represents the expression::ArgumentList node. + * (missing) + * + * Edges: + * - hasPositionalArguments (expression::ExpressionList, single) : (missing) + * - hasDictionary (expression::Expression, single) : (missing) + * - hasKeyword (expression::Keyword, multiple) : (missing) + * - hasTuple (expression::Expression, single) : (missing) + */ + class ArgumentList : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ArgumentList(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ArgumentList(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ArgumentList & operator=(const ArgumentList&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ArgumentList(const ArgumentList&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasPositionalArguments edge points to. + * \return Returns the end point of the hasPositionalArguments edge. + */ + expression::ExpressionList* getPositionalArguments() const; + + /** + * \brief Gives back the pointer of the node the hasDictionary edge points to. + * \return Returns the end point of the hasDictionary edge. + */ + expression::Expression* getDictionary() const; + + /** + * \brief Gives back iterator for the hasKeyword edges. + * \return Returns an iterator for the hasKeyword edges. + */ + ListIterator getKeywordListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasKeyword edges. + * \return Returns an iterator for the hasKeyword edges. + */ + ListIterator getKeywordListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasKeyword edges or not. + * \return Returns true if the node doesn't have any hasKeyword edge. + */ + bool getKeywordIsEmpty() const; + + /** + * \brief Gives back how many hasKeyword edges the node has. + * \return Returns with the number of hasKeyword edges. + */ + unsigned getKeywordSize() const; + + /** + * \brief Gives back the pointer of the node the hasTuple edge points to. + * \return Returns the end point of the hasTuple edge. + */ + expression::Expression* getTuple() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasPositionalArguments edge. + * \param id [in] The new end point of the hasPositionalArguments edge. + */ + void setPositionalArguments(NodeId id); + + /** + * \brief Sets the hasPositionalArguments edge. + * \param node [in] The new end point of the hasPositionalArguments edge. + */ + void setPositionalArguments(ExpressionList *node); + + /** + * \brief remove the hasPositionalArguments edge. + */ + void removePositionalArguments(); + + /** + * \brief Sets the hasDictionary edge. + * \param id [in] The new end point of the hasDictionary edge. + */ + void setDictionary(NodeId id); + + /** + * \brief Sets the hasDictionary edge. + * \param node [in] The new end point of the hasDictionary edge. + */ + void setDictionary(Expression *node); + + /** + * \brief remove the hasDictionary edge. + */ + void removeDictionary(); + + /** + * \brief Adds a new hasKeyword edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasKeyword edge. + */ + void addKeyword(const Keyword *node); + + /** + * \brief Adds a new hasKeyword edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasKeyword edge. + */ + void addKeyword(NodeId id); + + /** + * \brief Remove the hasKeyword edge by id from the node. + * \param id [in] The end point of the hasKeyword edge. + */ + void removeKeyword(NodeId id); + + /** + * \brief Remove the hasKeyword edge from the node. + * \param node [in] The end point of the hasKeyword edge. + */ + void removeKeyword(Keyword *node); + + /** + * \brief Sets the hasTuple edge. + * \param id [in] The new end point of the hasTuple edge. + */ + void setTuple(NodeId id); + + /** + * \brief Sets the hasTuple edge. + * \param node [in] The new end point of the hasTuple edge. + */ + void setTuple(Expression *node); + + /** + * \brief remove the hasTuple edge. + */ + void removeTuple(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasPositionalArguments edge points to. */ + NodeId m_hasPositionalArguments; + + /** \internal \brief The id of the node the hasDictionary edge points to. */ + NodeId m_hasDictionary; + + /** \internal \brief Container stores the id of the nodes the hasKeyword edge points to. */ + ListIterator::Container hasKeywordContainer; + + /** \internal \brief The id of the node the hasTuple edge points to. */ + NodeId m_hasTuple; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/AttributeRef.h b/lib/python/inc/expression/AttributeRef.h new file mode 100644 index 0000000..7b92222 --- /dev/null +++ b/lib/python/inc/expression/AttributeRef.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_AttributeRef_H_ +#define _PYTHON_AttributeRef_H_ + +#include "python/inc/python.h" + +/** +* \file AttributeRef.h +* \brief Contains declaration of the expression::AttributeRef class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief AttributeRef class, which represents the expression::AttributeRef node. + * (missing) + */ + class AttributeRef : public Binary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + AttributeRef(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~AttributeRef(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + AttributeRef & operator=(const AttributeRef&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + AttributeRef(const AttributeRef&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Binary.h b/lib/python/inc/expression/Binary.h new file mode 100644 index 0000000..004658d --- /dev/null +++ b/lib/python/inc/expression/Binary.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Binary_H_ +#define _PYTHON_Binary_H_ + +#include "python/inc/python.h" + +/** +* \file Binary.h +* \brief Contains declaration of the expression::Binary class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Binary class, which represents the expression::Binary node. + * (missing) + * + * Edges: + * - hasLeftExpression (expression::Expression, single) : (missing) + * - hasRightExpression (expression::Expression, single) : (missing) + */ + class Binary : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Binary(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Binary(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Binary & operator=(const Binary&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Binary(const Binary&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasLeftExpression edge points to. + * \return Returns the end point of the hasLeftExpression edge. + */ + expression::Expression* getLeftExpression() const; + + /** + * \brief Gives back the pointer of the node the hasRightExpression edge points to. + * \return Returns the end point of the hasRightExpression edge. + */ + expression::Expression* getRightExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasLeftExpression edge. + * \param id [in] The new end point of the hasLeftExpression edge. + */ + void setLeftExpression(NodeId id); + + /** + * \brief Sets the hasLeftExpression edge. + * \param node [in] The new end point of the hasLeftExpression edge. + */ + void setLeftExpression(Expression *node); + + /** + * \brief remove the hasLeftExpression edge. + */ + void removeLeftExpression(); + + /** + * \brief Sets the hasRightExpression edge. + * \param id [in] The new end point of the hasRightExpression edge. + */ + void setRightExpression(NodeId id); + + /** + * \brief Sets the hasRightExpression edge. + * \param node [in] The new end point of the hasRightExpression edge. + */ + void setRightExpression(Expression *node); + + /** + * \brief remove the hasRightExpression edge. + */ + void removeRightExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasLeftExpression edge points to. */ + NodeId m_hasLeftExpression; + + /** \internal \brief The id of the node the hasRightExpression edge points to. */ + NodeId m_hasRightExpression; + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/BinaryArithmetic.h b/lib/python/inc/expression/BinaryArithmetic.h new file mode 100644 index 0000000..af1c7a3 --- /dev/null +++ b/lib/python/inc/expression/BinaryArithmetic.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_BinaryArithmetic_H_ +#define _PYTHON_BinaryArithmetic_H_ + +#include "python/inc/python.h" + +/** +* \file BinaryArithmetic.h +* \brief Contains declaration of the expression::BinaryArithmetic class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief BinaryArithmetic class, which represents the expression::BinaryArithmetic node. + * (missing) + * + * Attributes: + * - kind (BinaryArithmeticKind) : (missing) + */ + class BinaryArithmetic : public Binary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + BinaryArithmetic(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~BinaryArithmetic(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + BinaryArithmetic & operator=(const BinaryArithmetic&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + BinaryArithmetic(const BinaryArithmetic&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + BinaryArithmeticKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(BinaryArithmeticKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The BinaryArithmeticKind of the node. */ + BinaryArithmeticKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/BinaryLogical.h b/lib/python/inc/expression/BinaryLogical.h new file mode 100644 index 0000000..3dbd033 --- /dev/null +++ b/lib/python/inc/expression/BinaryLogical.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_BinaryLogical_H_ +#define _PYTHON_BinaryLogical_H_ + +#include "python/inc/python.h" + +/** +* \file BinaryLogical.h +* \brief Contains declaration of the expression::BinaryLogical class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief BinaryLogical class, which represents the expression::BinaryLogical node. + * (missing) + * + * Attributes: + * - kind (BinaryLogicalKind) : (missing) + */ + class BinaryLogical : public Binary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + BinaryLogical(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~BinaryLogical(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + BinaryLogical & operator=(const BinaryLogical&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + BinaryLogical(const BinaryLogical&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + BinaryLogicalKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(BinaryLogicalKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The BinaryLogicalKind of the node. */ + BinaryLogicalKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Call.h b/lib/python/inc/expression/Call.h new file mode 100644 index 0000000..14e9577 --- /dev/null +++ b/lib/python/inc/expression/Call.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Call_H_ +#define _PYTHON_Call_H_ + +#include "python/inc/python.h" + +/** +* \file Call.h +* \brief Contains declaration of the expression::Call class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Call class, which represents the expression::Call node. + * (missing) + * + * Edges: + * - hasArgumentList (expression::ArgumentList, single) : (missing) + * - refersTo (statement::CompoundStatement, single) : (missing) + */ + class Call : public Unary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Call(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Call(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Call & operator=(const Call&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Call(const Call&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasArgumentList edge points to. + * \return Returns the end point of the hasArgumentList edge. + */ + expression::ArgumentList* getArgumentList() const; + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + statement::CompoundStatement* getRefersTo() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasArgumentList edge. + * \param id [in] The new end point of the hasArgumentList edge. + */ + void setArgumentList(NodeId id); + + /** + * \brief Sets the hasArgumentList edge. + * \param node [in] The new end point of the hasArgumentList edge. + */ + void setArgumentList(ArgumentList *node); + + /** + * \brief remove the hasArgumentList edge. + */ + void removeArgumentList(); + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(statement::CompoundStatement *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasArgumentList edge points to. */ + NodeId m_hasArgumentList; + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/DictComp.h b/lib/python/inc/expression/DictComp.h new file mode 100644 index 0000000..1fe5150 --- /dev/null +++ b/lib/python/inc/expression/DictComp.h @@ -0,0 +1,252 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_DictComp_H_ +#define _PYTHON_DictComp_H_ + +#include "python/inc/python.h" + +/** +* \file DictComp.h +* \brief Contains declaration of the expression::DictComp class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief DictComp class, which represents the expression::DictComp node. + * (missing) + * + * Edges: + * - hasKeyValue (expression::KeyValue, single) : (missing) + * - hasGenerator (expression::Generator, multiple) : (missing) + */ + class DictComp : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + DictComp(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~DictComp(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + DictComp & operator=(const DictComp&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + DictComp(const DictComp&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasKeyValue edge points to. + * \return Returns the end point of the hasKeyValue edge. + */ + expression::KeyValue* getKeyValue() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasGenerator edges or not. + * \return Returns true if the node doesn't have any hasGenerator edge. + */ + bool getGeneratorIsEmpty() const; + + /** + * \brief Gives back how many hasGenerator edges the node has. + * \return Returns with the number of hasGenerator edges. + */ + unsigned getGeneratorSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasKeyValue edge. + * \param id [in] The new end point of the hasKeyValue edge. + */ + void setKeyValue(NodeId id); + + /** + * \brief Sets the hasKeyValue edge. + * \param node [in] The new end point of the hasKeyValue edge. + */ + void setKeyValue(KeyValue *node); + + /** + * \brief remove the hasKeyValue edge. + */ + void removeKeyValue(); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasGenerator edge. + */ + void addGenerator(const Generator *node); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasGenerator edge. + */ + void addGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge by id from the node. + * \param id [in] The end point of the hasGenerator edge. + */ + void removeGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge from the node. + * \param node [in] The end point of the hasGenerator edge. + */ + void removeGenerator(Generator *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasKeyValue edge points to. */ + NodeId m_hasKeyValue; + + /** \internal \brief Container stores the id of the nodes the hasGenerator edge points to. */ + ListIterator::Container hasGeneratorContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Dictionary.h b/lib/python/inc/expression/Dictionary.h new file mode 100644 index 0000000..bebfc71 --- /dev/null +++ b/lib/python/inc/expression/Dictionary.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Dictionary_H_ +#define _PYTHON_Dictionary_H_ + +#include "python/inc/python.h" + +/** +* \file Dictionary.h +* \brief Contains declaration of the expression::Dictionary class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Dictionary class, which represents the expression::Dictionary node. + * (missing) + * + * Edges: + * - hasKeyValue (expression::KeyValue, multiple) : (missing) + */ + class Dictionary : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Dictionary(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Dictionary(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Dictionary & operator=(const Dictionary&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Dictionary(const Dictionary&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasKeyValue edges. + * \return Returns an iterator for the hasKeyValue edges. + */ + ListIterator getKeyValueListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasKeyValue edges. + * \return Returns an iterator for the hasKeyValue edges. + */ + ListIterator getKeyValueListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasKeyValue edges or not. + * \return Returns true if the node doesn't have any hasKeyValue edge. + */ + bool getKeyValueIsEmpty() const; + + /** + * \brief Gives back how many hasKeyValue edges the node has. + * \return Returns with the number of hasKeyValue edges. + */ + unsigned getKeyValueSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasKeyValue edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasKeyValue edge. + */ + void addKeyValue(const KeyValue *node); + + /** + * \brief Adds a new hasKeyValue edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasKeyValue edge. + */ + void addKeyValue(NodeId id); + + /** + * \brief Remove the hasKeyValue edge by id from the node. + * \param id [in] The end point of the hasKeyValue edge. + */ + void removeKeyValue(NodeId id); + + /** + * \brief Remove the hasKeyValue edge from the node. + * \param node [in] The end point of the hasKeyValue edge. + */ + void removeKeyValue(KeyValue *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasKeyValue edge points to. */ + ListIterator::Container hasKeyValueContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Ellipsis.h b/lib/python/inc/expression/Ellipsis.h new file mode 100644 index 0000000..d2362b6 --- /dev/null +++ b/lib/python/inc/expression/Ellipsis.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Ellipsis_H_ +#define _PYTHON_Ellipsis_H_ + +#include "python/inc/python.h" + +/** +* \file Ellipsis.h +* \brief Contains declaration of the expression::Ellipsis class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Ellipsis class, which represents the expression::Ellipsis node. + * (missing) + */ + class Ellipsis : public Slicing { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Ellipsis(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Ellipsis(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Ellipsis & operator=(const Ellipsis&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Ellipsis(const Ellipsis&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Expression.h b/lib/python/inc/expression/Expression.h new file mode 100644 index 0000000..8485c95 --- /dev/null +++ b/lib/python/inc/expression/Expression.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Expression_H_ +#define _PYTHON_Expression_H_ + +#include "python/inc/python.h" + +/** +* \file Expression.h +* \brief Contains declaration of the expression::Expression class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Expression class, which represents the expression::Expression node. + * (missing) + * + * Edges: + * - hasType (type::Type, single) : (missing) + */ + class Expression : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Expression(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Expression(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Expression & operator=(const Expression&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Expression(const Expression&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasType edge points to. + * \return Returns the end point of the hasType edge. + */ + type::Type* getType() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasType edge. + * \param id [in] The new end point of the hasType edge. + */ + void setType(NodeId id); + + /** + * \brief Sets the hasType edge. + * \param node [in] The new end point of the hasType edge. + */ + void setType(type::Type *node); + + /** + * \brief remove the hasType edge. + */ + void removeType(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasType edge points to. */ + NodeId m_hasType; + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/ExpressionList.h b/lib/python/inc/expression/ExpressionList.h new file mode 100644 index 0000000..fa4415f --- /dev/null +++ b/lib/python/inc/expression/ExpressionList.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ExpressionList_H_ +#define _PYTHON_ExpressionList_H_ + +#include "python/inc/python.h" + +/** +* \file ExpressionList.h +* \brief Contains declaration of the expression::ExpressionList class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief ExpressionList class, which represents the expression::ExpressionList node. + * (missing) + * + * Attributes: + * - isYieldExpression (boolean) : (missing) + * + * Edges: + * - hasExpression (expression::Expression, multiple) : (missing) + */ + class ExpressionList : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ExpressionList(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ExpressionList(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ExpressionList & operator=(const ExpressionList&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ExpressionList(const ExpressionList&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the isYieldExpression of the node. + * \return Returns with the isYieldExpression. + */ + bool getIsYieldExpression() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the isYieldExpression of the node. + * \param isYieldExpression [in] The new value of the isYieldExpression. + */ + void setIsYieldExpression(bool _isYieldExpression); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief Stores whether the node is `YieldExpression` or not. */ + bool m_isYieldExpression : 1; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasExpression edges. + * \return Returns an iterator for the hasExpression edges. + */ + ListIterator getExpressionListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasExpression edges. + * \return Returns an iterator for the hasExpression edges. + */ + ListIterator getExpressionListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasExpression edges or not. + * \return Returns true if the node doesn't have any hasExpression edge. + */ + bool getExpressionIsEmpty() const; + + /** + * \brief Gives back how many hasExpression edges the node has. + * \return Returns with the number of hasExpression edges. + */ + unsigned getExpressionSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasExpression edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasExpression edge. + */ + void addExpression(const Expression *node); + + /** + * \brief Adds a new hasExpression edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasExpression edge. + */ + void addExpression(NodeId id); + + /** + * \brief Remove the hasExpression edge by id from the node. + * \param id [in] The end point of the hasExpression edge. + */ + void removeExpression(NodeId id); + + /** + * \brief Remove the hasExpression edge from the node. + * \param node [in] The end point of the hasExpression edge. + */ + void removeExpression(Expression *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasExpression edge points to. */ + ListIterator::Container hasExpressionContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/ExtSlice.h b/lib/python/inc/expression/ExtSlice.h new file mode 100644 index 0000000..9af824e --- /dev/null +++ b/lib/python/inc/expression/ExtSlice.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ExtSlice_H_ +#define _PYTHON_ExtSlice_H_ + +#include "python/inc/python.h" + +/** +* \file ExtSlice.h +* \brief Contains declaration of the expression::ExtSlice class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief ExtSlice class, which represents the expression::ExtSlice node. + * (missing) + * + * Edges: + * - hasItem (expression::Slicing, multiple) : (missing) + */ + class ExtSlice : public Slicing { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ExtSlice(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ExtSlice(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ExtSlice & operator=(const ExtSlice&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ExtSlice(const ExtSlice&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasItem edges. + * \return Returns an iterator for the hasItem edges. + */ + ListIterator getItemListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasItem edges. + * \return Returns an iterator for the hasItem edges. + */ + ListIterator getItemListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasItem edges or not. + * \return Returns true if the node doesn't have any hasItem edge. + */ + bool getItemIsEmpty() const; + + /** + * \brief Gives back how many hasItem edges the node has. + * \return Returns with the number of hasItem edges. + */ + unsigned getItemSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasItem edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasItem edge. + */ + void addItem(const Slicing *node); + + /** + * \brief Adds a new hasItem edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasItem edge. + */ + void addItem(NodeId id); + + /** + * \brief Remove the hasItem edge by id from the node. + * \param id [in] The end point of the hasItem edge. + */ + void removeItem(NodeId id); + + /** + * \brief Remove the hasItem edge from the node. + * \param node [in] The end point of the hasItem edge. + */ + void removeItem(Slicing *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasItem edge points to. */ + ListIterator::Container hasItemContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/FloatNumber.h b/lib/python/inc/expression/FloatNumber.h new file mode 100644 index 0000000..df7c540 --- /dev/null +++ b/lib/python/inc/expression/FloatNumber.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_FloatNumber_H_ +#define _PYTHON_FloatNumber_H_ + +#include "python/inc/python.h" + +/** +* \file FloatNumber.h +* \brief Contains declaration of the expression::FloatNumber class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief FloatNumber class, which represents the expression::FloatNumber node. + * (missing) + * + * Attributes: + * - value (double) : (missing) + */ + class FloatNumber : public Literal { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + FloatNumber(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~FloatNumber(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + FloatNumber & operator=(const FloatNumber&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + FloatNumber(const FloatNumber&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the value of the node. + * \return Returns with the value. + */ + double getValue() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the value of the node. + * \param value [in] The new value of the value. + */ + void setValue(double _value); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `value`. */ + double m_value; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Generator.h b/lib/python/inc/expression/Generator.h new file mode 100644 index 0000000..4c52e53 --- /dev/null +++ b/lib/python/inc/expression/Generator.h @@ -0,0 +1,279 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Generator_H_ +#define _PYTHON_Generator_H_ + +#include "python/inc/python.h" + +/** +* \file Generator.h +* \brief Contains declaration of the expression::Generator class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Generator class, which represents the expression::Generator node. + * (missing) + * + * Edges: + * - hasCondition (expression::Expression, multiple) : (missing) + * - hasIter (expression::Expression, single) : (missing) + * - hasTarget (expression::Expression, single) : (missing) + */ + class Generator : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Generator(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Generator(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Generator & operator=(const Generator&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Generator(const Generator&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasCondition edges. + * \return Returns an iterator for the hasCondition edges. + */ + ListIterator getConditionListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasCondition edges. + * \return Returns an iterator for the hasCondition edges. + */ + ListIterator getConditionListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasCondition edges or not. + * \return Returns true if the node doesn't have any hasCondition edge. + */ + bool getConditionIsEmpty() const; + + /** + * \brief Gives back how many hasCondition edges the node has. + * \return Returns with the number of hasCondition edges. + */ + unsigned getConditionSize() const; + + /** + * \brief Gives back the pointer of the node the hasIter edge points to. + * \return Returns the end point of the hasIter edge. + */ + expression::Expression* getIter() const; + + /** + * \brief Gives back the pointer of the node the hasTarget edge points to. + * \return Returns the end point of the hasTarget edge. + */ + expression::Expression* getTarget() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasCondition edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasCondition edge. + */ + void addCondition(const Expression *node); + + /** + * \brief Adds a new hasCondition edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasCondition edge. + */ + void addCondition(NodeId id); + + /** + * \brief Remove the hasCondition edge by id from the node. + * \param id [in] The end point of the hasCondition edge. + */ + void removeCondition(NodeId id); + + /** + * \brief Remove the hasCondition edge from the node. + * \param node [in] The end point of the hasCondition edge. + */ + void removeCondition(Expression *node); + + /** + * \brief Sets the hasIter edge. + * \param id [in] The new end point of the hasIter edge. + */ + void setIter(NodeId id); + + /** + * \brief Sets the hasIter edge. + * \param node [in] The new end point of the hasIter edge. + */ + void setIter(Expression *node); + + /** + * \brief remove the hasIter edge. + */ + void removeIter(); + + /** + * \brief Sets the hasTarget edge. + * \param id [in] The new end point of the hasTarget edge. + */ + void setTarget(NodeId id); + + /** + * \brief Sets the hasTarget edge. + * \param node [in] The new end point of the hasTarget edge. + */ + void setTarget(Expression *node); + + /** + * \brief remove the hasTarget edge. + */ + void removeTarget(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasCondition edge points to. */ + ListIterator::Container hasConditionContainer; + + /** \internal \brief The id of the node the hasIter edge points to. */ + NodeId m_hasIter; + + /** \internal \brief The id of the node the hasTarget edge points to. */ + NodeId m_hasTarget; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/GeneratorExpression.h b/lib/python/inc/expression/GeneratorExpression.h new file mode 100644 index 0000000..c7e2259 --- /dev/null +++ b/lib/python/inc/expression/GeneratorExpression.h @@ -0,0 +1,252 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_GeneratorExpression_H_ +#define _PYTHON_GeneratorExpression_H_ + +#include "python/inc/python.h" + +/** +* \file GeneratorExpression.h +* \brief Contains declaration of the expression::GeneratorExpression class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief GeneratorExpression class, which represents the expression::GeneratorExpression node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + * - hasGenerator (expression::Generator, multiple) : (missing) + */ + class GeneratorExpression : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + GeneratorExpression(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~GeneratorExpression(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + GeneratorExpression & operator=(const GeneratorExpression&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + GeneratorExpression(const GeneratorExpression&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasGenerator edges or not. + * \return Returns true if the node doesn't have any hasGenerator edge. + */ + bool getGeneratorIsEmpty() const; + + /** + * \brief Gives back how many hasGenerator edges the node has. + * \return Returns with the number of hasGenerator edges. + */ + unsigned getGeneratorSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasGenerator edge. + */ + void addGenerator(const Generator *node); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasGenerator edge. + */ + void addGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge by id from the node. + * \param id [in] The end point of the hasGenerator edge. + */ + void removeGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge from the node. + * \param node [in] The end point of the hasGenerator edge. + */ + void removeGenerator(Generator *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + /** \internal \brief Container stores the id of the nodes the hasGenerator edge points to. */ + ListIterator::Container hasGeneratorContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Identifier.h b/lib/python/inc/expression/Identifier.h new file mode 100644 index 0000000..102a880 --- /dev/null +++ b/lib/python/inc/expression/Identifier.h @@ -0,0 +1,242 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Identifier_H_ +#define _PYTHON_Identifier_H_ + +#include "python/inc/python.h" + +/** +* \file Identifier.h +* \brief Contains declaration of the expression::Identifier class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Identifier class, which represents the expression::Identifier node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + * + * Edges: + * - refersTo (module::Object, single) : (missing) + */ + class Identifier : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Identifier(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Identifier(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Identifier & operator=(const Identifier&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Identifier(const Identifier&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + module::Object* getRefersTo() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(module::Object *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/IfExpression.h b/lib/python/inc/expression/IfExpression.h new file mode 100644 index 0000000..6a4e040 --- /dev/null +++ b/lib/python/inc/expression/IfExpression.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_IfExpression_H_ +#define _PYTHON_IfExpression_H_ + +#include "python/inc/python.h" + +/** +* \file IfExpression.h +* \brief Contains declaration of the expression::IfExpression class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief IfExpression class, which represents the expression::IfExpression node. + * (missing) + * + * Edges: + * - hasBody (expression::Expression, single) : (missing) + * - hasElseBody (expression::Expression, single) : (missing) + * - hasTest (expression::Expression, single) : (missing) + */ + class IfExpression : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + IfExpression(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~IfExpression(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + IfExpression & operator=(const IfExpression&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + IfExpression(const IfExpression&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasBody edge points to. + * \return Returns the end point of the hasBody edge. + */ + expression::Expression* getBody() const; + + /** + * \brief Gives back the pointer of the node the hasElseBody edge points to. + * \return Returns the end point of the hasElseBody edge. + */ + expression::Expression* getElseBody() const; + + /** + * \brief Gives back the pointer of the node the hasTest edge points to. + * \return Returns the end point of the hasTest edge. + */ + expression::Expression* getTest() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasBody edge. + * \param id [in] The new end point of the hasBody edge. + */ + void setBody(NodeId id); + + /** + * \brief Sets the hasBody edge. + * \param node [in] The new end point of the hasBody edge. + */ + void setBody(Expression *node); + + /** + * \brief remove the hasBody edge. + */ + void removeBody(); + + /** + * \brief Sets the hasElseBody edge. + * \param id [in] The new end point of the hasElseBody edge. + */ + void setElseBody(NodeId id); + + /** + * \brief Sets the hasElseBody edge. + * \param node [in] The new end point of the hasElseBody edge. + */ + void setElseBody(Expression *node); + + /** + * \brief remove the hasElseBody edge. + */ + void removeElseBody(); + + /** + * \brief Sets the hasTest edge. + * \param id [in] The new end point of the hasTest edge. + */ + void setTest(NodeId id); + + /** + * \brief Sets the hasTest edge. + * \param node [in] The new end point of the hasTest edge. + */ + void setTest(Expression *node); + + /** + * \brief remove the hasTest edge. + */ + void removeTest(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasBody edge points to. */ + NodeId m_hasBody; + + /** \internal \brief The id of the node the hasElseBody edge points to. */ + NodeId m_hasElseBody; + + /** \internal \brief The id of the node the hasTest edge points to. */ + NodeId m_hasTest; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/ImagNumber.h b/lib/python/inc/expression/ImagNumber.h new file mode 100644 index 0000000..d328b28 --- /dev/null +++ b/lib/python/inc/expression/ImagNumber.h @@ -0,0 +1,206 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ImagNumber_H_ +#define _PYTHON_ImagNumber_H_ + +#include "python/inc/python.h" + +/** +* \file ImagNumber.h +* \brief Contains declaration of the expression::ImagNumber class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief ImagNumber class, which represents the expression::ImagNumber node. + * (missing) + * + * Attributes: + * - im (double) : (missing) + * - real (double) : (missing) + */ + class ImagNumber : public Literal { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ImagNumber(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ImagNumber(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ImagNumber & operator=(const ImagNumber&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ImagNumber(const ImagNumber&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the im of the node. + * \return Returns with the im. + */ + double getIm() const; + + /** + * \brief Gives back the real of the node. + * \return Returns with the real. + */ + double getReal() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the im of the node. + * \param im [in] The new value of the im. + */ + void setIm(double _im); + + /** + * \internal + * \brief Sets the real of the node. + * \param real [in] The new value of the real. + */ + void setReal(double _real); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `im`. */ + double m_im; + + /** \internal \brief The value of the `real`. */ + double m_real; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Index.h b/lib/python/inc/expression/Index.h new file mode 100644 index 0000000..26263e5 --- /dev/null +++ b/lib/python/inc/expression/Index.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Index_H_ +#define _PYTHON_Index_H_ + +#include "python/inc/python.h" + +/** +* \file Index.h +* \brief Contains declaration of the expression::Index class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Index class, which represents the expression::Index node. + * (missing) + */ + class Index : public Slicing { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Index(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Index(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Index & operator=(const Index&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Index(const Index&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/IntegerLiteral.h b/lib/python/inc/expression/IntegerLiteral.h new file mode 100644 index 0000000..8af1e85 --- /dev/null +++ b/lib/python/inc/expression/IntegerLiteral.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_IntegerLiteral_H_ +#define _PYTHON_IntegerLiteral_H_ + +#include "python/inc/python.h" + +/** +* \file IntegerLiteral.h +* \brief Contains declaration of the expression::IntegerLiteral class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief IntegerLiteral class, which represents the expression::IntegerLiteral node. + * (missing) + * + * Attributes: + * - value (int) : (missing) + */ + class IntegerLiteral : public Literal { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + IntegerLiteral(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~IntegerLiteral(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + IntegerLiteral & operator=(const IntegerLiteral&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + IntegerLiteral(const IntegerLiteral&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the value of the node. + * \return Returns with the value. + */ + int getValue() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the value of the node. + * \param value [in] The new value of the value. + */ + void setValue(int _value); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `value`. */ + int m_value; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/KeyValue.h b/lib/python/inc/expression/KeyValue.h new file mode 100644 index 0000000..6fe7915 --- /dev/null +++ b/lib/python/inc/expression/KeyValue.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_KeyValue_H_ +#define _PYTHON_KeyValue_H_ + +#include "python/inc/python.h" + +/** +* \file KeyValue.h +* \brief Contains declaration of the expression::KeyValue class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief KeyValue class, which represents the expression::KeyValue node. + * (missing) + * + * Edges: + * - hasKey (expression::Expression, single) : (missing) + * - hasValue (expression::Expression, single) : (missing) + */ + class KeyValue : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + KeyValue(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~KeyValue(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + KeyValue & operator=(const KeyValue&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + KeyValue(const KeyValue&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasKey edge points to. + * \return Returns the end point of the hasKey edge. + */ + expression::Expression* getKey() const; + + /** + * \brief Gives back the pointer of the node the hasValue edge points to. + * \return Returns the end point of the hasValue edge. + */ + expression::Expression* getValue() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasKey edge. + * \param id [in] The new end point of the hasKey edge. + */ + void setKey(NodeId id); + + /** + * \brief Sets the hasKey edge. + * \param node [in] The new end point of the hasKey edge. + */ + void setKey(Expression *node); + + /** + * \brief remove the hasKey edge. + */ + void removeKey(); + + /** + * \brief Sets the hasValue edge. + * \param id [in] The new end point of the hasValue edge. + */ + void setValue(NodeId id); + + /** + * \brief Sets the hasValue edge. + * \param node [in] The new end point of the hasValue edge. + */ + void setValue(Expression *node); + + /** + * \brief remove the hasValue edge. + */ + void removeValue(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasKey edge points to. */ + NodeId m_hasKey; + + /** \internal \brief The id of the node the hasValue edge points to. */ + NodeId m_hasValue; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Keyword.h b/lib/python/inc/expression/Keyword.h new file mode 100644 index 0000000..140cff9 --- /dev/null +++ b/lib/python/inc/expression/Keyword.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Keyword_H_ +#define _PYTHON_Keyword_H_ + +#include "python/inc/python.h" + +/** +* \file Keyword.h +* \brief Contains declaration of the expression::Keyword class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Keyword class, which represents the expression::Keyword node. + * (missing) + * + * Edges: + * - hasKey (expression::Identifier, single) : (missing) + * - hasValue (expression::Expression, single) : (missing) + */ + class Keyword : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Keyword(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Keyword(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Keyword & operator=(const Keyword&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Keyword(const Keyword&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasKey edge points to. + * \return Returns the end point of the hasKey edge. + */ + expression::Identifier* getKey() const; + + /** + * \brief Gives back the pointer of the node the hasValue edge points to. + * \return Returns the end point of the hasValue edge. + */ + expression::Expression* getValue() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasKey edge. + * \param id [in] The new end point of the hasKey edge. + */ + void setKey(NodeId id); + + /** + * \brief Sets the hasKey edge. + * \param node [in] The new end point of the hasKey edge. + */ + void setKey(Identifier *node); + + /** + * \brief remove the hasKey edge. + */ + void removeKey(); + + /** + * \brief Sets the hasValue edge. + * \param id [in] The new end point of the hasValue edge. + */ + void setValue(NodeId id); + + /** + * \brief Sets the hasValue edge. + * \param node [in] The new end point of the hasValue edge. + */ + void setValue(Expression *node); + + /** + * \brief remove the hasValue edge. + */ + void removeValue(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasKey edge points to. */ + NodeId m_hasKey; + + /** \internal \brief The id of the node the hasValue edge points to. */ + NodeId m_hasValue; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Lambda.h b/lib/python/inc/expression/Lambda.h new file mode 100644 index 0000000..8c74ea7 --- /dev/null +++ b/lib/python/inc/expression/Lambda.h @@ -0,0 +1,304 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Lambda_H_ +#define _PYTHON_Lambda_H_ + +#include "python/inc/python.h" + +/** +* \file Lambda.h +* \brief Contains declaration of the expression::Lambda class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Lambda class, which represents the expression::Lambda node. + * (missing) + * + * Edges: + * - hasObject (module::Object, multiple) : (missing) + * - hasParameter (statement::Parameter, multiple) : (missing) + * - hasExpression (expression::Expression, single) : (missing) + */ + class Lambda : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Lambda(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Lambda(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Lambda & operator=(const Lambda&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Lambda(const Lambda&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasObject edges or not. + * \return Returns true if the node doesn't have any hasObject edge. + */ + bool getObjectIsEmpty() const; + + /** + * \brief Gives back how many hasObject edges the node has. + * \return Returns with the number of hasObject edges. + */ + unsigned getObjectSize() const; + + /** + * \brief Gives back iterator for the hasParameter edges. + * \return Returns an iterator for the hasParameter edges. + */ + ListIterator getParameterListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasParameter edges. + * \return Returns an iterator for the hasParameter edges. + */ + ListIterator getParameterListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasParameter edges or not. + * \return Returns true if the node doesn't have any hasParameter edge. + */ + bool getParameterIsEmpty() const; + + /** + * \brief Gives back how many hasParameter edges the node has. + * \return Returns with the number of hasParameter edges. + */ + unsigned getParameterSize() const; + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasObject edge. + */ + void addObject(const module::Object *node); + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasObject edge. + */ + void addObject(NodeId id); + + /** + * \brief Remove the hasObject edge by id from the node. + * \param id [in] The end point of the hasObject edge. + */ + void removeObject(NodeId id); + + /** + * \brief Remove the hasObject edge from the node. + * \param node [in] The end point of the hasObject edge. + */ + void removeObject(module::Object *node); + + /** + * \brief Adds a new hasParameter edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasParameter edge. + */ + void addParameter(const statement::Parameter *node); + + /** + * \brief Adds a new hasParameter edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasParameter edge. + */ + void addParameter(NodeId id); + + /** + * \brief Remove the hasParameter edge by id from the node. + * \param id [in] The end point of the hasParameter edge. + */ + void removeParameter(NodeId id); + + /** + * \brief Remove the hasParameter edge from the node. + * \param node [in] The end point of the hasParameter edge. + */ + void removeParameter(statement::Parameter *node); + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasObject edge points to. */ + ListIterator::Container hasObjectContainer; + + /** \internal \brief Container stores the id of the nodes the hasParameter edge points to. */ + ListIterator::Container hasParameterContainer; + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/List.h b/lib/python/inc/expression/List.h new file mode 100644 index 0000000..1c32534 --- /dev/null +++ b/lib/python/inc/expression/List.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_List_H_ +#define _PYTHON_List_H_ + +#include "python/inc/python.h" + +/** +* \file List.h +* \brief Contains declaration of the expression::List class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief List class, which represents the expression::List node. + * (missing) + * + * Attributes: + * - isTuple (boolean) : (missing) + * + * Edges: + * - hasExpression (expression::Expression, multiple) : (missing) + */ + class List : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + List(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~List(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + List & operator=(const List&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + List(const List&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the isTuple of the node. + * \return Returns with the isTuple. + */ + bool getIsTuple() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the isTuple of the node. + * \param isTuple [in] The new value of the isTuple. + */ + void setIsTuple(bool _isTuple); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief Stores whether the node is `Tuple` or not. */ + bool m_isTuple : 1; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasExpression edges. + * \return Returns an iterator for the hasExpression edges. + */ + ListIterator getExpressionListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasExpression edges. + * \return Returns an iterator for the hasExpression edges. + */ + ListIterator getExpressionListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasExpression edges or not. + * \return Returns true if the node doesn't have any hasExpression edge. + */ + bool getExpressionIsEmpty() const; + + /** + * \brief Gives back how many hasExpression edges the node has. + * \return Returns with the number of hasExpression edges. + */ + unsigned getExpressionSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasExpression edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasExpression edge. + */ + void addExpression(const Expression *node); + + /** + * \brief Adds a new hasExpression edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasExpression edge. + */ + void addExpression(NodeId id); + + /** + * \brief Remove the hasExpression edge by id from the node. + * \param id [in] The end point of the hasExpression edge. + */ + void removeExpression(NodeId id); + + /** + * \brief Remove the hasExpression edge from the node. + * \param node [in] The end point of the hasExpression edge. + */ + void removeExpression(Expression *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasExpression edge points to. */ + ListIterator::Container hasExpressionContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/ListComp.h b/lib/python/inc/expression/ListComp.h new file mode 100644 index 0000000..841e20c --- /dev/null +++ b/lib/python/inc/expression/ListComp.h @@ -0,0 +1,252 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ListComp_H_ +#define _PYTHON_ListComp_H_ + +#include "python/inc/python.h" + +/** +* \file ListComp.h +* \brief Contains declaration of the expression::ListComp class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief ListComp class, which represents the expression::ListComp node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + * - hasGenerator (expression::Generator, multiple) : (missing) + */ + class ListComp : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ListComp(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ListComp(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ListComp & operator=(const ListComp&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ListComp(const ListComp&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasGenerator edges or not. + * \return Returns true if the node doesn't have any hasGenerator edge. + */ + bool getGeneratorIsEmpty() const; + + /** + * \brief Gives back how many hasGenerator edges the node has. + * \return Returns with the number of hasGenerator edges. + */ + unsigned getGeneratorSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasGenerator edge. + */ + void addGenerator(const Generator *node); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasGenerator edge. + */ + void addGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge by id from the node. + * \param id [in] The end point of the hasGenerator edge. + */ + void removeGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge from the node. + * \param node [in] The end point of the hasGenerator edge. + */ + void removeGenerator(Generator *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + /** \internal \brief Container stores the id of the nodes the hasGenerator edge points to. */ + ListIterator::Container hasGeneratorContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Literal.h b/lib/python/inc/expression/Literal.h new file mode 100644 index 0000000..323dbd8 --- /dev/null +++ b/lib/python/inc/expression/Literal.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Literal_H_ +#define _PYTHON_Literal_H_ + +#include "python/inc/python.h" + +/** +* \file Literal.h +* \brief Contains declaration of the expression::Literal class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Literal class, which represents the expression::Literal node. + * (missing) + */ + class Literal : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Literal(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Literal(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Literal & operator=(const Literal&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Literal(const Literal&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/LongInteger.h b/lib/python/inc/expression/LongInteger.h new file mode 100644 index 0000000..824d673 --- /dev/null +++ b/lib/python/inc/expression/LongInteger.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_LongInteger_H_ +#define _PYTHON_LongInteger_H_ + +#include "python/inc/python.h" + +/** +* \file LongInteger.h +* \brief Contains declaration of the expression::LongInteger class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief LongInteger class, which represents the expression::LongInteger node. + * (missing) + * + * Attributes: + * - value (int) : (missing) + */ + class LongInteger : public Literal { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + LongInteger(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~LongInteger(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + LongInteger & operator=(const LongInteger&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + LongInteger(const LongInteger&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the value of the node. + * \return Returns with the value. + */ + int getValue() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the value of the node. + * \param value [in] The new value of the value. + */ + void setValue(int _value); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `value`. */ + int m_value; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Set.h b/lib/python/inc/expression/Set.h new file mode 100644 index 0000000..6a972f4 --- /dev/null +++ b/lib/python/inc/expression/Set.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Set_H_ +#define _PYTHON_Set_H_ + +#include "python/inc/python.h" + +/** +* \file Set.h +* \brief Contains declaration of the expression::Set class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Set class, which represents the expression::Set node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, multiple) : (missing) + */ + class Set : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Set(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Set(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Set & operator=(const Set&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Set(const Set&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasExpression edges. + * \return Returns an iterator for the hasExpression edges. + */ + ListIterator getExpressionListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasExpression edges. + * \return Returns an iterator for the hasExpression edges. + */ + ListIterator getExpressionListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasExpression edges or not. + * \return Returns true if the node doesn't have any hasExpression edge. + */ + bool getExpressionIsEmpty() const; + + /** + * \brief Gives back how many hasExpression edges the node has. + * \return Returns with the number of hasExpression edges. + */ + unsigned getExpressionSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasExpression edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasExpression edge. + */ + void addExpression(const Expression *node); + + /** + * \brief Adds a new hasExpression edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasExpression edge. + */ + void addExpression(NodeId id); + + /** + * \brief Remove the hasExpression edge by id from the node. + * \param id [in] The end point of the hasExpression edge. + */ + void removeExpression(NodeId id); + + /** + * \brief Remove the hasExpression edge from the node. + * \param node [in] The end point of the hasExpression edge. + */ + void removeExpression(Expression *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasExpression edge points to. */ + ListIterator::Container hasExpressionContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/SetComp.h b/lib/python/inc/expression/SetComp.h new file mode 100644 index 0000000..89196cf --- /dev/null +++ b/lib/python/inc/expression/SetComp.h @@ -0,0 +1,252 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_SetComp_H_ +#define _PYTHON_SetComp_H_ + +#include "python/inc/python.h" + +/** +* \file SetComp.h +* \brief Contains declaration of the expression::SetComp class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief SetComp class, which represents the expression::SetComp node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + * - hasGenerator (expression::Generator, multiple) : (missing) + */ + class SetComp : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + SetComp(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~SetComp(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SetComp & operator=(const SetComp&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SetComp(const SetComp&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasGenerator edges. + * \return Returns an iterator for the hasGenerator edges. + */ + ListIterator getGeneratorListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasGenerator edges or not. + * \return Returns true if the node doesn't have any hasGenerator edge. + */ + bool getGeneratorIsEmpty() const; + + /** + * \brief Gives back how many hasGenerator edges the node has. + * \return Returns with the number of hasGenerator edges. + */ + unsigned getGeneratorSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasGenerator edge. + */ + void addGenerator(const Generator *node); + + /** + * \brief Adds a new hasGenerator edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasGenerator edge. + */ + void addGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge by id from the node. + * \param id [in] The end point of the hasGenerator edge. + */ + void removeGenerator(NodeId id); + + /** + * \brief Remove the hasGenerator edge from the node. + * \param node [in] The end point of the hasGenerator edge. + */ + void removeGenerator(Generator *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + /** \internal \brief Container stores the id of the nodes the hasGenerator edge points to. */ + ListIterator::Container hasGeneratorContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Slice.h b/lib/python/inc/expression/Slice.h new file mode 100644 index 0000000..2504782 --- /dev/null +++ b/lib/python/inc/expression/Slice.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Slice_H_ +#define _PYTHON_Slice_H_ + +#include "python/inc/python.h" + +/** +* \file Slice.h +* \brief Contains declaration of the expression::Slice class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Slice class, which represents the expression::Slice node. + * (missing) + * + * Edges: + * - hasLowerBound (expression::Expression, single) : (missing) + * - hasStride (expression::Expression, single) : (missing) + * - hasUpperBound (expression::Expression, single) : (missing) + */ + class Slice : public Slicing { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Slice(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Slice(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Slice & operator=(const Slice&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Slice(const Slice&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasLowerBound edge points to. + * \return Returns the end point of the hasLowerBound edge. + */ + expression::Expression* getLowerBound() const; + + /** + * \brief Gives back the pointer of the node the hasStride edge points to. + * \return Returns the end point of the hasStride edge. + */ + expression::Expression* getStride() const; + + /** + * \brief Gives back the pointer of the node the hasUpperBound edge points to. + * \return Returns the end point of the hasUpperBound edge. + */ + expression::Expression* getUpperBound() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasLowerBound edge. + * \param id [in] The new end point of the hasLowerBound edge. + */ + void setLowerBound(NodeId id); + + /** + * \brief Sets the hasLowerBound edge. + * \param node [in] The new end point of the hasLowerBound edge. + */ + void setLowerBound(Expression *node); + + /** + * \brief remove the hasLowerBound edge. + */ + void removeLowerBound(); + + /** + * \brief Sets the hasStride edge. + * \param id [in] The new end point of the hasStride edge. + */ + void setStride(NodeId id); + + /** + * \brief Sets the hasStride edge. + * \param node [in] The new end point of the hasStride edge. + */ + void setStride(Expression *node); + + /** + * \brief remove the hasStride edge. + */ + void removeStride(); + + /** + * \brief Sets the hasUpperBound edge. + * \param id [in] The new end point of the hasUpperBound edge. + */ + void setUpperBound(NodeId id); + + /** + * \brief Sets the hasUpperBound edge. + * \param node [in] The new end point of the hasUpperBound edge. + */ + void setUpperBound(Expression *node); + + /** + * \brief remove the hasUpperBound edge. + */ + void removeUpperBound(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasLowerBound edge points to. */ + NodeId m_hasLowerBound; + + /** \internal \brief The id of the node the hasStride edge points to. */ + NodeId m_hasStride; + + /** \internal \brief The id of the node the hasUpperBound edge points to. */ + NodeId m_hasUpperBound; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Slicing.h b/lib/python/inc/expression/Slicing.h new file mode 100644 index 0000000..dca30c9 --- /dev/null +++ b/lib/python/inc/expression/Slicing.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Slicing_H_ +#define _PYTHON_Slicing_H_ + +#include "python/inc/python.h" + +/** +* \file Slicing.h +* \brief Contains declaration of the expression::Slicing class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Slicing class, which represents the expression::Slicing node. + * (missing) + */ + class Slicing : public Unary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Slicing(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Slicing(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Slicing & operator=(const Slicing&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Slicing(const Slicing&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/StringConversion.h b/lib/python/inc/expression/StringConversion.h new file mode 100644 index 0000000..0587d1d --- /dev/null +++ b/lib/python/inc/expression/StringConversion.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_StringConversion_H_ +#define _PYTHON_StringConversion_H_ + +#include "python/inc/python.h" + +/** +* \file StringConversion.h +* \brief Contains declaration of the expression::StringConversion class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief StringConversion class, which represents the expression::StringConversion node. + * (missing) + * + * Edges: + * - hasExpressionList (expression::ExpressionList, single) : (missing) + */ + class StringConversion : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + StringConversion(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~StringConversion(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + StringConversion & operator=(const StringConversion&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + StringConversion(const StringConversion&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpressionList edge points to. + * \return Returns the end point of the hasExpressionList edge. + */ + expression::ExpressionList* getExpressionList() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpressionList edge. + * \param id [in] The new end point of the hasExpressionList edge. + */ + void setExpressionList(NodeId id); + + /** + * \brief Sets the hasExpressionList edge. + * \param node [in] The new end point of the hasExpressionList edge. + */ + void setExpressionList(ExpressionList *node); + + /** + * \brief remove the hasExpressionList edge. + */ + void removeExpressionList(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpressionList edge points to. */ + NodeId m_hasExpressionList; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/StringLiteral.h b/lib/python/inc/expression/StringLiteral.h new file mode 100644 index 0000000..2d85373 --- /dev/null +++ b/lib/python/inc/expression/StringLiteral.h @@ -0,0 +1,202 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_StringLiteral_H_ +#define _PYTHON_StringLiteral_H_ + +#include "python/inc/python.h" + +/** +* \file StringLiteral.h +* \brief Contains declaration of the expression::StringLiteral class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief StringLiteral class, which represents the expression::StringLiteral node. + * (missing) + * + * Attributes: + * - value (String) : (missing) + */ + class StringLiteral : public Literal { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + StringLiteral(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~StringLiteral(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + StringLiteral & operator=(const StringLiteral&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + StringLiteral(const StringLiteral&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the value of the node. + * \return Returns with the value. + */ + const std::string& getValue() const; + + /** + * \brief Gives back the Key of value of the node. + * \return Returns with the Key of the value. + */ + Key getValueKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the value of the node. + * \param value [in] The new value of the value. + */ + void setValue(const std::string& _value); + + /** + * \internal + * \brief Sets the value of the node. + * \param value [in] The new Key of the value. + */ + void setValueKey(Key _value); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `value`. */ + Key m_value; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Subscription.h b/lib/python/inc/expression/Subscription.h new file mode 100644 index 0000000..8e19df0 --- /dev/null +++ b/lib/python/inc/expression/Subscription.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Subscription_H_ +#define _PYTHON_Subscription_H_ + +#include "python/inc/python.h" + +/** +* \file Subscription.h +* \brief Contains declaration of the expression::Subscription class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Subscription class, which represents the expression::Subscription node. + * (missing) + * + * Edges: + * - hasSlicing (expression::Slicing, single) : (missing) + */ + class Subscription : public Unary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Subscription(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Subscription(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Subscription & operator=(const Subscription&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Subscription(const Subscription&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasSlicing edge points to. + * \return Returns the end point of the hasSlicing edge. + */ + expression::Slicing* getSlicing() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasSlicing edge. + * \param id [in] The new end point of the hasSlicing edge. + */ + void setSlicing(NodeId id); + + /** + * \brief Sets the hasSlicing edge. + * \param node [in] The new end point of the hasSlicing edge. + */ + void setSlicing(Slicing *node); + + /** + * \brief remove the hasSlicing edge. + */ + void removeSlicing(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasSlicing edge points to. */ + NodeId m_hasSlicing; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/Unary.h b/lib/python/inc/expression/Unary.h new file mode 100644 index 0000000..dd950fb --- /dev/null +++ b/lib/python/inc/expression/Unary.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Unary_H_ +#define _PYTHON_Unary_H_ + +#include "python/inc/python.h" + +/** +* \file Unary.h +* \brief Contains declaration of the expression::Unary class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief Unary class, which represents the expression::Unary node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + */ + class Unary : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Unary(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Unary(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Unary & operator=(const Unary&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Unary(const Unary&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/UnaryOperation.h b/lib/python/inc/expression/UnaryOperation.h new file mode 100644 index 0000000..a2e4fc4 --- /dev/null +++ b/lib/python/inc/expression/UnaryOperation.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_UnaryOperation_H_ +#define _PYTHON_UnaryOperation_H_ + +#include "python/inc/python.h" + +/** +* \file UnaryOperation.h +* \brief Contains declaration of the expression::UnaryOperation class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief UnaryOperation class, which represents the expression::UnaryOperation node. + * (missing) + * + * Attributes: + * - kind (UnaryKind) : (missing) + */ + class UnaryOperation : public Unary { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + UnaryOperation(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~UnaryOperation(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + UnaryOperation & operator=(const UnaryOperation&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + UnaryOperation(const UnaryOperation&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + UnaryKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(UnaryKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The UnaryKind of the node. */ + UnaryKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/expression/YieldExpression.h b/lib/python/inc/expression/YieldExpression.h new file mode 100644 index 0000000..58c014c --- /dev/null +++ b/lib/python/inc/expression/YieldExpression.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_YieldExpression_H_ +#define _PYTHON_YieldExpression_H_ + +#include "python/inc/python.h" + +/** +* \file YieldExpression.h +* \brief Contains declaration of the expression::YieldExpression class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace expression { + + /** + * \brief YieldExpression class, which represents the expression::YieldExpression node. + * (missing) + * + * Edges: + * - hasYieldExpression (expression::ExpressionList, single) : (missing) + */ + class YieldExpression : public Expression { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + YieldExpression(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~YieldExpression(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + YieldExpression & operator=(const YieldExpression&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + YieldExpression(const YieldExpression&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasYieldExpression edge points to. + * \return Returns the end point of the hasYieldExpression edge. + */ + expression::ExpressionList* getYieldExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasYieldExpression edge. + * \param id [in] The new end point of the hasYieldExpression edge. + */ + void setYieldExpression(NodeId id); + + /** + * \brief Sets the hasYieldExpression edge. + * \param node [in] The new end point of the hasYieldExpression edge. + */ + void setYieldExpression(ExpressionList *node); + + /** + * \brief remove the hasYieldExpression edge. + */ + void removeYieldExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasYieldExpression edge points to. */ + NodeId m_hasYieldExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/messages.h b/lib/python/inc/messages.h new file mode 100644 index 0000000..24a831e --- /dev/null +++ b/lib/python/inc/messages.h @@ -0,0 +1,74 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_M_H_ +#define _PYTHON_M_H_ + +#define CMSG_THE_NODE_LOADED common::WriteMsg::mlDDDebug, "DDDebug: The %d node is loaded(%s)\n" +#define CMSG_THE_NODE_HAVE_BEEN_DESTROYED common::WriteMsg::mlDDDebug, "DDDebug: The node %u has been destroyed\n" +#define CMSG_SELECTOR_FUNCTION_IS_CHANGED common::WriteMsg::mlDebug, "Debug: Selector function is changed\n" +#define CMSG_NODE_CREATED_THE_MIRROR_OF common::WriteMsg::mlDDDDebug, "DDDDebug: The %d node created the mirror of %d node in the src\n" +#define CMSG_NODE_PARENT_IS common::WriteMsg::mlDDDDebug, "DDDDebug: The parent of the %d node is %d node in the src\n" +#define CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE common::WriteMsg::mlDebug, "Debug: The pre order has touched a node twice (id: %d, type: %s)\n" +#define CMSG_HAS_ALREADY_PARENT_THE_PARENT_WAS common::WriteMsg::mlDDDebug, "DDDebug: The %d (%s) already has a parent. The parent was %d (%s). The new parent is %d (%s)\n" +#define CMSG_SHOW_HEX_VALUE common::WriteMsg::mlDDDebug, " [%X] " +#define CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN common::WriteMsg::mlDDDebug, "DDDebug: Get the node hash of %u node [" +#define CMSG_GET_THE_NODE_HASH_OF_NODE_END common::WriteMsg::mlDDDebug, " =(%X) ] \n" +#define CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP common::WriteMsg::mlDDDebug, "The hash generator found a circle ] \n" +#define CMSG_REMOVE_FORWARD_EDGE_FORM common::WriteMsg::mlDDDebug, "DDDebug: Removing forward edge (form: %u, to: %u)\n" +#define CMSG_SORT_DUPLICATED_EDGE_NAMES_AT_NODE common::WriteMsg::mlWarning, "Warning: Duplicated string representation is found while sorting the '%s' edges of node %u (%s): %s" +#define CMSG_SORT_DUPLICATED_EDGE_DATA common::WriteMsg::mlWarning, "Warning: End point: %u (%s)" + +#define CMSG_EX_YOU_MUST_GIVE_A_FACTORY_AT_FIRST "A factory must be given first" +#define CMSG_EX_DON_T_HAVE_ANY_VISITOR "Do not have any visitor" +#define CMSG_EX_MISSING_FILE_TYPE_INFORMATION "Missing file type information" +#define CMSG_EX_WRONG_FILE_TYPE_INFORMATION "Wrong file type information" +#define CMSG_EX_MISSING_API_VERSION_INFORMATION "Missing API version information" +#define CMSG_EX_WRONG_API_VERSION(APVER_REQ, APVER_FOUND) "Wrong API version (" + APVER_REQ + " required, " + APVER_FOUND + " found)" +#define CMSG_EX_MISSING_BINARY_VERSION_INFORMATION "Missing binary version information" +#define CMSG_EX_WRONG_BINARY_VERSION(BINVER_REQ, BINVER_FOUND) "Wrong binary version (" + BINVER_REQ + " required, " + BINVER_FOUND + " found)" +#define CMSG_EX_INVALID_ASSOCIATION_CLASS_TYPE(TYPE) "Invalid association class type (" + TYPE + ")" +#define CMSG_EX_INVALID_NODE_ID(ID) "Invalid NodeId (" + Common::toString(ID) + ")" +#define CMSG_EX_YOU_MUST_ENABLE_THE_REVERSE_EDGE_FIRST "The reverse edge must be enabled first" +#define CMSG_EX_THE_NODE_DOES_NOT_EXISTS "The node does not exist" +#define CMSG_EX_NEXT_ELEMENT_DOES_NOT_EXIST "Next element does not exist" +#define CMSG_EX_THE_LOADED_FILTER_DOES_NOT_MATCH_TO_THE_CURRENT "The loaded filter does not match to the current ASG" +#define CMSG_EX_INVALID_NODE_KIND "Invalid node kind" +#define CMSG_EX_INVALID_EDGE_KIND "Invalid edge kind" +#define CMSG_EX_THE_ITERATOR_IS_INVALID "The iterator is invalid" +#define CMSG_EX_CAN_T_SET_ASSOCIATION_EDGE(EDGEKIND) "Cannot set the association edge by this method (edgeKind: " + Common::toString( EDGEKIND ) + ")" +#define CMSG_EX_THE_NODE_IS_NULL "The node is null" +#define CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH "The factory of the nodes does not match" +#define CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST "The end point of the edge does not exist" +#define CMSG_EX_CAN_T_SET_EDGE_TO_NULL "Cannot set the edge to null (if it is necessary the remove function should be called)" +#define CMSG_EX_THE_EDGE_IS_NULL "The edge is null" +#define CMSG_EX_IN_CASE_THE_NODE_HAS_MORE_RANGES "In case the node has more ranges you must not use this method" +#define CMSG_EX_THE_NODE_HAS_THE_SAME_ATTRIBUTES(ID, ATTRIBUTENAME) "The node id" + Common::toString(ID) + " has the same attributes (" + ATTRIBUTENAME + ")" +#define CMSG_EX_NO_REVERSE_EDGE_INFORMATION_FOR(ID) "No reverse edge information for NodeId ("+ Common::toString(ID) + ")" +#define CMSG_EX_WRONG_NODE_KIND_FOR "Wrong node kind for '" #name "'" +#define CMSG_EX_UNTIL_NO_STRTABLE_IS_SET_THE_SETPATH "The setPath() can not be used until setting strTable" +#define CMSG_EX_NEITHER_NEXT_NOR_PREVIOUS_HAVE_BEEN_CALLED "Neither next() nor previous() have been called, or remove() or add() have been called after the last call to next() or previous()" +#define CMSG_EX_THE_ITERATION_HAS_NOT_NEXT_ELEMENT "The iteration does not have next element" +#define CMSG_EX_THE_ITERATION_HAS_NOT_PREVIOUS_ELEMENT "The iteration does not have previous element" + +#define CMSG_PATH_DOES_NOT_EXIST common::WriteMsg::mlWarning, "Warning: Path does not exist: %s\n" +#define CMSG_FILESYSTEM_ERROR common::WriteMsg::mlError, "Error: FileSystem error: %s\n" + +#endif diff --git a/lib/python/inc/module/Module.h b/lib/python/inc/module/Module.h new file mode 100644 index 0000000..1f86b20 --- /dev/null +++ b/lib/python/inc/module/Module.h @@ -0,0 +1,333 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Module_H_ +#define _PYTHON_Module_H_ + +#include "python/inc/python.h" + +/** +* \file Module.h +* \brief Contains declaration of the module::Module class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace module { + + /** + * \brief Module class, which represents the module::Module node. + * (missing) + * + * Attributes: + * - lloc (int) : (missing) + * + * Edges: + * - hasObject (module::Object, multiple) : (missing) + * - hasStatement (base::Positioned, multiple) : (missing) + * - docstring (base::Docstring, single) : (missing) + */ + class Module : public base::Named { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Module(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Module(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Module & operator=(const Module&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Module(const Module&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the lloc of the node. + * \return Returns with the lloc. + */ + int getLloc() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the lloc of the node. + * \param lloc [in] The new value of the lloc. + */ + void setLloc(int _lloc); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `lloc`. */ + int m_lloc; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasObject edges or not. + * \return Returns true if the node doesn't have any hasObject edge. + */ + bool getObjectIsEmpty() const; + + /** + * \brief Gives back how many hasObject edges the node has. + * \return Returns with the number of hasObject edges. + */ + unsigned getObjectSize() const; + + /** + * \brief Gives back iterator for the hasStatement edges. + * \return Returns an iterator for the hasStatement edges. + */ + ListIterator getStatementListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasStatement edges. + * \return Returns an iterator for the hasStatement edges. + */ + ListIterator getStatementListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasStatement edges or not. + * \return Returns true if the node doesn't have any hasStatement edge. + */ + bool getStatementIsEmpty() const; + + /** + * \brief Gives back how many hasStatement edges the node has. + * \return Returns with the number of hasStatement edges. + */ + unsigned getStatementSize() const; + + /** + * \brief Gives back the pointer of the node the docstring edge points to. + * \return Returns the end point of the docstring edge. + */ + base::Docstring* getDocstring() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasObject edge. + */ + void addObject(const Object *node); + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasObject edge. + */ + void addObject(NodeId id); + + /** + * \brief Remove the hasObject edge by id from the node. + * \param id [in] The end point of the hasObject edge. + */ + void removeObject(NodeId id); + + /** + * \brief Remove the hasObject edge from the node. + * \param node [in] The end point of the hasObject edge. + */ + void removeObject(Object *node); + + /** + * \brief Adds a new hasStatement edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasStatement edge. + */ + void addStatement(const base::Positioned *node); + + /** + * \brief Adds a new hasStatement edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasStatement edge. + */ + void addStatement(NodeId id); + + /** + * \brief Remove the hasStatement edge by id from the node. + * \param id [in] The end point of the hasStatement edge. + */ + void removeStatement(NodeId id); + + /** + * \brief Remove the hasStatement edge from the node. + * \param node [in] The end point of the hasStatement edge. + */ + void removeStatement(base::Positioned *node); + + /** + * \brief Sets the docstring edge. + * \param id [in] The new end point of the docstring edge. + */ + void setDocstring(NodeId id); + + /** + * \brief Sets the docstring edge. + * \param node [in] The new end point of the docstring edge. + */ + void setDocstring(base::Docstring *node); + + /** + * \brief remove the docstring edge. + */ + void removeDocstring(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasObject edge points to. */ + ListIterator::Container hasObjectContainer; + + /** \internal \brief Container stores the id of the nodes the hasStatement edge points to. */ + ListIterator::Container hasStatementContainer; + + /** \internal \brief The id of the node the docstring edge points to. */ + NodeId m_docstring; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/module/Object.h b/lib/python/inc/module/Object.h new file mode 100644 index 0000000..b1bdb2b --- /dev/null +++ b/lib/python/inc/module/Object.h @@ -0,0 +1,319 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Object_H_ +#define _PYTHON_Object_H_ + +#include "python/inc/python.h" + +/** +* \file Object.h +* \brief Contains declaration of the module::Object class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace module { + + /** + * \brief Object class, which represents the module::Object node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + * + * Edges: + * - refersTo (base::Positioned, multiple) : (missing) + * - hasType (type::Type, multiple) : (missing) + */ + class Object : public base::Base { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Object(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Object(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Object & operator=(const Object&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Object(const Object&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the refersTo edges. + * \return Returns an iterator for the refersTo edges. + */ + ListIterator getRefersToListIteratorBegin() const; + + /** + * \brief Gives back iterator for the refersTo edges. + * \return Returns an iterator for the refersTo edges. + */ + ListIterator getRefersToListIteratorEnd() const; + + /** + * \brief Tells whether the node has refersTo edges or not. + * \return Returns true if the node doesn't have any refersTo edge. + */ + bool getRefersToIsEmpty() const; + + /** + * \brief Gives back how many refersTo edges the node has. + * \return Returns with the number of refersTo edges. + */ + unsigned getRefersToSize() const; + + /** + * \brief Gives back iterator for the hasType edges. + * \return Returns an iterator for the hasType edges. + */ + ListIterator getTypeListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasType edges. + * \return Returns an iterator for the hasType edges. + */ + ListIterator getTypeListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasType edges or not. + * \return Returns true if the node doesn't have any hasType edge. + */ + bool getTypeIsEmpty() const; + + /** + * \brief Gives back how many hasType edges the node has. + * \return Returns with the number of hasType edges. + */ + unsigned getTypeSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new refersTo edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new refersTo edge. + */ + void addRefersTo(const base::Positioned *node); + + /** + * \brief Adds a new refersTo edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new refersTo edge. + */ + void addRefersTo(NodeId id); + + /** + * \brief Remove the refersTo edge by id from the node. + * \param id [in] The end point of the refersTo edge. + */ + void removeRefersTo(NodeId id); + + /** + * \brief Remove the refersTo edge from the node. + * \param node [in] The end point of the refersTo edge. + */ + void removeRefersTo(base::Positioned *node); + + /** + * \brief Adds a new hasType edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasType edge. + */ + void addType(const type::Type *node); + + /** + * \brief Adds a new hasType edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasType edge. + */ + void addType(NodeId id); + + /** + * \brief Remove the hasType edge by id from the node. + * \param id [in] The end point of the hasType edge. + */ + void removeType(NodeId id); + + /** + * \brief Remove the hasType edge from the node. + * \param node [in] The end point of the hasType edge. + */ + void removeType(type::Type *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the refersTo edge points to. */ + ListIterator::Container refersToContainer; + + /** \internal \brief Container stores the id of the nodes the hasType edge points to. */ + ListIterator::Container hasTypeContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/module/Package.h b/lib/python/inc/module/Package.h new file mode 100644 index 0000000..b4f035e --- /dev/null +++ b/lib/python/inc/module/Package.h @@ -0,0 +1,349 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Package_H_ +#define _PYTHON_Package_H_ + +#include "python/inc/python.h" + +/** +* \file Package.h +* \brief Contains declaration of the module::Package class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace module { + + /** + * \brief Package class, which represents the module::Package node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + * - path (String) : (missing) + * + * Edges: + * - hasModule (module::Module, multiple) : (missing) + * - hasPackage (module::Package, multiple) : (missing) + */ + class Package : public base::Base { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Package(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Package(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Package & operator=(const Package&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Package(const Package&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + /** + * \brief Gives back the path of the node. + * \return Returns with the path. + */ + const std::string& getPath() const; + + /** + * \brief Gives back the Key of path of the node. + * \return Returns with the Key of the path. + */ + Key getPathKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the path of the node. + * \param path [in] The new value of the path. + */ + void setPath(const std::string& _path); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + /** + * \internal + * \brief Sets the path of the node. + * \param path [in] The new Key of the path. + */ + void setPathKey(Key _path); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + /** \internal \brief The Key of the `path`. */ + Key m_path; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasModule edges. + * \return Returns an iterator for the hasModule edges. + */ + ListIterator getModuleListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasModule edges. + * \return Returns an iterator for the hasModule edges. + */ + ListIterator getModuleListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasModule edges or not. + * \return Returns true if the node doesn't have any hasModule edge. + */ + bool getModuleIsEmpty() const; + + /** + * \brief Gives back how many hasModule edges the node has. + * \return Returns with the number of hasModule edges. + */ + unsigned getModuleSize() const; + + /** + * \brief Gives back iterator for the hasPackage edges. + * \return Returns an iterator for the hasPackage edges. + */ + ListIterator getPackageListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasPackage edges. + * \return Returns an iterator for the hasPackage edges. + */ + ListIterator getPackageListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasPackage edges or not. + * \return Returns true if the node doesn't have any hasPackage edge. + */ + bool getPackageIsEmpty() const; + + /** + * \brief Gives back how many hasPackage edges the node has. + * \return Returns with the number of hasPackage edges. + */ + unsigned getPackageSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasModule edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasModule edge. + */ + void addModule(const Module *node); + + /** + * \brief Adds a new hasModule edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasModule edge. + */ + void addModule(NodeId id); + + /** + * \brief Remove the hasModule edge by id from the node. + * \param id [in] The end point of the hasModule edge. + */ + void removeModule(NodeId id); + + /** + * \brief Remove the hasModule edge from the node. + * \param node [in] The end point of the hasModule edge. + */ + void removeModule(Module *node); + + /** + * \brief Adds a new hasPackage edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasPackage edge. + */ + void addPackage(const Package *node); + + /** + * \brief Adds a new hasPackage edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasPackage edge. + */ + void addPackage(NodeId id); + + /** + * \brief Remove the hasPackage edge by id from the node. + * \param id [in] The end point of the hasPackage edge. + */ + void removePackage(NodeId id); + + /** + * \brief Remove the hasPackage edge from the node. + * \param node [in] The end point of the hasPackage edge. + */ + void removePackage(Package *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasModule edge points to. */ + ListIterator::Container hasModuleContainer; + + /** \internal \brief Container stores the id of the nodes the hasPackage edge points to. */ + ListIterator::Container hasPackageContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/python.h b/lib/python/inc/python.h new file mode 100644 index 0000000..39cdbea --- /dev/null +++ b/lib/python/inc/python.h @@ -0,0 +1,156 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_H_ +#define _PYTHON_H_ + +/** +* \file PYTHON.h +* \brief Header can be used for precompiled header. +*/ +#include +#include +#include +#include +#include +#include + +#include "Forwards.h" + +// externals +#include "AsgCommon.h" +#include "strtable/inc/RefDistributorStrTable.h" +#include "csi/inc/csi.h" +#include "Exception.h" + +#include "Constant.h" +#include "Types.h" +#include "Range.h" +#include "PythonException.h" +#include "ListIterator.h" +#include "Common.h" +#include "ReverseEdges.h" + + + /***********************NODES******************/ +#include "base/Base.h" +#include "base/Positioned.h" +#include "module/Object.h" +#include "module/Package.h" +#include "type/Type.h" +#include "base/Comment.h" +#include "base/Docstring.h" +#include "base/Named.h" +#include "expression/ArgumentList.h" +#include "expression/Expression.h" +#include "expression/Generator.h" +#include "expression/KeyValue.h" +#include "expression/Keyword.h" +#include "statement/BaseSpecifier.h" +#include "statement/Statement.h" +#include "statement/Suite.h" +#include "statement/TargetList.h" +#include "type/DictType.h" +#include "type/ReferenceType.h" +#include "type/SequenceType.h" +#include "type/SimpleType.h" +#include "module/Module.h" +#include "statement/Alias.h" +#include "statement/Parameter.h" +#include "expression/Binary.h" +#include "expression/DictComp.h" +#include "expression/Dictionary.h" +#include "expression/ExpressionList.h" +#include "expression/GeneratorExpression.h" +#include "expression/Identifier.h" +#include "expression/IfExpression.h" +#include "expression/Lambda.h" +#include "expression/List.h" +#include "expression/ListComp.h" +#include "expression/Literal.h" +#include "expression/Set.h" +#include "expression/SetComp.h" +#include "expression/StringConversion.h" +#include "expression/Unary.h" +#include "expression/YieldExpression.h" +#include "statement/CompoundStatement.h" +#include "statement/Handler.h" +#include "statement/SimpleStatement.h" +#include "expression/AttributeRef.h" +#include "expression/BinaryArithmetic.h" +#include "expression/BinaryLogical.h" +#include "expression/FloatNumber.h" +#include "expression/ImagNumber.h" +#include "expression/IntegerLiteral.h" +#include "expression/LongInteger.h" +#include "expression/StringLiteral.h" +#include "expression/Call.h" +#include "expression/Slicing.h" +#include "expression/Subscription.h" +#include "expression/UnaryOperation.h" +#include "statement/ClassDef.h" +#include "statement/FunctionDef.h" +#include "statement/If.h" +#include "statement/Iteration.h" +#include "statement/Try.h" +#include "statement/With.h" +#include "statement/Assert.h" +#include "statement/Assign.h" +#include "statement/Break.h" +#include "statement/Continue.h" +#include "statement/Delete.h" +#include "statement/Exec.h" +#include "statement/Global.h" +#include "statement/ImportStatement.h" +#include "statement/Pass.h" +#include "statement/Print.h" +#include "statement/Raise.h" +#include "statement/Return.h" +#include "expression/Ellipsis.h" +#include "expression/ExtSlice.h" +#include "expression/Index.h" +#include "expression/Slice.h" +#include "statement/For.h" +#include "statement/While.h" +#include "statement/TryExcept.h" +#include "statement/TryFinal.h" +#include "statement/AugAssign.h" +#include "statement/ImportFrom.h" + + +#include "Filter.h" +#include "Factory.h" + +#include "visitors/Visitor.h" +#include "visitors/VisitorAbstractNodes.h" +#include "visitors/VisitorPYTHONML.h" +#include "visitors/VisitorFilter.h" +#include "visitors/VisitorReverseEdges.h" +#include "visitors/VisitorSave.h" +#include "visitors/VisitorSubtreeCollector.h" +#include "visitors/VisitorSimpleEdge.h" +#include "Range.h" + +#include "algorithms/Algorithm.h" +#include "algorithms/AlgorithmPreorder.h" +#include "PythonCollector.h" + +#endif + diff --git a/lib/python/inc/statement/Alias.h b/lib/python/inc/statement/Alias.h new file mode 100644 index 0000000..3f72bdb --- /dev/null +++ b/lib/python/inc/statement/Alias.h @@ -0,0 +1,242 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Alias_H_ +#define _PYTHON_Alias_H_ + +#include "python/inc/python.h" + +/** +* \file Alias.h +* \brief Contains declaration of the statement::Alias class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Alias class, which represents the statement::Alias node. + * (missing) + * + * Attributes: + * - alias (String) : (missing) + * + * Edges: + * - refersTo (base::Base, single) : (missing) + */ + class Alias : public base::Named { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Alias(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Alias(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Alias & operator=(const Alias&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Alias(const Alias&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the alias of the node. + * \return Returns with the alias. + */ + const std::string& getAlias() const; + + /** + * \brief Gives back the Key of alias of the node. + * \return Returns with the Key of the alias. + */ + Key getAliasKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the alias of the node. + * \param alias [in] The new value of the alias. + */ + void setAlias(const std::string& _alias); + + /** + * \internal + * \brief Sets the alias of the node. + * \param alias [in] The new Key of the alias. + */ + void setAliasKey(Key _alias); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `alias`. */ + Key m_alias; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + base::Base* getRefersTo() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(base::Base *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Assert.h b/lib/python/inc/statement/Assert.h new file mode 100644 index 0000000..a26170d --- /dev/null +++ b/lib/python/inc/statement/Assert.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Assert_H_ +#define _PYTHON_Assert_H_ + +#include "python/inc/python.h" + +/** +* \file Assert.h +* \brief Contains declaration of the statement::Assert class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Assert class, which represents the statement::Assert node. + * (missing) + * + * Edges: + * - hasMsgExpression (expression::Expression, single) : (missing) + * - hasTestExpression (expression::Expression, single) : (missing) + */ + class Assert : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Assert(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Assert(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Assert & operator=(const Assert&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Assert(const Assert&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasMsgExpression edge points to. + * \return Returns the end point of the hasMsgExpression edge. + */ + expression::Expression* getMsgExpression() const; + + /** + * \brief Gives back the pointer of the node the hasTestExpression edge points to. + * \return Returns the end point of the hasTestExpression edge. + */ + expression::Expression* getTestExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasMsgExpression edge. + * \param id [in] The new end point of the hasMsgExpression edge. + */ + void setMsgExpression(NodeId id); + + /** + * \brief Sets the hasMsgExpression edge. + * \param node [in] The new end point of the hasMsgExpression edge. + */ + void setMsgExpression(expression::Expression *node); + + /** + * \brief remove the hasMsgExpression edge. + */ + void removeMsgExpression(); + + /** + * \brief Sets the hasTestExpression edge. + * \param id [in] The new end point of the hasTestExpression edge. + */ + void setTestExpression(NodeId id); + + /** + * \brief Sets the hasTestExpression edge. + * \param node [in] The new end point of the hasTestExpression edge. + */ + void setTestExpression(expression::Expression *node); + + /** + * \brief remove the hasTestExpression edge. + */ + void removeTestExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasMsgExpression edge points to. */ + NodeId m_hasMsgExpression; + + /** \internal \brief The id of the node the hasTestExpression edge points to. */ + NodeId m_hasTestExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Assign.h b/lib/python/inc/statement/Assign.h new file mode 100644 index 0000000..d21420e --- /dev/null +++ b/lib/python/inc/statement/Assign.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Assign_H_ +#define _PYTHON_Assign_H_ + +#include "python/inc/python.h" + +/** +* \file Assign.h +* \brief Contains declaration of the statement::Assign class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Assign class, which represents the statement::Assign node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + * - hasTargetList (statement::TargetList, single) : (missing) + */ + class Assign : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Assign(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Assign(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Assign & operator=(const Assign&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Assign(const Assign&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + /** + * \brief Gives back the pointer of the node the hasTargetList edge points to. + * \return Returns the end point of the hasTargetList edge. + */ + statement::TargetList* getTargetList() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(expression::Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + /** + * \brief Sets the hasTargetList edge. + * \param id [in] The new end point of the hasTargetList edge. + */ + void setTargetList(NodeId id); + + /** + * \brief Sets the hasTargetList edge. + * \param node [in] The new end point of the hasTargetList edge. + */ + void setTargetList(TargetList *node); + + /** + * \brief remove the hasTargetList edge. + */ + void removeTargetList(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + /** \internal \brief The id of the node the hasTargetList edge points to. */ + NodeId m_hasTargetList; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/AugAssign.h b/lib/python/inc/statement/AugAssign.h new file mode 100644 index 0000000..df7b30b --- /dev/null +++ b/lib/python/inc/statement/AugAssign.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_AugAssign_H_ +#define _PYTHON_AugAssign_H_ + +#include "python/inc/python.h" + +/** +* \file AugAssign.h +* \brief Contains declaration of the statement::AugAssign class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief AugAssign class, which represents the statement::AugAssign node. + * (missing) + * + * Attributes: + * - kind (AssignmentKind) : (missing) + */ + class AugAssign : public Assign { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + AugAssign(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~AugAssign(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + AugAssign & operator=(const AugAssign&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + AugAssign(const AugAssign&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + AssignmentKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(AssignmentKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The AssignmentKind of the node. */ + AssignmentKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/BaseSpecifier.h b/lib/python/inc/statement/BaseSpecifier.h new file mode 100644 index 0000000..2a6e290 --- /dev/null +++ b/lib/python/inc/statement/BaseSpecifier.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_BaseSpecifier_H_ +#define _PYTHON_BaseSpecifier_H_ + +#include "python/inc/python.h" + +/** +* \file BaseSpecifier.h +* \brief Contains declaration of the statement::BaseSpecifier class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief BaseSpecifier class, which represents the statement::BaseSpecifier node. + * (missing) + * + * Edges: + * - hasName (expression::Expression, single) : (missing) + * - derivesFrom (statement::ClassDef, single) : (missing) + */ + class BaseSpecifier : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + BaseSpecifier(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~BaseSpecifier(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + BaseSpecifier & operator=(const BaseSpecifier&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + BaseSpecifier(const BaseSpecifier&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasName edge points to. + * \return Returns the end point of the hasName edge. + */ + expression::Expression* getName() const; + + /** + * \brief Gives back the pointer of the node the derivesFrom edge points to. + * \return Returns the end point of the derivesFrom edge. + */ + statement::ClassDef* getDerivesFrom() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasName edge. + * \param id [in] The new end point of the hasName edge. + */ + void setName(NodeId id); + + /** + * \brief Sets the hasName edge. + * \param node [in] The new end point of the hasName edge. + */ + void setName(expression::Expression *node); + + /** + * \brief remove the hasName edge. + */ + void removeName(); + + /** + * \brief Sets the derivesFrom edge. + * \param id [in] The new end point of the derivesFrom edge. + */ + void setDerivesFrom(NodeId id); + + /** + * \brief Sets the derivesFrom edge. + * \param node [in] The new end point of the derivesFrom edge. + */ + void setDerivesFrom(ClassDef *node); + + /** + * \brief remove the derivesFrom edge. + */ + void removeDerivesFrom(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasName edge points to. */ + NodeId m_hasName; + + /** \internal \brief The id of the node the derivesFrom edge points to. */ + NodeId m_derivesFrom; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Break.h b/lib/python/inc/statement/Break.h new file mode 100644 index 0000000..67ff23c --- /dev/null +++ b/lib/python/inc/statement/Break.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Break_H_ +#define _PYTHON_Break_H_ + +#include "python/inc/python.h" + +/** +* \file Break.h +* \brief Contains declaration of the statement::Break class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Break class, which represents the statement::Break node. + * (missing) + */ + class Break : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Break(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Break(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Break & operator=(const Break&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Break(const Break&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/ClassDef.h b/lib/python/inc/statement/ClassDef.h new file mode 100644 index 0000000..37330ae --- /dev/null +++ b/lib/python/inc/statement/ClassDef.h @@ -0,0 +1,442 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ClassDef_H_ +#define _PYTHON_ClassDef_H_ + +#include "python/inc/python.h" + +/** +* \file ClassDef.h +* \brief Contains declaration of the statement::ClassDef class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief ClassDef class, which represents the statement::ClassDef node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + * - lloc (int) : (missing) + * + * Edges: + * - hasObject (module::Object, multiple) : (missing) + * - hasBaseSpecifier (statement::BaseSpecifier, multiple) : (missing) + * - hasDecorator (expression::Expression, multiple) : (missing) + * - refersTo (module::Object, single) : (missing) + * - docstring (base::Docstring, single) : (missing) + */ + class ClassDef : public CompoundStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ClassDef(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ClassDef(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ClassDef & operator=(const ClassDef&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ClassDef(const ClassDef&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + /** + * \brief Gives back the lloc of the node. + * \return Returns with the lloc. + */ + int getLloc() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the lloc of the node. + * \param lloc [in] The new value of the lloc. + */ + void setLloc(int _lloc); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `lloc`. */ + int m_lloc; + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasObject edges or not. + * \return Returns true if the node doesn't have any hasObject edge. + */ + bool getObjectIsEmpty() const; + + /** + * \brief Gives back how many hasObject edges the node has. + * \return Returns with the number of hasObject edges. + */ + unsigned getObjectSize() const; + + /** + * \brief Gives back iterator for the hasBaseSpecifier edges. + * \return Returns an iterator for the hasBaseSpecifier edges. + */ + ListIterator getBaseSpecifierListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasBaseSpecifier edges. + * \return Returns an iterator for the hasBaseSpecifier edges. + */ + ListIterator getBaseSpecifierListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasBaseSpecifier edges or not. + * \return Returns true if the node doesn't have any hasBaseSpecifier edge. + */ + bool getBaseSpecifierIsEmpty() const; + + /** + * \brief Gives back how many hasBaseSpecifier edges the node has. + * \return Returns with the number of hasBaseSpecifier edges. + */ + unsigned getBaseSpecifierSize() const; + + /** + * \brief Gives back iterator for the hasDecorator edges. + * \return Returns an iterator for the hasDecorator edges. + */ + ListIterator getDecoratorListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasDecorator edges. + * \return Returns an iterator for the hasDecorator edges. + */ + ListIterator getDecoratorListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasDecorator edges or not. + * \return Returns true if the node doesn't have any hasDecorator edge. + */ + bool getDecoratorIsEmpty() const; + + /** + * \brief Gives back how many hasDecorator edges the node has. + * \return Returns with the number of hasDecorator edges. + */ + unsigned getDecoratorSize() const; + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + module::Object* getRefersTo() const; + + /** + * \brief Gives back the pointer of the node the docstring edge points to. + * \return Returns the end point of the docstring edge. + */ + base::Docstring* getDocstring() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasObject edge. + */ + void addObject(const module::Object *node); + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasObject edge. + */ + void addObject(NodeId id); + + /** + * \brief Remove the hasObject edge by id from the node. + * \param id [in] The end point of the hasObject edge. + */ + void removeObject(NodeId id); + + /** + * \brief Remove the hasObject edge from the node. + * \param node [in] The end point of the hasObject edge. + */ + void removeObject(module::Object *node); + + /** + * \brief Adds a new hasBaseSpecifier edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasBaseSpecifier edge. + */ + void addBaseSpecifier(const BaseSpecifier *node); + + /** + * \brief Adds a new hasBaseSpecifier edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasBaseSpecifier edge. + */ + void addBaseSpecifier(NodeId id); + + /** + * \brief Remove the hasBaseSpecifier edge by id from the node. + * \param id [in] The end point of the hasBaseSpecifier edge. + */ + void removeBaseSpecifier(NodeId id); + + /** + * \brief Remove the hasBaseSpecifier edge from the node. + * \param node [in] The end point of the hasBaseSpecifier edge. + */ + void removeBaseSpecifier(BaseSpecifier *node); + + /** + * \brief Adds a new hasDecorator edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasDecorator edge. + */ + void addDecorator(const expression::Expression *node); + + /** + * \brief Adds a new hasDecorator edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasDecorator edge. + */ + void addDecorator(NodeId id); + + /** + * \brief Remove the hasDecorator edge by id from the node. + * \param id [in] The end point of the hasDecorator edge. + */ + void removeDecorator(NodeId id); + + /** + * \brief Remove the hasDecorator edge from the node. + * \param node [in] The end point of the hasDecorator edge. + */ + void removeDecorator(expression::Expression *node); + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(module::Object *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + /** + * \brief Sets the docstring edge. + * \param id [in] The new end point of the docstring edge. + */ + void setDocstring(NodeId id); + + /** + * \brief Sets the docstring edge. + * \param node [in] The new end point of the docstring edge. + */ + void setDocstring(base::Docstring *node); + + /** + * \brief remove the docstring edge. + */ + void removeDocstring(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasObject edge points to. */ + ListIterator::Container hasObjectContainer; + + /** \internal \brief Container stores the id of the nodes the hasBaseSpecifier edge points to. */ + ListIterator::Container hasBaseSpecifierContainer; + + /** \internal \brief Container stores the id of the nodes the hasDecorator edge points to. */ + ListIterator::Container hasDecoratorContainer; + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + /** \internal \brief The id of the node the docstring edge points to. */ + NodeId m_docstring; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/CompoundStatement.h b/lib/python/inc/statement/CompoundStatement.h new file mode 100644 index 0000000..5cd5a48 --- /dev/null +++ b/lib/python/inc/statement/CompoundStatement.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_CompoundStatement_H_ +#define _PYTHON_CompoundStatement_H_ + +#include "python/inc/python.h" + +/** +* \file CompoundStatement.h +* \brief Contains declaration of the statement::CompoundStatement class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief CompoundStatement class, which represents the statement::CompoundStatement node. + * (missing) + * + * Edges: + * - hasBody (statement::Suite, single) : (missing) + */ + class CompoundStatement : public Statement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + CompoundStatement(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~CompoundStatement(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + CompoundStatement & operator=(const CompoundStatement&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + CompoundStatement(const CompoundStatement&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasBody edge points to. + * \return Returns the end point of the hasBody edge. + */ + statement::Suite* getBody() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasBody edge. + * \param id [in] The new end point of the hasBody edge. + */ + void setBody(NodeId id); + + /** + * \brief Sets the hasBody edge. + * \param node [in] The new end point of the hasBody edge. + */ + void setBody(Suite *node); + + /** + * \brief remove the hasBody edge. + */ + void removeBody(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasBody edge points to. */ + NodeId m_hasBody; + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Continue.h b/lib/python/inc/statement/Continue.h new file mode 100644 index 0000000..9fb314c --- /dev/null +++ b/lib/python/inc/statement/Continue.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Continue_H_ +#define _PYTHON_Continue_H_ + +#include "python/inc/python.h" + +/** +* \file Continue.h +* \brief Contains declaration of the statement::Continue class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Continue class, which represents the statement::Continue node. + * (missing) + */ + class Continue : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Continue(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Continue(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Continue & operator=(const Continue&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Continue(const Continue&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Delete.h b/lib/python/inc/statement/Delete.h new file mode 100644 index 0000000..c53f8e2 --- /dev/null +++ b/lib/python/inc/statement/Delete.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Delete_H_ +#define _PYTHON_Delete_H_ + +#include "python/inc/python.h" + +/** +* \file Delete.h +* \brief Contains declaration of the statement::Delete class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Delete class, which represents the statement::Delete node. + * (missing) + * + * Edges: + * - hasTargetList (statement::TargetList, single) : (missing) + */ + class Delete : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Delete(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Delete(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Delete & operator=(const Delete&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Delete(const Delete&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasTargetList edge points to. + * \return Returns the end point of the hasTargetList edge. + */ + statement::TargetList* getTargetList() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasTargetList edge. + * \param id [in] The new end point of the hasTargetList edge. + */ + void setTargetList(NodeId id); + + /** + * \brief Sets the hasTargetList edge. + * \param node [in] The new end point of the hasTargetList edge. + */ + void setTargetList(TargetList *node); + + /** + * \brief remove the hasTargetList edge. + */ + void removeTargetList(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasTargetList edge points to. */ + NodeId m_hasTargetList; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Exec.h b/lib/python/inc/statement/Exec.h new file mode 100644 index 0000000..3ef0fe9 --- /dev/null +++ b/lib/python/inc/statement/Exec.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Exec_H_ +#define _PYTHON_Exec_H_ + +#include "python/inc/python.h" + +/** +* \file Exec.h +* \brief Contains declaration of the statement::Exec class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Exec class, which represents the statement::Exec node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + * - hasGlobals (expression::Expression, single) : (missing) + * - hasLocals (expression::Expression, single) : (missing) + */ + class Exec : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Exec(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Exec(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Exec & operator=(const Exec&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Exec(const Exec&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + /** + * \brief Gives back the pointer of the node the hasGlobals edge points to. + * \return Returns the end point of the hasGlobals edge. + */ + expression::Expression* getGlobals() const; + + /** + * \brief Gives back the pointer of the node the hasLocals edge points to. + * \return Returns the end point of the hasLocals edge. + */ + expression::Expression* getLocals() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(expression::Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + /** + * \brief Sets the hasGlobals edge. + * \param id [in] The new end point of the hasGlobals edge. + */ + void setGlobals(NodeId id); + + /** + * \brief Sets the hasGlobals edge. + * \param node [in] The new end point of the hasGlobals edge. + */ + void setGlobals(expression::Expression *node); + + /** + * \brief remove the hasGlobals edge. + */ + void removeGlobals(); + + /** + * \brief Sets the hasLocals edge. + * \param id [in] The new end point of the hasLocals edge. + */ + void setLocals(NodeId id); + + /** + * \brief Sets the hasLocals edge. + * \param node [in] The new end point of the hasLocals edge. + */ + void setLocals(expression::Expression *node); + + /** + * \brief remove the hasLocals edge. + */ + void removeLocals(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + /** \internal \brief The id of the node the hasGlobals edge points to. */ + NodeId m_hasGlobals; + + /** \internal \brief The id of the node the hasLocals edge points to. */ + NodeId m_hasLocals; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/For.h b/lib/python/inc/statement/For.h new file mode 100644 index 0000000..b8d245a --- /dev/null +++ b/lib/python/inc/statement/For.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_For_H_ +#define _PYTHON_For_H_ + +#include "python/inc/python.h" + +/** +* \file For.h +* \brief Contains declaration of the statement::For class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief For class, which represents the statement::For node. + * (missing) + * + * Edges: + * - hasExpressionList (expression::ExpressionList, single) : (missing) + * - hasTargetList (statement::TargetList, single) : (missing) + */ + class For : public Iteration { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + For(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~For(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + For & operator=(const For&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + For(const For&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpressionList edge points to. + * \return Returns the end point of the hasExpressionList edge. + */ + expression::ExpressionList* getExpressionList() const; + + /** + * \brief Gives back the pointer of the node the hasTargetList edge points to. + * \return Returns the end point of the hasTargetList edge. + */ + statement::TargetList* getTargetList() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpressionList edge. + * \param id [in] The new end point of the hasExpressionList edge. + */ + void setExpressionList(NodeId id); + + /** + * \brief Sets the hasExpressionList edge. + * \param node [in] The new end point of the hasExpressionList edge. + */ + void setExpressionList(expression::ExpressionList *node); + + /** + * \brief remove the hasExpressionList edge. + */ + void removeExpressionList(); + + /** + * \brief Sets the hasTargetList edge. + * \param id [in] The new end point of the hasTargetList edge. + */ + void setTargetList(NodeId id); + + /** + * \brief Sets the hasTargetList edge. + * \param node [in] The new end point of the hasTargetList edge. + */ + void setTargetList(TargetList *node); + + /** + * \brief remove the hasTargetList edge. + */ + void removeTargetList(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpressionList edge points to. */ + NodeId m_hasExpressionList; + + /** \internal \brief The id of the node the hasTargetList edge points to. */ + NodeId m_hasTargetList; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/FunctionDef.h b/lib/python/inc/statement/FunctionDef.h new file mode 100644 index 0000000..a33383e --- /dev/null +++ b/lib/python/inc/statement/FunctionDef.h @@ -0,0 +1,469 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_FunctionDef_H_ +#define _PYTHON_FunctionDef_H_ + +#include "python/inc/python.h" + +/** +* \file FunctionDef.h +* \brief Contains declaration of the statement::FunctionDef class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief FunctionDef class, which represents the statement::FunctionDef node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + * - lloc (int) : (missing) + * + * Edges: + * - hasDecorator (expression::Expression, multiple) : (missing) + * - hasObject (module::Object, multiple) : (missing) + * - hasParameter (statement::Parameter, multiple) : (missing) + * - refersTo (module::Object, single) : (missing) + * - returnType (type::Type, single) : (missing) + * - docstring (base::Docstring, single) : (missing) + */ + class FunctionDef : public CompoundStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + FunctionDef(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~FunctionDef(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + FunctionDef & operator=(const FunctionDef&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + FunctionDef(const FunctionDef&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + /** + * \brief Gives back the lloc of the node. + * \return Returns with the lloc. + */ + int getLloc() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the lloc of the node. + * \param lloc [in] The new value of the lloc. + */ + void setLloc(int _lloc); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `lloc`. */ + int m_lloc; + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasDecorator edges. + * \return Returns an iterator for the hasDecorator edges. + */ + ListIterator getDecoratorListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasDecorator edges. + * \return Returns an iterator for the hasDecorator edges. + */ + ListIterator getDecoratorListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasDecorator edges or not. + * \return Returns true if the node doesn't have any hasDecorator edge. + */ + bool getDecoratorIsEmpty() const; + + /** + * \brief Gives back how many hasDecorator edges the node has. + * \return Returns with the number of hasDecorator edges. + */ + unsigned getDecoratorSize() const; + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasObject edges. + * \return Returns an iterator for the hasObject edges. + */ + ListIterator getObjectListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasObject edges or not. + * \return Returns true if the node doesn't have any hasObject edge. + */ + bool getObjectIsEmpty() const; + + /** + * \brief Gives back how many hasObject edges the node has. + * \return Returns with the number of hasObject edges. + */ + unsigned getObjectSize() const; + + /** + * \brief Gives back iterator for the hasParameter edges. + * \return Returns an iterator for the hasParameter edges. + */ + ListIterator getParameterListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasParameter edges. + * \return Returns an iterator for the hasParameter edges. + */ + ListIterator getParameterListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasParameter edges or not. + * \return Returns true if the node doesn't have any hasParameter edge. + */ + bool getParameterIsEmpty() const; + + /** + * \brief Gives back how many hasParameter edges the node has. + * \return Returns with the number of hasParameter edges. + */ + unsigned getParameterSize() const; + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + module::Object* getRefersTo() const; + + /** + * \brief Gives back the pointer of the node the returnType edge points to. + * \return Returns the end point of the returnType edge. + */ + type::Type* getReturnType() const; + + /** + * \brief Gives back the pointer of the node the docstring edge points to. + * \return Returns the end point of the docstring edge. + */ + base::Docstring* getDocstring() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasDecorator edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasDecorator edge. + */ + void addDecorator(const expression::Expression *node); + + /** + * \brief Adds a new hasDecorator edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasDecorator edge. + */ + void addDecorator(NodeId id); + + /** + * \brief Remove the hasDecorator edge by id from the node. + * \param id [in] The end point of the hasDecorator edge. + */ + void removeDecorator(NodeId id); + + /** + * \brief Remove the hasDecorator edge from the node. + * \param node [in] The end point of the hasDecorator edge. + */ + void removeDecorator(expression::Expression *node); + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasObject edge. + */ + void addObject(const module::Object *node); + + /** + * \brief Adds a new hasObject edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasObject edge. + */ + void addObject(NodeId id); + + /** + * \brief Remove the hasObject edge by id from the node. + * \param id [in] The end point of the hasObject edge. + */ + void removeObject(NodeId id); + + /** + * \brief Remove the hasObject edge from the node. + * \param node [in] The end point of the hasObject edge. + */ + void removeObject(module::Object *node); + + /** + * \brief Adds a new hasParameter edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasParameter edge. + */ + void addParameter(const Parameter *node); + + /** + * \brief Adds a new hasParameter edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasParameter edge. + */ + void addParameter(NodeId id); + + /** + * \brief Remove the hasParameter edge by id from the node. + * \param id [in] The end point of the hasParameter edge. + */ + void removeParameter(NodeId id); + + /** + * \brief Remove the hasParameter edge from the node. + * \param node [in] The end point of the hasParameter edge. + */ + void removeParameter(Parameter *node); + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(module::Object *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + /** + * \brief Sets the returnType edge. + * \param id [in] The new end point of the returnType edge. + */ + void setReturnType(NodeId id); + + /** + * \brief Sets the returnType edge. + * \param node [in] The new end point of the returnType edge. + */ + void setReturnType(type::Type *node); + + /** + * \brief remove the returnType edge. + */ + void removeReturnType(); + + /** + * \brief Sets the docstring edge. + * \param id [in] The new end point of the docstring edge. + */ + void setDocstring(NodeId id); + + /** + * \brief Sets the docstring edge. + * \param node [in] The new end point of the docstring edge. + */ + void setDocstring(base::Docstring *node); + + /** + * \brief remove the docstring edge. + */ + void removeDocstring(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasDecorator edge points to. */ + ListIterator::Container hasDecoratorContainer; + + /** \internal \brief Container stores the id of the nodes the hasObject edge points to. */ + ListIterator::Container hasObjectContainer; + + /** \internal \brief Container stores the id of the nodes the hasParameter edge points to. */ + ListIterator::Container hasParameterContainer; + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + /** \internal \brief The id of the node the returnType edge points to. */ + NodeId m_returnType; + + /** \internal \brief The id of the node the docstring edge points to. */ + NodeId m_docstring; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Global.h b/lib/python/inc/statement/Global.h new file mode 100644 index 0000000..6b64462 --- /dev/null +++ b/lib/python/inc/statement/Global.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Global_H_ +#define _PYTHON_Global_H_ + +#include "python/inc/python.h" + +/** +* \file Global.h +* \brief Contains declaration of the statement::Global class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Global class, which represents the statement::Global node. + * (missing) + * + * Edges: + * - hasIdentifier (expression::Identifier, multiple) : (missing) + */ + class Global : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Global(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Global(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Global & operator=(const Global&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Global(const Global&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasIdentifier edges. + * \return Returns an iterator for the hasIdentifier edges. + */ + ListIterator getIdentifierListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasIdentifier edges. + * \return Returns an iterator for the hasIdentifier edges. + */ + ListIterator getIdentifierListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasIdentifier edges or not. + * \return Returns true if the node doesn't have any hasIdentifier edge. + */ + bool getIdentifierIsEmpty() const; + + /** + * \brief Gives back how many hasIdentifier edges the node has. + * \return Returns with the number of hasIdentifier edges. + */ + unsigned getIdentifierSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasIdentifier edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasIdentifier edge. + */ + void addIdentifier(const expression::Identifier *node); + + /** + * \brief Adds a new hasIdentifier edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasIdentifier edge. + */ + void addIdentifier(NodeId id); + + /** + * \brief Remove the hasIdentifier edge by id from the node. + * \param id [in] The end point of the hasIdentifier edge. + */ + void removeIdentifier(NodeId id); + + /** + * \brief Remove the hasIdentifier edge from the node. + * \param node [in] The end point of the hasIdentifier edge. + */ + void removeIdentifier(expression::Identifier *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasIdentifier edge points to. */ + ListIterator::Container hasIdentifierContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Handler.h b/lib/python/inc/statement/Handler.h new file mode 100644 index 0000000..1b3b34a --- /dev/null +++ b/lib/python/inc/statement/Handler.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Handler_H_ +#define _PYTHON_Handler_H_ + +#include "python/inc/python.h" + +/** +* \file Handler.h +* \brief Contains declaration of the statement::Handler class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Handler class, which represents the statement::Handler node. + * (missing) + * + * Edges: + * - hasName (expression::Expression, single) : (missing) + * - hasExceptBody (statement::Suite, single) : (missing) + * - hasType (expression::Expression, single) : (missing) + */ + class Handler : public Statement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Handler(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Handler(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Handler & operator=(const Handler&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Handler(const Handler&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasName edge points to. + * \return Returns the end point of the hasName edge. + */ + expression::Expression* getName() const; + + /** + * \brief Gives back the pointer of the node the hasExceptBody edge points to. + * \return Returns the end point of the hasExceptBody edge. + */ + statement::Suite* getExceptBody() const; + + /** + * \brief Gives back the pointer of the node the hasType edge points to. + * \return Returns the end point of the hasType edge. + */ + expression::Expression* getType() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasName edge. + * \param id [in] The new end point of the hasName edge. + */ + void setName(NodeId id); + + /** + * \brief Sets the hasName edge. + * \param node [in] The new end point of the hasName edge. + */ + void setName(expression::Expression *node); + + /** + * \brief remove the hasName edge. + */ + void removeName(); + + /** + * \brief Sets the hasExceptBody edge. + * \param id [in] The new end point of the hasExceptBody edge. + */ + void setExceptBody(NodeId id); + + /** + * \brief Sets the hasExceptBody edge. + * \param node [in] The new end point of the hasExceptBody edge. + */ + void setExceptBody(Suite *node); + + /** + * \brief remove the hasExceptBody edge. + */ + void removeExceptBody(); + + /** + * \brief Sets the hasType edge. + * \param id [in] The new end point of the hasType edge. + */ + void setType(NodeId id); + + /** + * \brief Sets the hasType edge. + * \param node [in] The new end point of the hasType edge. + */ + void setType(expression::Expression *node); + + /** + * \brief remove the hasType edge. + */ + void removeType(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasName edge points to. */ + NodeId m_hasName; + + /** \internal \brief The id of the node the hasExceptBody edge points to. */ + NodeId m_hasExceptBody; + + /** \internal \brief The id of the node the hasType edge points to. */ + NodeId m_hasType; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/If.h b/lib/python/inc/statement/If.h new file mode 100644 index 0000000..fa32fe8 --- /dev/null +++ b/lib/python/inc/statement/If.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_If_H_ +#define _PYTHON_If_H_ + +#include "python/inc/python.h" + +/** +* \file If.h +* \brief Contains declaration of the statement::If class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief If class, which represents the statement::If node. + * (missing) + * + * Edges: + * - hasElseBody (statement::Suite, single) : (missing) + * - hasTestExpression (expression::Expression, single) : (missing) + */ + class If : public CompoundStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + If(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~If(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + If & operator=(const If&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + If(const If&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasElseBody edge points to. + * \return Returns the end point of the hasElseBody edge. + */ + statement::Suite* getElseBody() const; + + /** + * \brief Gives back the pointer of the node the hasTestExpression edge points to. + * \return Returns the end point of the hasTestExpression edge. + */ + expression::Expression* getTestExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasElseBody edge. + * \param id [in] The new end point of the hasElseBody edge. + */ + void setElseBody(NodeId id); + + /** + * \brief Sets the hasElseBody edge. + * \param node [in] The new end point of the hasElseBody edge. + */ + void setElseBody(Suite *node); + + /** + * \brief remove the hasElseBody edge. + */ + void removeElseBody(); + + /** + * \brief Sets the hasTestExpression edge. + * \param id [in] The new end point of the hasTestExpression edge. + */ + void setTestExpression(NodeId id); + + /** + * \brief Sets the hasTestExpression edge. + * \param node [in] The new end point of the hasTestExpression edge. + */ + void setTestExpression(expression::Expression *node); + + /** + * \brief remove the hasTestExpression edge. + */ + void removeTestExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasElseBody edge points to. */ + NodeId m_hasElseBody; + + /** \internal \brief The id of the node the hasTestExpression edge points to. */ + NodeId m_hasTestExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/ImportFrom.h b/lib/python/inc/statement/ImportFrom.h new file mode 100644 index 0000000..9b8af9a --- /dev/null +++ b/lib/python/inc/statement/ImportFrom.h @@ -0,0 +1,219 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ImportFrom_H_ +#define _PYTHON_ImportFrom_H_ + +#include "python/inc/python.h" + +/** +* \file ImportFrom.h +* \brief Contains declaration of the statement::ImportFrom class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief ImportFrom class, which represents the statement::ImportFrom node. + * (missing) + * + * Attributes: + * - modulname (String) : (missing) + * - level (int) : (missing) + */ + class ImportFrom : public ImportStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ImportFrom(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ImportFrom(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ImportFrom & operator=(const ImportFrom&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ImportFrom(const ImportFrom&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the modulname of the node. + * \return Returns with the modulname. + */ + const std::string& getModulname() const; + + /** + * \brief Gives back the Key of modulname of the node. + * \return Returns with the Key of the modulname. + */ + Key getModulnameKey() const; + + /** + * \brief Gives back the level of the node. + * \return Returns with the level. + */ + int getLevel() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the modulname of the node. + * \param modulname [in] The new value of the modulname. + */ + void setModulname(const std::string& _modulname); + + /** + * \internal + * \brief Sets the level of the node. + * \param level [in] The new value of the level. + */ + void setLevel(int _level); + + /** + * \internal + * \brief Sets the modulname of the node. + * \param modulname [in] The new Key of the modulname. + */ + void setModulnameKey(Key _modulname); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `level`. */ + int m_level; + + /** \internal \brief The Key of the `modulname`. */ + Key m_modulname; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/ImportStatement.h b/lib/python/inc/statement/ImportStatement.h new file mode 100644 index 0000000..9df93c2 --- /dev/null +++ b/lib/python/inc/statement/ImportStatement.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ImportStatement_H_ +#define _PYTHON_ImportStatement_H_ + +#include "python/inc/python.h" + +/** +* \file ImportStatement.h +* \brief Contains declaration of the statement::ImportStatement class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief ImportStatement class, which represents the statement::ImportStatement node. + * (missing) + * + * Edges: + * - hasAlias (statement::Alias, multiple) : (missing) + */ + class ImportStatement : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ImportStatement(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ImportStatement(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ImportStatement & operator=(const ImportStatement&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ImportStatement(const ImportStatement&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasAlias edges. + * \return Returns an iterator for the hasAlias edges. + */ + ListIterator getAliasListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasAlias edges. + * \return Returns an iterator for the hasAlias edges. + */ + ListIterator getAliasListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasAlias edges or not. + * \return Returns true if the node doesn't have any hasAlias edge. + */ + bool getAliasIsEmpty() const; + + /** + * \brief Gives back how many hasAlias edges the node has. + * \return Returns with the number of hasAlias edges. + */ + unsigned getAliasSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasAlias edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasAlias edge. + */ + void addAlias(const Alias *node); + + /** + * \brief Adds a new hasAlias edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasAlias edge. + */ + void addAlias(NodeId id); + + /** + * \brief Remove the hasAlias edge by id from the node. + * \param id [in] The end point of the hasAlias edge. + */ + void removeAlias(NodeId id); + + /** + * \brief Remove the hasAlias edge from the node. + * \param node [in] The end point of the hasAlias edge. + */ + void removeAlias(Alias *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasAlias edge points to. */ + ListIterator::Container hasAliasContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Iteration.h b/lib/python/inc/statement/Iteration.h new file mode 100644 index 0000000..79212e4 --- /dev/null +++ b/lib/python/inc/statement/Iteration.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Iteration_H_ +#define _PYTHON_Iteration_H_ + +#include "python/inc/python.h" + +/** +* \file Iteration.h +* \brief Contains declaration of the statement::Iteration class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Iteration class, which represents the statement::Iteration node. + * (missing) + * + * Edges: + * - hasElseBody (statement::Suite, single) : (missing) + */ + class Iteration : public CompoundStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Iteration(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Iteration(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Iteration & operator=(const Iteration&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Iteration(const Iteration&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasElseBody edge points to. + * \return Returns the end point of the hasElseBody edge. + */ + statement::Suite* getElseBody() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasElseBody edge. + * \param id [in] The new end point of the hasElseBody edge. + */ + void setElseBody(NodeId id); + + /** + * \brief Sets the hasElseBody edge. + * \param node [in] The new end point of the hasElseBody edge. + */ + void setElseBody(Suite *node); + + /** + * \brief remove the hasElseBody edge. + */ + void removeElseBody(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasElseBody edge points to. */ + NodeId m_hasElseBody; + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Parameter.h b/lib/python/inc/statement/Parameter.h new file mode 100644 index 0000000..873c7f5 --- /dev/null +++ b/lib/python/inc/statement/Parameter.h @@ -0,0 +1,256 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Parameter_H_ +#define _PYTHON_Parameter_H_ + +#include "python/inc/python.h" + +/** +* \file Parameter.h +* \brief Contains declaration of the statement::Parameter class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Parameter class, which represents the statement::Parameter node. + * (missing) + * + * Attributes: + * - kind (ParameterKind) : (missing) + * + * Edges: + * - hasDefaultValue (expression::Expression, single) : (missing) + * - refersTo (module::Object, single) : (missing) + */ + class Parameter : public base::Named { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Parameter(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Parameter(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Parameter & operator=(const Parameter&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Parameter(const Parameter&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + ParameterKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(ParameterKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The ParameterKind of the node. */ + ParameterKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasDefaultValue edge points to. + * \return Returns the end point of the hasDefaultValue edge. + */ + expression::Expression* getDefaultValue() const; + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + module::Object* getRefersTo() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasDefaultValue edge. + * \param id [in] The new end point of the hasDefaultValue edge. + */ + void setDefaultValue(NodeId id); + + /** + * \brief Sets the hasDefaultValue edge. + * \param node [in] The new end point of the hasDefaultValue edge. + */ + void setDefaultValue(expression::Expression *node); + + /** + * \brief remove the hasDefaultValue edge. + */ + void removeDefaultValue(); + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(module::Object *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasDefaultValue edge points to. */ + NodeId m_hasDefaultValue; + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Pass.h b/lib/python/inc/statement/Pass.h new file mode 100644 index 0000000..9fc38d1 --- /dev/null +++ b/lib/python/inc/statement/Pass.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Pass_H_ +#define _PYTHON_Pass_H_ + +#include "python/inc/python.h" + +/** +* \file Pass.h +* \brief Contains declaration of the statement::Pass class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Pass class, which represents the statement::Pass node. + * (missing) + */ + class Pass : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Pass(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Pass(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Pass & operator=(const Pass&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Pass(const Pass&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Print.h b/lib/python/inc/statement/Print.h new file mode 100644 index 0000000..19031e0 --- /dev/null +++ b/lib/python/inc/statement/Print.h @@ -0,0 +1,256 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Print_H_ +#define _PYTHON_Print_H_ + +#include "python/inc/python.h" + +/** +* \file Print.h +* \brief Contains declaration of the statement::Print class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Print class, which represents the statement::Print node. + * (missing) + * + * Attributes: + * - nl (boolean) : (missing) + * + * Edges: + * - hasExpressionList (expression::ExpressionList, single) : (missing) + * - hasDestination (expression::Expression, single) : (missing) + */ + class Print : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Print(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Print(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Print & operator=(const Print&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Print(const Print&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the nl of the node. + * \return Returns with the nl. + */ + bool getNl() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the nl of the node. + * \param nl [in] The new value of the nl. + */ + void setNl(bool _nl); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The value of the `nl`. */ + bool m_nl : 1; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpressionList edge points to. + * \return Returns the end point of the hasExpressionList edge. + */ + expression::ExpressionList* getExpressionList() const; + + /** + * \brief Gives back the pointer of the node the hasDestination edge points to. + * \return Returns the end point of the hasDestination edge. + */ + expression::Expression* getDestination() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpressionList edge. + * \param id [in] The new end point of the hasExpressionList edge. + */ + void setExpressionList(NodeId id); + + /** + * \brief Sets the hasExpressionList edge. + * \param node [in] The new end point of the hasExpressionList edge. + */ + void setExpressionList(expression::ExpressionList *node); + + /** + * \brief remove the hasExpressionList edge. + */ + void removeExpressionList(); + + /** + * \brief Sets the hasDestination edge. + * \param id [in] The new end point of the hasDestination edge. + */ + void setDestination(NodeId id); + + /** + * \brief Sets the hasDestination edge. + * \param node [in] The new end point of the hasDestination edge. + */ + void setDestination(expression::Expression *node); + + /** + * \brief remove the hasDestination edge. + */ + void removeDestination(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpressionList edge points to. */ + NodeId m_hasExpressionList; + + /** \internal \brief The id of the node the hasDestination edge points to. */ + NodeId m_hasDestination; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Raise.h b/lib/python/inc/statement/Raise.h new file mode 100644 index 0000000..63810fb --- /dev/null +++ b/lib/python/inc/statement/Raise.h @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Raise_H_ +#define _PYTHON_Raise_H_ + +#include "python/inc/python.h" + +/** +* \file Raise.h +* \brief Contains declaration of the statement::Raise class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Raise class, which represents the statement::Raise node. + * (missing) + * + * Edges: + * - hasTracebackExpression (expression::Expression, single) : (missing) + * - hasTypeExpression (expression::Expression, single) : (missing) + * - hasValueExpression (expression::Expression, single) : (missing) + */ + class Raise : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Raise(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Raise(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Raise & operator=(const Raise&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Raise(const Raise&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasTracebackExpression edge points to. + * \return Returns the end point of the hasTracebackExpression edge. + */ + expression::Expression* getTracebackExpression() const; + + /** + * \brief Gives back the pointer of the node the hasTypeExpression edge points to. + * \return Returns the end point of the hasTypeExpression edge. + */ + expression::Expression* getTypeExpression() const; + + /** + * \brief Gives back the pointer of the node the hasValueExpression edge points to. + * \return Returns the end point of the hasValueExpression edge. + */ + expression::Expression* getValueExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasTracebackExpression edge. + * \param id [in] The new end point of the hasTracebackExpression edge. + */ + void setTracebackExpression(NodeId id); + + /** + * \brief Sets the hasTracebackExpression edge. + * \param node [in] The new end point of the hasTracebackExpression edge. + */ + void setTracebackExpression(expression::Expression *node); + + /** + * \brief remove the hasTracebackExpression edge. + */ + void removeTracebackExpression(); + + /** + * \brief Sets the hasTypeExpression edge. + * \param id [in] The new end point of the hasTypeExpression edge. + */ + void setTypeExpression(NodeId id); + + /** + * \brief Sets the hasTypeExpression edge. + * \param node [in] The new end point of the hasTypeExpression edge. + */ + void setTypeExpression(expression::Expression *node); + + /** + * \brief remove the hasTypeExpression edge. + */ + void removeTypeExpression(); + + /** + * \brief Sets the hasValueExpression edge. + * \param id [in] The new end point of the hasValueExpression edge. + */ + void setValueExpression(NodeId id); + + /** + * \brief Sets the hasValueExpression edge. + * \param node [in] The new end point of the hasValueExpression edge. + */ + void setValueExpression(expression::Expression *node); + + /** + * \brief remove the hasValueExpression edge. + */ + void removeValueExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasTracebackExpression edge points to. */ + NodeId m_hasTracebackExpression; + + /** \internal \brief The id of the node the hasTypeExpression edge points to. */ + NodeId m_hasTypeExpression; + + /** \internal \brief The id of the node the hasValueExpression edge points to. */ + NodeId m_hasValueExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Return.h b/lib/python/inc/statement/Return.h new file mode 100644 index 0000000..eb30f40 --- /dev/null +++ b/lib/python/inc/statement/Return.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Return_H_ +#define _PYTHON_Return_H_ + +#include "python/inc/python.h" + +/** +* \file Return.h +* \brief Contains declaration of the statement::Return class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Return class, which represents the statement::Return node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + */ + class Return : public SimpleStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Return(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Return(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Return & operator=(const Return&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Return(const Return&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(expression::Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/SimpleStatement.h b/lib/python/inc/statement/SimpleStatement.h new file mode 100644 index 0000000..0faf8b9 --- /dev/null +++ b/lib/python/inc/statement/SimpleStatement.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_SimpleStatement_H_ +#define _PYTHON_SimpleStatement_H_ + +#include "python/inc/python.h" + +/** +* \file SimpleStatement.h +* \brief Contains declaration of the statement::SimpleStatement class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief SimpleStatement class, which represents the statement::SimpleStatement node. + * (missing) + */ + class SimpleStatement : public Statement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + SimpleStatement(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~SimpleStatement(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SimpleStatement & operator=(const SimpleStatement&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SimpleStatement(const SimpleStatement&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Statement.h b/lib/python/inc/statement/Statement.h new file mode 100644 index 0000000..061b1bc --- /dev/null +++ b/lib/python/inc/statement/Statement.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Statement_H_ +#define _PYTHON_Statement_H_ + +#include "python/inc/python.h" + +/** +* \file Statement.h +* \brief Contains declaration of the statement::Statement class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Statement class, which represents the statement::Statement node. + * (missing) + */ + class Statement : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Statement(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Statement(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Statement & operator=(const Statement&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Statement(const Statement&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Suite.h b/lib/python/inc/statement/Suite.h new file mode 100644 index 0000000..9fc4d06 --- /dev/null +++ b/lib/python/inc/statement/Suite.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Suite_H_ +#define _PYTHON_Suite_H_ + +#include "python/inc/python.h" + +/** +* \file Suite.h +* \brief Contains declaration of the statement::Suite class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Suite class, which represents the statement::Suite node. + * (missing) + * + * Edges: + * - hasStatement (base::Positioned, multiple) : (missing) + */ + class Suite : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Suite(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Suite(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Suite & operator=(const Suite&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Suite(const Suite&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasStatement edges. + * \return Returns an iterator for the hasStatement edges. + */ + ListIterator getStatementListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasStatement edges. + * \return Returns an iterator for the hasStatement edges. + */ + ListIterator getStatementListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasStatement edges or not. + * \return Returns true if the node doesn't have any hasStatement edge. + */ + bool getStatementIsEmpty() const; + + /** + * \brief Gives back how many hasStatement edges the node has. + * \return Returns with the number of hasStatement edges. + */ + unsigned getStatementSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasStatement edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasStatement edge. + */ + void addStatement(const base::Positioned *node); + + /** + * \brief Adds a new hasStatement edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasStatement edge. + */ + void addStatement(NodeId id); + + /** + * \brief Remove the hasStatement edge by id from the node. + * \param id [in] The end point of the hasStatement edge. + */ + void removeStatement(NodeId id); + + /** + * \brief Remove the hasStatement edge from the node. + * \param node [in] The end point of the hasStatement edge. + */ + void removeStatement(base::Positioned *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasStatement edge points to. */ + ListIterator::Container hasStatementContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/TargetList.h b/lib/python/inc/statement/TargetList.h new file mode 100644 index 0000000..3d13277 --- /dev/null +++ b/lib/python/inc/statement/TargetList.h @@ -0,0 +1,225 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_TargetList_H_ +#define _PYTHON_TargetList_H_ + +#include "python/inc/python.h" + +/** +* \file TargetList.h +* \brief Contains declaration of the statement::TargetList class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief TargetList class, which represents the statement::TargetList node. + * (missing) + * + * Edges: + * - hasTarget (expression::Expression, multiple) : (missing) + */ + class TargetList : public base::Positioned { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + TargetList(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~TargetList(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + TargetList & operator=(const TargetList&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + TargetList(const TargetList&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back iterator for the hasTarget edges. + * \return Returns an iterator for the hasTarget edges. + */ + ListIterator getTargetListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasTarget edges. + * \return Returns an iterator for the hasTarget edges. + */ + ListIterator getTargetListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasTarget edges or not. + * \return Returns true if the node doesn't have any hasTarget edge. + */ + bool getTargetIsEmpty() const; + + /** + * \brief Gives back how many hasTarget edges the node has. + * \return Returns with the number of hasTarget edges. + */ + unsigned getTargetSize() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Adds a new hasTarget edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasTarget edge. + */ + void addTarget(const expression::Expression *node); + + /** + * \brief Adds a new hasTarget edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasTarget edge. + */ + void addTarget(NodeId id); + + /** + * \brief Remove the hasTarget edge by id from the node. + * \param id [in] The end point of the hasTarget edge. + */ + void removeTarget(NodeId id); + + /** + * \brief Remove the hasTarget edge from the node. + * \param node [in] The end point of the hasTarget edge. + */ + void removeTarget(expression::Expression *node); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief Container stores the id of the nodes the hasTarget edge points to. */ + ListIterator::Container hasTargetContainer; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/Try.h b/lib/python/inc/statement/Try.h new file mode 100644 index 0000000..dd81e63 --- /dev/null +++ b/lib/python/inc/statement/Try.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Try_H_ +#define _PYTHON_Try_H_ + +#include "python/inc/python.h" + +/** +* \file Try.h +* \brief Contains declaration of the statement::Try class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief Try class, which represents the statement::Try node. + * (missing) + */ + class Try : public CompoundStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Try(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Try(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Try & operator=(const Try&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Try(const Try&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/TryExcept.h b/lib/python/inc/statement/TryExcept.h new file mode 100644 index 0000000..63af475 --- /dev/null +++ b/lib/python/inc/statement/TryExcept.h @@ -0,0 +1,279 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_TryExcept_H_ +#define _PYTHON_TryExcept_H_ + +#include "python/inc/python.h" + +/** +* \file TryExcept.h +* \brief Contains declaration of the statement::TryExcept class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief TryExcept class, which represents the statement::TryExcept node. + * (missing) + * + * Edges: + * - hasElseBody (statement::Suite, single) : (missing) + * - hasHandler (statement::Handler, multiple) : (missing) + * - hasFinallyBody (statement::Suite, single) : (missing) + */ + class TryExcept : public Try { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + TryExcept(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~TryExcept(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + TryExcept & operator=(const TryExcept&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + TryExcept(const TryExcept&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasElseBody edge points to. + * \return Returns the end point of the hasElseBody edge. + */ + statement::Suite* getElseBody() const; + + /** + * \brief Gives back iterator for the hasHandler edges. + * \return Returns an iterator for the hasHandler edges. + */ + ListIterator getHandlerListIteratorBegin() const; + + /** + * \brief Gives back iterator for the hasHandler edges. + * \return Returns an iterator for the hasHandler edges. + */ + ListIterator getHandlerListIteratorEnd() const; + + /** + * \brief Tells whether the node has hasHandler edges or not. + * \return Returns true if the node doesn't have any hasHandler edge. + */ + bool getHandlerIsEmpty() const; + + /** + * \brief Gives back how many hasHandler edges the node has. + * \return Returns with the number of hasHandler edges. + */ + unsigned getHandlerSize() const; + + /** + * \brief Gives back the pointer of the node the hasFinallyBody edge points to. + * \return Returns the end point of the hasFinallyBody edge. + */ + statement::Suite* getFinallyBody() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasElseBody edge. + * \param id [in] The new end point of the hasElseBody edge. + */ + void setElseBody(NodeId id); + + /** + * \brief Sets the hasElseBody edge. + * \param node [in] The new end point of the hasElseBody edge. + */ + void setElseBody(Suite *node); + + /** + * \brief remove the hasElseBody edge. + */ + void removeElseBody(); + + /** + * \brief Adds a new hasHandler edge to the node and inserts it after the other ones. + * \param node [in] The end point of the new hasHandler edge. + */ + void addHandler(const Handler *node); + + /** + * \brief Adds a new hasHandler edge to the node and inserts it after the other ones. + * \param id [in] The end point of the new hasHandler edge. + */ + void addHandler(NodeId id); + + /** + * \brief Remove the hasHandler edge by id from the node. + * \param id [in] The end point of the hasHandler edge. + */ + void removeHandler(NodeId id); + + /** + * \brief Remove the hasHandler edge from the node. + * \param node [in] The end point of the hasHandler edge. + */ + void removeHandler(Handler *node); + + /** + * \brief Sets the hasFinallyBody edge. + * \param id [in] The new end point of the hasFinallyBody edge. + */ + void setFinallyBody(NodeId id); + + /** + * \brief Sets the hasFinallyBody edge. + * \param node [in] The new end point of the hasFinallyBody edge. + */ + void setFinallyBody(Suite *node); + + /** + * \brief remove the hasFinallyBody edge. + */ + void removeFinallyBody(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasElseBody edge points to. */ + NodeId m_hasElseBody; + + /** \internal \brief Container stores the id of the nodes the hasHandler edge points to. */ + ListIterator::Container hasHandlerContainer; + + /** \internal \brief The id of the node the hasFinallyBody edge points to. */ + NodeId m_hasFinallyBody; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/TryFinal.h b/lib/python/inc/statement/TryFinal.h new file mode 100644 index 0000000..4da6102 --- /dev/null +++ b/lib/python/inc/statement/TryFinal.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_TryFinal_H_ +#define _PYTHON_TryFinal_H_ + +#include "python/inc/python.h" + +/** +* \file TryFinal.h +* \brief Contains declaration of the statement::TryFinal class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief TryFinal class, which represents the statement::TryFinal node. + * (missing) + * + * Edges: + * - hasFinallyBody (statement::Suite, single) : (missing) + */ + class TryFinal : public Try { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + TryFinal(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~TryFinal(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + TryFinal & operator=(const TryFinal&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + TryFinal(const TryFinal&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasFinallyBody edge points to. + * \return Returns the end point of the hasFinallyBody edge. + */ + statement::Suite* getFinallyBody() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasFinallyBody edge. + * \param id [in] The new end point of the hasFinallyBody edge. + */ + void setFinallyBody(NodeId id); + + /** + * \brief Sets the hasFinallyBody edge. + * \param node [in] The new end point of the hasFinallyBody edge. + */ + void setFinallyBody(Suite *node); + + /** + * \brief remove the hasFinallyBody edge. + */ + void removeFinallyBody(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasFinallyBody edge points to. */ + NodeId m_hasFinallyBody; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/While.h b/lib/python/inc/statement/While.h new file mode 100644 index 0000000..e8479d5 --- /dev/null +++ b/lib/python/inc/statement/While.h @@ -0,0 +1,200 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_While_H_ +#define _PYTHON_While_H_ + +#include "python/inc/python.h" + +/** +* \file While.h +* \brief Contains declaration of the statement::While class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief While class, which represents the statement::While node. + * (missing) + * + * Edges: + * - hasTestExpression (expression::Expression, single) : (missing) + */ + class While : public Iteration { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + While(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~While(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + While & operator=(const While&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + While(const While&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasTestExpression edge points to. + * \return Returns the end point of the hasTestExpression edge. + */ + expression::Expression* getTestExpression() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasTestExpression edge. + * \param id [in] The new end point of the hasTestExpression edge. + */ + void setTestExpression(NodeId id); + + /** + * \brief Sets the hasTestExpression edge. + * \param node [in] The new end point of the hasTestExpression edge. + */ + void setTestExpression(expression::Expression *node); + + /** + * \brief remove the hasTestExpression edge. + */ + void removeTestExpression(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasTestExpression edge points to. */ + NodeId m_hasTestExpression; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/statement/With.h b/lib/python/inc/statement/With.h new file mode 100644 index 0000000..a80443a --- /dev/null +++ b/lib/python/inc/statement/With.h @@ -0,0 +1,227 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_With_H_ +#define _PYTHON_With_H_ + +#include "python/inc/python.h" + +/** +* \file With.h +* \brief Contains declaration of the statement::With class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace statement { + + /** + * \brief With class, which represents the statement::With node. + * (missing) + * + * Edges: + * - hasExpression (expression::Expression, single) : (missing) + * - hasTargetList (statement::TargetList, single) : (missing) + */ + class With : public CompoundStatement { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + With(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~With(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + With & operator=(const With&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + With(const With&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the hasExpression edge points to. + * \return Returns the end point of the hasExpression edge. + */ + expression::Expression* getExpression() const; + + /** + * \brief Gives back the pointer of the node the hasTargetList edge points to. + * \return Returns the end point of the hasTargetList edge. + */ + statement::TargetList* getTargetList() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the hasExpression edge. + * \param id [in] The new end point of the hasExpression edge. + */ + void setExpression(NodeId id); + + /** + * \brief Sets the hasExpression edge. + * \param node [in] The new end point of the hasExpression edge. + */ + void setExpression(expression::Expression *node); + + /** + * \brief remove the hasExpression edge. + */ + void removeExpression(); + + /** + * \brief Sets the hasTargetList edge. + * \param id [in] The new end point of the hasTargetList edge. + */ + void setTargetList(NodeId id); + + /** + * \brief Sets the hasTargetList edge. + * \param node [in] The new end point of the hasTargetList edge. + */ + void setTargetList(TargetList *node); + + /** + * \brief remove the hasTargetList edge. + */ + void removeTargetList(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the hasExpression edge points to. */ + NodeId m_hasExpression; + + /** \internal \brief The id of the node the hasTargetList edge points to. */ + NodeId m_hasTargetList; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/type/DictType.h b/lib/python/inc/type/DictType.h new file mode 100644 index 0000000..3c06886 --- /dev/null +++ b/lib/python/inc/type/DictType.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_DictType_H_ +#define _PYTHON_DictType_H_ + +#include "python/inc/python.h" + +/** +* \file DictType.h +* \brief Contains declaration of the type::DictType class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace type { + + /** + * \brief DictType class, which represents the type::DictType node. + * (missing) + */ + class DictType : public Type { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + DictType(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~DictType(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + DictType & operator=(const DictType&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + DictType(const DictType&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/type/ReferenceType.h b/lib/python/inc/type/ReferenceType.h new file mode 100644 index 0000000..dd3bbf3 --- /dev/null +++ b/lib/python/inc/type/ReferenceType.h @@ -0,0 +1,242 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_ReferenceType_H_ +#define _PYTHON_ReferenceType_H_ + +#include "python/inc/python.h" + +/** +* \file ReferenceType.h +* \brief Contains declaration of the type::ReferenceType class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace type { + + /** + * \brief ReferenceType class, which represents the type::ReferenceType node. + * (missing) + * + * Attributes: + * - name (String) : (missing) + * + * Edges: + * - refersTo (base::Positioned, single) : (missing) + */ + class ReferenceType : public Type { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + ReferenceType(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~ReferenceType(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ReferenceType & operator=(const ReferenceType&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + ReferenceType(const ReferenceType&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the name of the node. + * \return Returns with the name. + */ + const std::string& getName() const; + + /** + * \brief Gives back the Key of name of the node. + * \return Returns with the Key of the name. + */ + Key getNameKey() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new value of the name. + */ + void setName(const std::string& _name); + + /** + * \internal + * \brief Sets the name of the node. + * \param name [in] The new Key of the name. + */ + void setNameKey(Key _name); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The Key of the `name`. */ + Key m_name; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Edge getter function(s) ---------- + + /** + * \brief Gives back the pointer of the node the refersTo edge points to. + * \return Returns the end point of the refersTo edge. + */ + base::Positioned* getRefersTo() const; + + + // ---------- Edge setter function(s) ---------- + + /** + * \brief Sets the refersTo edge. + * \param id [in] The new end point of the refersTo edge. + */ + void setRefersTo(NodeId id); + + /** + * \brief Sets the refersTo edge. + * \param node [in] The new end point of the refersTo edge. + */ + void setRefersTo(base::Positioned *node); + + /** + * \brief remove the refersTo edge. + */ + void removeRefersTo(); + + protected: + + // ---------- Edges ---------- + + /** \internal \brief The id of the node the refersTo edge points to. */ + NodeId m_refersTo; + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/type/SequenceType.h b/lib/python/inc/type/SequenceType.h new file mode 100644 index 0000000..dbfac8d --- /dev/null +++ b/lib/python/inc/type/SequenceType.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_SequenceType_H_ +#define _PYTHON_SequenceType_H_ + +#include "python/inc/python.h" + +/** +* \file SequenceType.h +* \brief Contains declaration of the type::SequenceType class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace type { + + /** + * \brief SequenceType class, which represents the type::SequenceType node. + * (missing) + * + * Attributes: + * - kind (SequenceTypeKind) : (missing) + */ + class SequenceType : public Type { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + SequenceType(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~SequenceType(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SequenceType & operator=(const SequenceType&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SequenceType(const SequenceType&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + SequenceTypeKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(SequenceTypeKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The SequenceTypeKind of the node. */ + SequenceTypeKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/type/SimpleType.h b/lib/python/inc/type/SimpleType.h new file mode 100644 index 0000000..e66783f --- /dev/null +++ b/lib/python/inc/type/SimpleType.h @@ -0,0 +1,189 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_SimpleType_H_ +#define _PYTHON_SimpleType_H_ + +#include "python/inc/python.h" + +/** +* \file SimpleType.h +* \brief Contains declaration of the type::SimpleType class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace type { + + /** + * \brief SimpleType class, which represents the type::SimpleType node. + * (missing) + * + * Attributes: + * - kind (SimpleTypeKind) : (missing) + */ + class SimpleType : public Type { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + SimpleType(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~SimpleType(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SimpleType & operator=(const SimpleType&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + SimpleType(const SimpleType&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + + // ---------- Attribute getter function(s) ---------- + + /** + * \brief Gives back the kind of the node. + * \return Returns with the kind. + */ + SimpleTypeKind getKind() const; + + + // ---------- Attribute setter function(s) ---------- + + /** + * \internal + * \brief Sets the kind of the node. + * \param kind [in] The new value of the kind. + */ + void setKind(SimpleTypeKind _kind); + + protected: + + // ---------- Attribute(s) ---------- + + /** \internal \brief The SimpleTypeKind of the node. */ + SimpleTypeKind m_kind; + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept fundtions for Visitor ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/type/Type.h b/lib/python/inc/type/Type.h new file mode 100644 index 0000000..f54d733 --- /dev/null +++ b/lib/python/inc/type/Type.h @@ -0,0 +1,160 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_Type_H_ +#define _PYTHON_Type_H_ + +#include "python/inc/python.h" + +/** +* \file Type.h +* \brief Contains declaration of the type::Type class. +* \brief The it get atributes from +*/ + +namespace columbus { namespace python { namespace asg { +namespace type { + + /** + * \brief Type class, which represents the type::Type node. + * (missing) + */ + class Type : public base::Base { + protected: + /** + * \internal + * \brief Non-public constructor, only factory can instantiates nodes. + * \param nodeId [in] The id of the node. + * \param factory [in] Poiter to the Factory the node belongs to. + */ + Type(NodeId nodeId, Factory *factory); + + /** + * \internal + * \brief Non-public destructor, only factory can destroy nodes. + */ + virtual ~Type(); + + private: + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Type & operator=(const Type&); + + /** + * \brief This function always throws a PythonException due to copying is not allowed! + */ + Type(const Type&); + + public: + /** + * \brief Gives back the NodeKind of the node. + * \return Returns with the NodeKind. + */ + virtual NodeKind getNodeKind() const = 0; + + /** + * \brief Delete all edge. + */ + virtual void prepareDelete(bool tryOnVirtualParent); + + protected: + /** + * \brief Set or add the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if setting was success. + */ + virtual bool setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + protected: + /** + * \brief Remove the edge by edge kind + * \param edgeKind [in] The kind of the edge. + * \param edgeEnd [in] The id of node which is on the end of the edge. + * \param tryOnVirtualParent [in] This is help for the traversal. + * \return Return true if removing was success. + */ + virtual bool removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent); + + public: + + // ---------- Accept functions for Visitor it now pure virtual ---------- + + /** + * \brief It calls the appropriate visit method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void accept(Visitor& visitor) const = 0; + + /** + * \brief It calls the appropriate visitEnd method of the given visitor in the child nodes. + * \param visitor [in] The used visitor. + */ + virtual void acceptEnd(Visitor& visitor) const = 0; + + /** + * \internal + * \brief Calculate node similarity. + * \param nodeIf [in] The other node. + */ + virtual double getSimilarity(const base::Base& node); + + /** + * \internal + * \brief Calculate node hash. + */ + virtual NodeHashType getHash(std::set& node) const ; + + protected: + /** + * \internal + * \brief It is swap the string table ids to the other string table. + * \param newStrTable [in] The new table + * \param oldAndNewStrKeyMap [in] The map for fast serch. + */ + virtual void swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ); + + /** + * \internal + * \brief Saves the node. + * \param io [in] The node is written into io. + */ + virtual void save(io::BinaryIO &io, bool withVirtualBase = true) const; + + /** + * \internal + * \brief Loads the node. + * \param io [in] The node is read from io. + */ + virtual void load(io::BinaryIO &io, bool withVirtualBase = true); + + + friend class python::asg::Factory; + friend class python::asg::VisitorSave; + }; + +} + + +}}} +#endif + diff --git a/lib/python/inc/visitors/Visitor.h b/lib/python/inc/visitors/Visitor.h new file mode 100644 index 0000000..4b52614 --- /dev/null +++ b/lib/python/inc/visitors/Visitor.h @@ -0,0 +1,2337 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITOR_H_ +#define _PYTHON_VISITOR_H_ + +#include "python/inc/python.h" + +/** +* \file Visitor.h +* \brief Contains declaration of Visitor class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Visitor for each non-abstract nodes and all edges of the graph. + */ + class Visitor { + public: + /** + * \brief Constructor for Visitor. + */ + Visitor(); + + /** + * \brief Destructor. + */ + virtual ~Visitor(); + + /** + * \brief Gives back the the actual position's depth in the ASG. + * \return The depth of the actual position. + */ + unsigned getDepth() const; + + /** + * \brief Increasing the depth by one in the ASG. + */ + void incDepth(); + + /** + * \brief Decreasing the depth by one in the ASG. + */ + void decDepth(); + + /** + * \brief This function is calling before the beginning of visiting process. + */ + virtual void beginVisit(); + + /** + * \brief This function is calling when the visiting process has finished. + */ + virtual void finishVisit(); + + /** + * \brief Visitor which is called at the beginning of the base::Comment node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const base::Comment& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the base::Comment node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const base::Comment& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the base::Docstring node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the base::Docstring node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::ArgumentList node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ArgumentList node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::AttributeRef node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::AttributeRef node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::BinaryArithmetic node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::BinaryArithmetic node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::BinaryLogical node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::BinaryLogical node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Call node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Call& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Call node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Call& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::DictComp node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::DictComp node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Dictionary node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Dictionary node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Ellipsis node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Ellipsis node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::ExpressionList node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ExpressionList node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::ExtSlice node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ExtSlice node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::FloatNumber node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::FloatNumber node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Generator node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Generator node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::GeneratorExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::GeneratorExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Identifier node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Identifier node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::IfExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::IfExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::ImagNumber node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ImagNumber node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Index node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Index& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Index node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Index& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::IntegerLiteral node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::IntegerLiteral node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::KeyValue node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::KeyValue node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Keyword node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Keyword node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Lambda node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Lambda node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::List node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::List& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::List node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::List& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::ListComp node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::ListComp node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::LongInteger node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::LongInteger node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Set node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Set& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Set node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Set& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::SetComp node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::SetComp node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Slice node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Slice node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::StringConversion node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::StringConversion node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::StringLiteral node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::StringLiteral node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::Subscription node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::Subscription node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::UnaryOperation node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::UnaryOperation node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the expression::YieldExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the expression::YieldExpression node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the module::Module node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const module::Module& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the module::Module node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Module& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the module::Object node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const module::Object& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the module::Object node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Object& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the module::Package node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const module::Package& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the module::Package node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Package& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Alias node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Alias node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Assert node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Assert node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Assign node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Assign node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::AugAssign node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::AugAssign node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::BaseSpecifier node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::BaseSpecifier node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Break node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Break& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Break node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Break& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::ClassDef node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::ClassDef node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Continue node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Continue node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Delete node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Delete node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Exec node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Exec node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::For node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::For& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::For node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::For& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::FunctionDef node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::FunctionDef node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Global node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Global& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Global node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Global& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Handler node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Handler node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::If node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::If& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::If node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::If& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::ImportFrom node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::ImportFrom node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::ImportStatement node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::ImportStatement node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Parameter node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Parameter node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Pass node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Pass node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Print node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Print& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Print node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Print& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Raise node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Raise node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Return node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Return& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Return node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Return& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::Suite node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::Suite node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::TargetList node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::TargetList node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::TryExcept node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::TryExcept node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::TryFinal node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::TryFinal node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::While node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::While& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::While node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::While& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the statement::With node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::With& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the statement::With node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::With& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the type::DictType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::DictType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the type::DictType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::DictType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the type::ReferenceType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the type::ReferenceType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the type::SequenceType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the type::SequenceType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the beginning of the type::SimpleType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::SimpleType& node , bool callVirtualBase = true); + + /** + * \brief Visitor which is called at the end of the type::SimpleType node visiting. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::SimpleType& node , bool callVirtualBase = true); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge end visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge end visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge end visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge end visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge end visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge end visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge end visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge end visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge end visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + protected: + /** \internal \brief Stores the depth position in the ASG. */ + unsigned depth; + }; // Visitor + + +}}} +#endif + diff --git a/lib/python/inc/visitors/VisitorAbstractNodes.h b/lib/python/inc/visitors/VisitorAbstractNodes.h new file mode 100644 index 0000000..86e8aec --- /dev/null +++ b/lib/python/inc/visitors/VisitorAbstractNodes.h @@ -0,0 +1,1209 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORABSTRACTNODES_H_ +#define _PYTHON_VISITORABSTRACTNODES_H_ + +#include "python/inc/python.h" + +/** +* \file VisitorAbstractNodes.h +* \brief Contains declaration of VisitorAbstractNodes class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Visitor class for all edges and nodes (including abstract nodes as well). + */ + class VisitorAbstractNodes : public Visitor { + public: + /** + * \brief Virtual destructor. + */ + virtual ~VisitorAbstractNodes(); + + /** + * \brief Empty abstract visitor for base::Base node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const base::Base& node , bool callVirtualBase = true); + + /** + * \brief Empty abstract end visitor for base::Base node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const base::Base& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the base::Comment node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const base::Comment& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the base::Comment node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const base::Comment& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the base::Docstring node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the base::Docstring node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the base::Named node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const base::Named& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the base::Named node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const base::Named& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Base,..) of the base::Positioned node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const base::Positioned& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Base,..) of the base::Positioned node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const base::Positioned& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::ArgumentList node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::ArgumentList node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Binary,..) of the expression::AttributeRef node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Binary,..) of the expression::AttributeRef node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Binary node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Binary& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Binary node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Binary& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Binary,..) of the expression::BinaryArithmetic node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Binary,..) of the expression::BinaryArithmetic node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Binary,..) of the expression::BinaryLogical node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Binary,..) of the expression::BinaryLogical node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Unary,..) of the expression::Call node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Call& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Unary,..) of the expression::Call node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Call& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::DictComp node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::DictComp node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Dictionary node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Dictionary node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Slicing,..) of the expression::Ellipsis node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Slicing,..) of the expression::Ellipsis node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::Expression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Expression& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::Expression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Expression& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::ExpressionList node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::ExpressionList node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Slicing,..) of the expression::ExtSlice node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Slicing,..) of the expression::ExtSlice node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Literal,..) of the expression::FloatNumber node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Literal,..) of the expression::FloatNumber node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::Generator node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::Generator node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::GeneratorExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::GeneratorExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Identifier node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Identifier node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::IfExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::IfExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Literal,..) of the expression::ImagNumber node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Literal,..) of the expression::ImagNumber node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Slicing,..) of the expression::Index node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Index& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Slicing,..) of the expression::Index node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Index& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Literal,..) of the expression::IntegerLiteral node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Literal,..) of the expression::IntegerLiteral node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::KeyValue node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::KeyValue node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the expression::Keyword node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the expression::Keyword node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Lambda node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Lambda node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::List node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::List& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::List node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::List& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::ListComp node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::ListComp node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Literal node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Literal& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Literal node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Literal& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Literal,..) of the expression::LongInteger node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Literal,..) of the expression::LongInteger node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Set node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Set& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Set node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Set& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::SetComp node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::SetComp node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Slicing,..) of the expression::Slice node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Slicing,..) of the expression::Slice node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Unary,..) of the expression::Slicing node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Slicing& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Unary,..) of the expression::Slicing node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Slicing& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::StringConversion node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::StringConversion node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Literal,..) of the expression::StringLiteral node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Literal,..) of the expression::StringLiteral node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Unary,..) of the expression::Subscription node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Unary,..) of the expression::Subscription node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::Unary node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::Unary& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::Unary node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::Unary& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Unary,..) of the expression::UnaryOperation node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Unary,..) of the expression::UnaryOperation node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (expression::Expression,..) of the expression::YieldExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (expression::Expression,..) of the expression::YieldExpression node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Named,..) of the module::Module node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const module::Module& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Named,..) of the module::Module node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const module::Module& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Base,..) of the module::Object node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const module::Object& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Base,..) of the module::Object node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const module::Object& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Base,..) of the module::Package node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const module::Package& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Base,..) of the module::Package node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const module::Package& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Named,..) of the statement::Alias node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Named,..) of the statement::Alias node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Assert node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Assert node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Assign node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Assign node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Assign,..) of the statement::AugAssign node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Assign,..) of the statement::AugAssign node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the statement::BaseSpecifier node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the statement::BaseSpecifier node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Break node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Break& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Break node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Break& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::CompoundStatement,..) of the statement::ClassDef node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::CompoundStatement,..) of the statement::ClassDef node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Statement,..) of the statement::CompoundStatement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::CompoundStatement& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Statement,..) of the statement::CompoundStatement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::CompoundStatement& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Continue node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Continue node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Delete node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Delete node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Exec node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Exec node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Iteration,..) of the statement::For node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::For& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Iteration,..) of the statement::For node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::For& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::CompoundStatement,..) of the statement::FunctionDef node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::CompoundStatement,..) of the statement::FunctionDef node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Global node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Global& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Global node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Global& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Statement,..) of the statement::Handler node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Statement,..) of the statement::Handler node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::CompoundStatement,..) of the statement::If node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::If& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::CompoundStatement,..) of the statement::If node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::If& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::ImportStatement,..) of the statement::ImportFrom node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::ImportStatement,..) of the statement::ImportFrom node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::ImportStatement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::ImportStatement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::CompoundStatement,..) of the statement::Iteration node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Iteration& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::CompoundStatement,..) of the statement::Iteration node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Iteration& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Named,..) of the statement::Parameter node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Named,..) of the statement::Parameter node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Pass node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Pass node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Print node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Print& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Print node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Print& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Raise node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Raise node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::SimpleStatement,..) of the statement::Return node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Return& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::SimpleStatement,..) of the statement::Return node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Return& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Statement,..) of the statement::SimpleStatement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::SimpleStatement& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Statement,..) of the statement::SimpleStatement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::SimpleStatement& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the statement::Statement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Statement& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the statement::Statement node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Statement& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the statement::Suite node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the statement::Suite node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Positioned,..) of the statement::TargetList node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Positioned,..) of the statement::TargetList node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::CompoundStatement,..) of the statement::Try node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::Try& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::CompoundStatement,..) of the statement::Try node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::Try& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Try,..) of the statement::TryExcept node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Try,..) of the statement::TryExcept node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Try,..) of the statement::TryFinal node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Try,..) of the statement::TryFinal node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::Iteration,..) of the statement::While node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::While& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::Iteration,..) of the statement::While node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::While& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (statement::CompoundStatement,..) of the statement::With node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const statement::With& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (statement::CompoundStatement,..) of the statement::With node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const statement::With& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (type::Type,..) of the type::DictType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const type::DictType& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (type::Type,..) of the type::DictType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const type::DictType& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (type::Type,..) of the type::ReferenceType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (type::Type,..) of the type::ReferenceType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (type::Type,..) of the type::SequenceType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (type::Type,..) of the type::SequenceType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (type::Type,..) of the type::SimpleType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const type::SimpleType& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (type::Type,..) of the type::SimpleType node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const type::SimpleType& node , bool callVirtualBase = true); + + /** + * \brief Abstract visitor, which calls the visitor of the base class(es) (base::Base,..) of the type::Type node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visit(const type::Type& node , bool callVirtualBase = true); + + /** + * \brief Abstract end visitor, which calls the end visitor of the base class (base::Base,..) of the type::Type node. + * \param node [in] The node which is visited. + * \param callVirtualBase [in] This technically flag is help the call a multiple heritage call the virtual base or not.(the none virtual base is called directly). + */ + virtual void visitEnd(const type::Type& node , bool callVirtualBase = true); + + }; // VisitorAbstractNodes + + +}}} +#endif + diff --git a/lib/python/inc/visitors/VisitorFilter.h b/lib/python/inc/visitors/VisitorFilter.h new file mode 100644 index 0000000..298b15e --- /dev/null +++ b/lib/python/inc/visitors/VisitorFilter.h @@ -0,0 +1,471 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORFILTER_H_ +#define _PYTHON_VISITORFILTER_H_ + +#include "python/inc/python.h" + +/** +* \file VisitorFilter.h +* \brief Contains declaration of VisitorFilter class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief VisitorFilter class filters out nodes from the ASG. + */ + class VisitorFilter : public Visitor { + protected: + /** \internal \brief Pointer to the set(Not)FilteredThisNodeOnly() method. */ + void (Factory::*selector)(NodeId id); + + public: + /** + * \brief Constructor for VisitorFilter. + * \param filter [in] If this parameter is true then the visitor will filter the nodes out. If it is false then it set the nodes to not filtered. + */ + VisitorFilter(bool filter = true); + + /** + * \brief Destructor. + */ + virtual ~VisitorFilter(); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const base::Comment& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const base::Docstring& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ArgumentList& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::AttributeRef& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::BinaryLogical& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Call& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::DictComp& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Dictionary& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Ellipsis& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ExpressionList& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ExtSlice& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::FloatNumber& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Generator& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Identifier& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::IfExpression& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImagNumber& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Index& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::KeyValue& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Keyword& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Lambda& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::List& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ListComp& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::LongInteger& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Set& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::SetComp& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Slice& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::StringConversion& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::StringLiteral& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Subscription& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::UnaryOperation& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::YieldExpression& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Module& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Object& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Package& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Alias& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Assert& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Assign& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::AugAssign& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Break& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ClassDef& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Continue& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Delete& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Exec& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::For& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::FunctionDef& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Global& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Handler& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::If& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ImportFrom& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ImportStatement& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Parameter& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Pass& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Print& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Raise& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Return& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Suite& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TargetList& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TryExcept& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TryFinal& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::While& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::With& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::DictType& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::ReferenceType& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::SequenceType& node , bool callVirtualBase = true); + + /** + * \brief Deselects the actual node (and only this). + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::SimpleType& node , bool callVirtualBase = true); + + }; // VisitorFilter + + +}}} +#endif + diff --git a/lib/python/inc/visitors/VisitorPYTHONML.h b/lib/python/inc/visitors/VisitorPYTHONML.h new file mode 100644 index 0000000..923daf1 --- /dev/null +++ b/lib/python/inc/visitors/VisitorPYTHONML.h @@ -0,0 +1,2856 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORPYTHONML_H_ +#define _PYTHON_VISITORPYTHONML_H_ + +#include "python/inc/python.h" +#include + +/** +* \file VisitorPYTHONML.h +* \brief Contains declaration of VisitorPYTHONML class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Creates XML dump of the ASG. + */ + class VisitorPYTHONML : public Visitor { + public: + + /** + * \brief Constructor of XML generator visitor. + * \param targetStream [in] ofstream to write the output + * \param projectName [in] Name of project - generated into the output + * \param noId [in] Do not write the ID of the nodes. + * \param noLineInfo [in] Do not write the line info of the nodes. + */ + VisitorPYTHONML(std::ofstream& targetStream, + const std::string& _projectName, + bool noId = false, + bool noLineInfo = false); + + /** + * \brief Virtual destructor. + */ + virtual ~VisitorPYTHONML(); + + /** + * \brief This function is calling before the beginning of visiting process. It flushes the header of xml. + */ + void beginVisit(); + + /** + * \brief This function is calling when the visiting process has finished. It flushes the tail of xml. + */ + void finishVisit(); + + /** + * \brief Writes the XML representation of the base::Comment node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const base::Comment& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the base::Comment node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const base::Comment& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the base::Docstring node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const base::Docstring& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the base::Docstring node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const base::Docstring& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::ArgumentList node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ArgumentList& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ArgumentList node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ArgumentList& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::AttributeRef node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::AttributeRef& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::AttributeRef node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::AttributeRef& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::BinaryArithmetic node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::BinaryArithmetic& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::BinaryArithmetic node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::BinaryArithmetic& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::BinaryLogical node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::BinaryLogical& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::BinaryLogical node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::BinaryLogical& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Call node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Call& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Call node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Call& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::DictComp node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::DictComp& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::DictComp node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::DictComp& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Dictionary node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Dictionary& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Dictionary node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Dictionary& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Ellipsis node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Ellipsis& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Ellipsis node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Ellipsis& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::ExpressionList node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ExpressionList& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ExpressionList node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ExpressionList& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::ExtSlice node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ExtSlice& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ExtSlice node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ExtSlice& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::FloatNumber node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::FloatNumber& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::FloatNumber node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::FloatNumber& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Generator node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Generator& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Generator node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Generator& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::GeneratorExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::GeneratorExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::GeneratorExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::GeneratorExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Identifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Identifier& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Identifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Identifier& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::IfExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::IfExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::IfExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::IfExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::ImagNumber node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ImagNumber& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ImagNumber node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ImagNumber& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Index node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Index& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Index node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Index& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::IntegerLiteral node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::IntegerLiteral& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::IntegerLiteral node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::IntegerLiteral& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::KeyValue node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::KeyValue& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::KeyValue node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::KeyValue& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Keyword node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Keyword& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Keyword node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Keyword& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Lambda node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Lambda& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Lambda node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Lambda& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::List node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::List& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::List node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::List& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::ListComp node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::ListComp& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::ListComp node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::ListComp& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::LongInteger node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::LongInteger& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::LongInteger node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::LongInteger& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Set node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Set& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Set node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Set& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::SetComp node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::SetComp& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::SetComp node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::SetComp& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Slice node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Slice& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Slice node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Slice& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::StringConversion node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::StringConversion& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::StringConversion node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::StringConversion& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::StringLiteral node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::StringLiteral& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::StringLiteral node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::StringLiteral& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::Subscription node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::Subscription& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::Subscription node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::Subscription& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::UnaryOperation node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::UnaryOperation& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::UnaryOperation node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::UnaryOperation& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the expression::YieldExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const expression::YieldExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the expression::YieldExpression node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const expression::YieldExpression& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the module::Module node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const module::Module& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the module::Module node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Module& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the module::Object node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const module::Object& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the module::Object node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Object& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the module::Package node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const module::Package& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the module::Package node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const module::Package& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Alias node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Alias& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Alias node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Alias& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Assert node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Assert& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Assert node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Assert& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Assign node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Assign& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Assign node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Assign& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::AugAssign node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::AugAssign& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::AugAssign node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::AugAssign& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::BaseSpecifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::BaseSpecifier& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::BaseSpecifier node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::BaseSpecifier& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Break node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Break& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Break node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Break& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::ClassDef node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::ClassDef& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::ClassDef node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ClassDef& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Continue node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Continue& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Continue node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Continue& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Delete node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Delete& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Delete node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Delete& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Exec node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Exec& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Exec node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Exec& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::For node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::For& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::For node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::For& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::FunctionDef node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::FunctionDef& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::FunctionDef node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::FunctionDef& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Global node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Global& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Global node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Global& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Handler node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Handler& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Handler node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Handler& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::If node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::If& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::If node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::If& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::ImportFrom node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::ImportFrom& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::ImportFrom node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ImportFrom& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::ImportStatement node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::ImportStatement& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::ImportStatement node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::ImportStatement& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Parameter node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Parameter& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Parameter node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Parameter& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Pass node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Pass& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Pass node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Pass& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Print node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Print& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Print node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Print& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Raise node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Raise& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Raise node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Raise& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Return node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Return& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Return node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Return& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::Suite node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::Suite& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::Suite node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::Suite& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::TargetList node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::TargetList& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::TargetList node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TargetList& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::TryExcept node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::TryExcept& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::TryExcept node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TryExcept& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::TryFinal node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::TryFinal& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::TryFinal node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::TryFinal& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::While node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::While& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::While node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::While& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the statement::With node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const statement::With& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the statement::With node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const statement::With& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the type::DictType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::DictType& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the type::DictType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::DictType& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the type::ReferenceType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::ReferenceType& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the type::ReferenceType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::ReferenceType& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the type::SequenceType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::SequenceType& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the type::SequenceType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::SequenceType& node, bool callVirtualBase = true); + + /** + * \brief Writes the XML representation of the type::SimpleType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visit(const type::SimpleType& node, bool callVirtualBase = true); + + /** + * \brief Writes the end part of XML representation of the type::SimpleType node into the output file. + * \param node [in] The node which is visited. + */ + virtual void visitEnd(const type::SimpleType& node, bool callVirtualBase = true); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge end visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge end visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge end visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge end visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge end visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge end visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge end visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge end visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge end visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + protected: + + /** + * \internal + * \brief Creates the indentation according to the depth. + */ + void createIndentation(); + + /** + * \internal + * \brief Replaces the invalid characters for XML in the string. + */ + std::string chk(std::string s); + + /** + * \internal + * \brief Writes out a Range attribute with name. + */ + void writeRange(const char *name, const Range &range); + + /** + * \internal + * \brief Writes out the attributes of the base::Base node. + */ + virtual void writeAttributes(const base::Base& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the base::Comment node. + */ + virtual void writeAttributes(const base::Comment& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the base::Docstring node. + */ + virtual void writeAttributes(const base::Docstring& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the base::Named node. + */ + virtual void writeAttributes(const base::Named& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the base::Positioned node. + */ + virtual void writeAttributes(const base::Positioned& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::ArgumentList node. + */ + virtual void writeAttributes(const expression::ArgumentList& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::AttributeRef node. + */ + virtual void writeAttributes(const expression::AttributeRef& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Binary node. + */ + virtual void writeAttributes(const expression::Binary& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::BinaryArithmetic node. + */ + virtual void writeAttributes(const expression::BinaryArithmetic& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::BinaryLogical node. + */ + virtual void writeAttributes(const expression::BinaryLogical& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Call node. + */ + virtual void writeAttributes(const expression::Call& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::DictComp node. + */ + virtual void writeAttributes(const expression::DictComp& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Dictionary node. + */ + virtual void writeAttributes(const expression::Dictionary& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Ellipsis node. + */ + virtual void writeAttributes(const expression::Ellipsis& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Expression node. + */ + virtual void writeAttributes(const expression::Expression& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::ExpressionList node. + */ + virtual void writeAttributes(const expression::ExpressionList& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::ExtSlice node. + */ + virtual void writeAttributes(const expression::ExtSlice& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::FloatNumber node. + */ + virtual void writeAttributes(const expression::FloatNumber& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Generator node. + */ + virtual void writeAttributes(const expression::Generator& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::GeneratorExpression node. + */ + virtual void writeAttributes(const expression::GeneratorExpression& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Identifier node. + */ + virtual void writeAttributes(const expression::Identifier& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::IfExpression node. + */ + virtual void writeAttributes(const expression::IfExpression& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::ImagNumber node. + */ + virtual void writeAttributes(const expression::ImagNumber& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Index node. + */ + virtual void writeAttributes(const expression::Index& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::IntegerLiteral node. + */ + virtual void writeAttributes(const expression::IntegerLiteral& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::KeyValue node. + */ + virtual void writeAttributes(const expression::KeyValue& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Keyword node. + */ + virtual void writeAttributes(const expression::Keyword& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Lambda node. + */ + virtual void writeAttributes(const expression::Lambda& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::List node. + */ + virtual void writeAttributes(const expression::List& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::ListComp node. + */ + virtual void writeAttributes(const expression::ListComp& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Literal node. + */ + virtual void writeAttributes(const expression::Literal& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::LongInteger node. + */ + virtual void writeAttributes(const expression::LongInteger& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Set node. + */ + virtual void writeAttributes(const expression::Set& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::SetComp node. + */ + virtual void writeAttributes(const expression::SetComp& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Slice node. + */ + virtual void writeAttributes(const expression::Slice& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Slicing node. + */ + virtual void writeAttributes(const expression::Slicing& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::StringConversion node. + */ + virtual void writeAttributes(const expression::StringConversion& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::StringLiteral node. + */ + virtual void writeAttributes(const expression::StringLiteral& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Subscription node. + */ + virtual void writeAttributes(const expression::Subscription& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::Unary node. + */ + virtual void writeAttributes(const expression::Unary& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::UnaryOperation node. + */ + virtual void writeAttributes(const expression::UnaryOperation& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the expression::YieldExpression node. + */ + virtual void writeAttributes(const expression::YieldExpression& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the module::Module node. + */ + virtual void writeAttributes(const module::Module& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the module::Object node. + */ + virtual void writeAttributes(const module::Object& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the module::Package node. + */ + virtual void writeAttributes(const module::Package& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Alias node. + */ + virtual void writeAttributes(const statement::Alias& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Assert node. + */ + virtual void writeAttributes(const statement::Assert& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Assign node. + */ + virtual void writeAttributes(const statement::Assign& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::AugAssign node. + */ + virtual void writeAttributes(const statement::AugAssign& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::BaseSpecifier node. + */ + virtual void writeAttributes(const statement::BaseSpecifier& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Break node. + */ + virtual void writeAttributes(const statement::Break& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::ClassDef node. + */ + virtual void writeAttributes(const statement::ClassDef& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::CompoundStatement node. + */ + virtual void writeAttributes(const statement::CompoundStatement& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Continue node. + */ + virtual void writeAttributes(const statement::Continue& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Delete node. + */ + virtual void writeAttributes(const statement::Delete& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Exec node. + */ + virtual void writeAttributes(const statement::Exec& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::For node. + */ + virtual void writeAttributes(const statement::For& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::FunctionDef node. + */ + virtual void writeAttributes(const statement::FunctionDef& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Global node. + */ + virtual void writeAttributes(const statement::Global& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Handler node. + */ + virtual void writeAttributes(const statement::Handler& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::If node. + */ + virtual void writeAttributes(const statement::If& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::ImportFrom node. + */ + virtual void writeAttributes(const statement::ImportFrom& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::ImportStatement node. + */ + virtual void writeAttributes(const statement::ImportStatement& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Iteration node. + */ + virtual void writeAttributes(const statement::Iteration& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Parameter node. + */ + virtual void writeAttributes(const statement::Parameter& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Pass node. + */ + virtual void writeAttributes(const statement::Pass& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Print node. + */ + virtual void writeAttributes(const statement::Print& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Raise node. + */ + virtual void writeAttributes(const statement::Raise& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Return node. + */ + virtual void writeAttributes(const statement::Return& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::SimpleStatement node. + */ + virtual void writeAttributes(const statement::SimpleStatement& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Statement node. + */ + virtual void writeAttributes(const statement::Statement& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Suite node. + */ + virtual void writeAttributes(const statement::Suite& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::TargetList node. + */ + virtual void writeAttributes(const statement::TargetList& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::Try node. + */ + virtual void writeAttributes(const statement::Try& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::TryExcept node. + */ + virtual void writeAttributes(const statement::TryExcept& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::TryFinal node. + */ + virtual void writeAttributes(const statement::TryFinal& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::While node. + */ + virtual void writeAttributes(const statement::While& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the statement::With node. + */ + virtual void writeAttributes(const statement::With& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the type::DictType node. + */ + virtual void writeAttributes(const type::DictType& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the type::ReferenceType node. + */ + virtual void writeAttributes(const type::ReferenceType& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the type::SequenceType node. + */ + virtual void writeAttributes(const type::SequenceType& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the type::SimpleType node. + */ + virtual void writeAttributes(const type::SimpleType& node, bool composite, bool bWithParent = true); + + /** + * \internal + * \brief Writes out the attributes of the type::Type node. + */ + virtual void writeAttributes(const type::Type& node, bool composite, bool bWithParent = true); + + /** \internal \brief The ofstrem into the xml will be written. */ + std::ofstream &ofs; + + /** \internal \brief Flag to know if the ID of the nodes have to be written or not. */ + bool noId; + + /** \internal \brief Flag to know if the line info of the nodes have to be written or not. */ + bool noLineInfo; + + const std::string projectName; + + }; // VisitorPYTHONML + + +}}} +#endif + diff --git a/lib/python/inc/visitors/VisitorReverseEdges.h b/lib/python/inc/visitors/VisitorReverseEdges.h new file mode 100644 index 0000000..6be166a --- /dev/null +++ b/lib/python/inc/visitors/VisitorReverseEdges.h @@ -0,0 +1,795 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORREVERSEEDGES_H_ +#define _PYTHON_VISITORREVERSEEDGES_H_ + +#include "python/inc/python.h" + +/** +* \file VisitorReverseEdges.h +* \brief Contains declaration of VisitorReverseEdges class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Collects the inverse relation of any "one way" defined edges. + */ + class VisitorReverseEdges : public VisitorAbstractNodes { + private: + + /** + * \brief Disable the copy of object . + */ + VisitorReverseEdges(const VisitorReverseEdges& ); + + /** + * \brief Disable the copy of object. + */ + VisitorReverseEdges& operator=(const VisitorReverseEdges& ); + + protected: + + /** + * \brief Only ReverseEdges can instantiates this class. + * \param reverseEdges [in] The edges are inserted into this. + */ + VisitorReverseEdges(ReverseEdges* reverseEdges); + + /** + * \brief Destructor. + */ + virtual ~VisitorReverseEdges(); + + public: + + /** + * \brief Sets all node "existing" in AlgorithmReverseEdges. + * \param node [in] The node. + */ + virtual void visit(const base::Base &node, bool callVirtualBase = true); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + protected: + + /** \internal \brief Edges are inserted into this ReverseEdges class. */ + ReverseEdges *revEdges; + + friend class ReverseEdges; + + }; // VisitorReverseEdges + + +}}} +#endif + diff --git a/lib/python/inc/visitors/VisitorSave.h b/lib/python/inc/visitors/VisitorSave.h new file mode 100644 index 0000000..e9f627f --- /dev/null +++ b/lib/python/inc/visitors/VisitorSave.h @@ -0,0 +1,60 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORSAVE_H_ +#define _PYTHON_VISITORSAVE_H_ + +#include "python/inc/python.h" + +/** +* \file VisitorSave.h +* \brief Contains declaration of VisitorSave class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Visitor for saving the graph. + */ + class VisitorSave : public VisitorAbstractNodes { + protected: + /** + * \brief Constructor for Visitor. + * \param io [in] The graph is save into this IO. + */ + VisitorSave(io::BinaryIO &io); + + public: + /** + * \brief Visitor for saving node. + * \param node [in] This node is being saved. + */ + virtual void visitEnd(const base::Base &node , bool callVirtualBase = true); + + protected: + /** \internal \brief Pointer to the "output". */ + io::BinaryIO &m_io; + + friend class Factory; + }; // VisitorSave + + +}}} +#endif + diff --git a/lib/python/inc/visitors/VisitorSimpleEdge.h b/lib/python/inc/visitors/VisitorSimpleEdge.h new file mode 100644 index 0000000..b713a22 --- /dev/null +++ b/lib/python/inc/visitors/VisitorSimpleEdge.h @@ -0,0 +1,1492 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORSIMPLEEDGE_H_ +#define _PYTHON_VISITORSIMPLEEDGE_H_ + +#include "python/inc/python.h" + +/** +* \file VisitorSimpleEdge.h +* \brief Contains declaration of VisitorSimpleEdge class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Visitor class for all edges and nodes (including abstract nodes as well). + */ + class VisitorSimpleEdge: public Visitor { + public: + /** + * \brief Virtual destructor. + */ + virtual ~VisitorSimpleEdge(); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end); + + /** + * \brief Edge visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge end visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end); + + /** + * \brief Edge visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge end visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExpression_HasType(const expression::Expression& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge end visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasObject(const expression::Lambda& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndList_HasExpression(const expression::List& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSet_HasExpression(const expression::Set& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end); + + /** + * \brief Edge visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasStride(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge end visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_HasObject(const module::Module& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_HasStatement(const module::Module& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndModule_Docstring(const module::Module& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndObject_RefersTo(const module::Object& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndObject_HasType(const module::Object& begin, const type::Type& end); + + /** + * \brief Edge visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge end visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPackage_HasModule(const module::Package& begin, const module::Module& end); + + /** + * \brief Edge visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge end visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPackage_HasPackage(const module::Package& begin, const module::Package& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAlias_RefersTo(const statement::Alias& begin, const base::Base& end); + + /** + * \brief Edge visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge end visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasExpression(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndExec_HasLocals(const statement::Exec& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFor_HasTargetList(const statement::For& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end); + + /** + * \brief Edge visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge end visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end); + + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasName(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndHandler_HasType(const statement::Handler& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIf_HasElseBody(const statement::If& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIf_HasTestExpression(const statement::If& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge end visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndParameter_RefersTo(const statement::Parameter& begin, const module::Object& end); + + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end); + + /** + * \brief Edge visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndPrint_HasDestination(const statement::Print& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndReturn_HasExpression(const statement::Return& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge end visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end); + + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWith_HasExpression(const statement::With& begin, const expression::Expression& end); + + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndWith_HasTargetList(const statement::With& begin, const statement::TargetList& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + virtual void visitEndReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end); + + /** + * \brief Edge visitor for all edge which is called when the subtree of this edge is finished. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + * \param ac [in] The value of the association class. + * \param kind [in] The kind of the association class. + */ + virtual void visitAllEdge(const base::Base& begin, const base::Base& end) = 0; + + /** + * \brief Edge end visitor for all edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + * \param ac [in] The value of the association class. + * \param kind [in] The kind of the association class. + */ + virtual void visitAllEdgeEnd(const base::Base& begin, const base::Base& end) = 0; + + }; // VisitorSimpleEdge + + +}}} +#endif diff --git a/lib/python/inc/visitors/VisitorSubtreeCollector.h b/lib/python/inc/visitors/VisitorSubtreeCollector.h new file mode 100644 index 0000000..bd2a496 --- /dev/null +++ b/lib/python/inc/visitors/VisitorSubtreeCollector.h @@ -0,0 +1,58 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#ifndef _PYTHON_VISITORSUBTREECOLLECTOR_H_ +#define _PYTHON_VISITORSUBTREECOLLECTOR_H_ + +#include "python/inc/python.h" + +/** +* \file VisitorSubtreeCollector.h +* \brief Contains declaration of VisitorSubtreeCollector class. +*/ + +namespace columbus { namespace python { namespace asg { + /** + * \brief Visitor ... + */ + class VisitorSubtreeCollector : public VisitorAbstractNodes { + public: + /** + * \brief Constructor for Visitor. + * \param nodelist [in, out] The list where the id of the visited nodes are inserted. + */ + VisitorSubtreeCollector(std::list< NodeId> &nodelist); + + /** + * \brief Visitor for all nodes. + * \param node [in] This node is being visited. + */ + virtual void visit(const base::Base &node, bool callVirtualBase = true); + + protected: + /** \internal \brief Reference to the list where the ids will be collected. */ + std::list &nodelist; + + }; // VisitorSave + + +}}} +#endif + diff --git a/lib/python/src/Common.cpp b/lib/python/src/Common.cpp new file mode 100644 index 0000000..2e25793 --- /dev/null +++ b/lib/python/src/Common.cpp @@ -0,0 +1,1392 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/messages.h" +#include + +namespace columbus { namespace python { namespace asg { +namespace Common { + +bool getIsComment(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkComment; +} + +bool getIsDocstring(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkDocstring; +} + +bool getIsNamed(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkNamed || + ndk == ndkModule || + ndk == ndkAlias || + ndk == ndkParameter; +} + +bool getIsPositioned(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkPositioned || + ndk == ndkComment || + ndk == ndkDocstring || + ndk == ndkModule || + ndk == ndkAlias || + ndk == ndkParameter || + ndk == ndkArgumentList || + ndk == ndkAttributeRef || + ndk == ndkBinaryArithmetic || + ndk == ndkBinaryLogical || + ndk == ndkDictComp || + ndk == ndkDictionary || + ndk == ndkExpressionList || + ndk == ndkGeneratorExpression || + ndk == ndkIdentifier || + ndk == ndkIfExpression || + ndk == ndkLambda || + ndk == ndkList || + ndk == ndkListComp || + ndk == ndkFloatNumber || + ndk == ndkImagNumber || + ndk == ndkIntegerLiteral || + ndk == ndkLongInteger || + ndk == ndkStringLiteral || + ndk == ndkSet || + ndk == ndkSetComp || + ndk == ndkStringConversion || + ndk == ndkCall || + ndk == ndkEllipsis || + ndk == ndkExtSlice || + ndk == ndkIndex || + ndk == ndkSlice || + ndk == ndkSubscription || + ndk == ndkUnaryOperation || + ndk == ndkYieldExpression || + ndk == ndkGenerator || + ndk == ndkKeyValue || + ndk == ndkKeyword || + ndk == ndkBaseSpecifier || + ndk == ndkClassDef || + ndk == ndkFunctionDef || + ndk == ndkIf || + ndk == ndkFor || + ndk == ndkWhile || + ndk == ndkTryExcept || + ndk == ndkTryFinal || + ndk == ndkWith || + ndk == ndkHandler || + ndk == ndkAssert || + ndk == ndkAssign || + ndk == ndkAugAssign || + ndk == ndkBreak || + ndk == ndkContinue || + ndk == ndkDelete || + ndk == ndkExec || + ndk == ndkGlobal || + ndk == ndkImportStatement || + ndk == ndkImportFrom || + ndk == ndkPass || + ndk == ndkPrint || + ndk == ndkRaise || + ndk == ndkReturn || + ndk == ndkSuite || + ndk == ndkTargetList; +} + +bool getIsArgumentList(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkArgumentList; +} + +bool getIsAttributeRef(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkAttributeRef; +} + +bool getIsBinary(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkBinary || + ndk == ndkAttributeRef || + ndk == ndkBinaryArithmetic || + ndk == ndkBinaryLogical; +} + +bool getIsBinaryArithmetic(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkBinaryArithmetic; +} + +bool getIsBinaryLogical(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkBinaryLogical; +} + +bool getIsCall(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkCall; +} + +bool getIsDictComp(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkDictComp; +} + +bool getIsDictionary(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkDictionary; +} + +bool getIsEllipsis(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkEllipsis; +} + +bool getIsExpression(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkExpression || + ndk == ndkAttributeRef || + ndk == ndkBinaryArithmetic || + ndk == ndkBinaryLogical || + ndk == ndkDictComp || + ndk == ndkDictionary || + ndk == ndkExpressionList || + ndk == ndkGeneratorExpression || + ndk == ndkIdentifier || + ndk == ndkIfExpression || + ndk == ndkLambda || + ndk == ndkList || + ndk == ndkListComp || + ndk == ndkFloatNumber || + ndk == ndkImagNumber || + ndk == ndkIntegerLiteral || + ndk == ndkLongInteger || + ndk == ndkStringLiteral || + ndk == ndkSet || + ndk == ndkSetComp || + ndk == ndkStringConversion || + ndk == ndkCall || + ndk == ndkEllipsis || + ndk == ndkExtSlice || + ndk == ndkIndex || + ndk == ndkSlice || + ndk == ndkSubscription || + ndk == ndkUnaryOperation || + ndk == ndkYieldExpression; +} + +bool getIsExpressionList(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkExpressionList; +} + +bool getIsExtSlice(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkExtSlice; +} + +bool getIsFloatNumber(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkFloatNumber; +} + +bool getIsGenerator(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkGenerator; +} + +bool getIsGeneratorExpression(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkGeneratorExpression; +} + +bool getIsIdentifier(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkIdentifier; +} + +bool getIsIfExpression(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkIfExpression; +} + +bool getIsImagNumber(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkImagNumber; +} + +bool getIsIndex(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkIndex; +} + +bool getIsIntegerLiteral(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkIntegerLiteral; +} + +bool getIsKeyValue(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkKeyValue; +} + +bool getIsKeyword(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkKeyword; +} + +bool getIsLambda(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkLambda; +} + +bool getIsList(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkList; +} + +bool getIsListComp(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkListComp; +} + +bool getIsLiteral(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkLiteral || + ndk == ndkFloatNumber || + ndk == ndkImagNumber || + ndk == ndkIntegerLiteral || + ndk == ndkLongInteger || + ndk == ndkStringLiteral; +} + +bool getIsLongInteger(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkLongInteger; +} + +bool getIsSet(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSet; +} + +bool getIsSetComp(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSetComp; +} + +bool getIsSlice(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSlice; +} + +bool getIsSlicing(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSlicing || + ndk == ndkEllipsis || + ndk == ndkExtSlice || + ndk == ndkIndex || + ndk == ndkSlice; +} + +bool getIsStringConversion(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkStringConversion; +} + +bool getIsStringLiteral(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkStringLiteral; +} + +bool getIsSubscription(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSubscription; +} + +bool getIsUnary(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkUnary || + ndk == ndkCall || + ndk == ndkEllipsis || + ndk == ndkExtSlice || + ndk == ndkIndex || + ndk == ndkSlice || + ndk == ndkSubscription || + ndk == ndkUnaryOperation; +} + +bool getIsUnaryOperation(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkUnaryOperation; +} + +bool getIsYieldExpression(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkYieldExpression; +} + +bool getIsModule(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkModule; +} + +bool getIsObject(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkObject; +} + +bool getIsPackage(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkPackage; +} + +bool getIsAlias(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkAlias; +} + +bool getIsAssert(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkAssert; +} + +bool getIsAssign(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkAssign || + ndk == ndkAugAssign; +} + +bool getIsAugAssign(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkAugAssign; +} + +bool getIsBaseSpecifier(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkBaseSpecifier; +} + +bool getIsBreak(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkBreak; +} + +bool getIsClassDef(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkClassDef; +} + +bool getIsCompoundStatement(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkCompoundStatement || + ndk == ndkClassDef || + ndk == ndkFunctionDef || + ndk == ndkIf || + ndk == ndkFor || + ndk == ndkWhile || + ndk == ndkTryExcept || + ndk == ndkTryFinal || + ndk == ndkWith; +} + +bool getIsContinue(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkContinue; +} + +bool getIsDelete(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkDelete; +} + +bool getIsExec(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkExec; +} + +bool getIsFor(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkFor; +} + +bool getIsFunctionDef(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkFunctionDef; +} + +bool getIsGlobal(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkGlobal; +} + +bool getIsHandler(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkHandler; +} + +bool getIsIf(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkIf; +} + +bool getIsImportFrom(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkImportFrom; +} + +bool getIsImportStatement(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkImportStatement || + ndk == ndkImportFrom; +} + +bool getIsIteration(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkIteration || + ndk == ndkFor || + ndk == ndkWhile; +} + +bool getIsParameter(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkParameter; +} + +bool getIsPass(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkPass; +} + +bool getIsPrint(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkPrint; +} + +bool getIsRaise(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkRaise; +} + +bool getIsReturn(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkReturn; +} + +bool getIsSimpleStatement(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSimpleStatement || + ndk == ndkAssert || + ndk == ndkAssign || + ndk == ndkAugAssign || + ndk == ndkBreak || + ndk == ndkContinue || + ndk == ndkDelete || + ndk == ndkExec || + ndk == ndkGlobal || + ndk == ndkImportStatement || + ndk == ndkImportFrom || + ndk == ndkPass || + ndk == ndkPrint || + ndk == ndkRaise || + ndk == ndkReturn; +} + +bool getIsStatement(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkStatement || + ndk == ndkClassDef || + ndk == ndkFunctionDef || + ndk == ndkIf || + ndk == ndkFor || + ndk == ndkWhile || + ndk == ndkTryExcept || + ndk == ndkTryFinal || + ndk == ndkWith || + ndk == ndkHandler || + ndk == ndkAssert || + ndk == ndkAssign || + ndk == ndkAugAssign || + ndk == ndkBreak || + ndk == ndkContinue || + ndk == ndkDelete || + ndk == ndkExec || + ndk == ndkGlobal || + ndk == ndkImportStatement || + ndk == ndkImportFrom || + ndk == ndkPass || + ndk == ndkPrint || + ndk == ndkRaise || + ndk == ndkReturn; +} + +bool getIsSuite(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSuite; +} + +bool getIsTargetList(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkTargetList; +} + +bool getIsTry(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkTry || + ndk == ndkTryExcept || + ndk == ndkTryFinal; +} + +bool getIsTryExcept(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkTryExcept; +} + +bool getIsTryFinal(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkTryFinal; +} + +bool getIsWhile(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkWhile; +} + +bool getIsWith(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkWith; +} + +bool getIsDictType(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkDictType; +} + +bool getIsReferenceType(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkReferenceType; +} + +bool getIsSequenceType(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSequenceType; +} + +bool getIsSimpleType(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkSimpleType; +} + +bool getIsType(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkType || + ndk == ndkDictType || + ndk == ndkReferenceType || + ndk == ndkSequenceType || + ndk == ndkSimpleType; +} + +bool getIsAPSpecNode(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkComment || + ndk == ndkDocstring || + ndk == ndkDictType || + ndk == ndkReferenceType || + ndk == ndkSequenceType || + ndk == ndkSimpleType; +} + +bool getIsComposite(const base::Base& node) { + return !getIsNotComposite(node); +} + +bool getIsNotComposite(const base::Base& node) { + NodeKind ndk = node.getNodeKind(); + return + ndk == ndkComment || + ndk == ndkDocstring || + ndk == ndkAlias || + ndk == ndkIdentifier || + ndk == ndkFloatNumber || + ndk == ndkImagNumber || + ndk == ndkIntegerLiteral || + ndk == ndkLongInteger || + ndk == ndkStringLiteral || + ndk == ndkBreak || + ndk == ndkContinue || + ndk == ndkPass || + ndk == ndkObject || + ndk == ndkDictType || + ndk == ndkReferenceType || + ndk == ndkSequenceType || + ndk == ndkSimpleType; +} + +const std::string toString(NodeId id) { + std::stringstream s; + s << id; + return s.str(); +} + +bool getIsBaseClassKind(NodeKind what, NodeKind base) { + NodeKind type = what; + if (type == base) + return true; + switch (type) { + case ndkBase: + return false; + case ndkComment: + return getIsBaseClassKind(ndkPositioned, base); + case ndkDocstring: + return getIsBaseClassKind(ndkPositioned, base); + case ndkNamed: + return getIsBaseClassKind(ndkPositioned, base); + case ndkPositioned: + return getIsBaseClassKind(ndkBase, base); + case ndkArgumentList: + return getIsBaseClassKind(ndkPositioned, base); + case ndkAttributeRef: + return getIsBaseClassKind(ndkBinary, base); + case ndkBinary: + return getIsBaseClassKind(ndkExpression, base); + case ndkBinaryArithmetic: + return getIsBaseClassKind(ndkBinary, base); + case ndkBinaryLogical: + return getIsBaseClassKind(ndkBinary, base); + case ndkCall: + return getIsBaseClassKind(ndkUnary, base); + case ndkDictComp: + return getIsBaseClassKind(ndkExpression, base); + case ndkDictionary: + return getIsBaseClassKind(ndkExpression, base); + case ndkEllipsis: + return getIsBaseClassKind(ndkSlicing, base); + case ndkExpression: + return getIsBaseClassKind(ndkPositioned, base); + case ndkExpressionList: + return getIsBaseClassKind(ndkExpression, base); + case ndkExtSlice: + return getIsBaseClassKind(ndkSlicing, base); + case ndkFloatNumber: + return getIsBaseClassKind(ndkLiteral, base); + case ndkGenerator: + return getIsBaseClassKind(ndkPositioned, base); + case ndkGeneratorExpression: + return getIsBaseClassKind(ndkExpression, base); + case ndkIdentifier: + return getIsBaseClassKind(ndkExpression, base); + case ndkIfExpression: + return getIsBaseClassKind(ndkExpression, base); + case ndkImagNumber: + return getIsBaseClassKind(ndkLiteral, base); + case ndkIndex: + return getIsBaseClassKind(ndkSlicing, base); + case ndkIntegerLiteral: + return getIsBaseClassKind(ndkLiteral, base); + case ndkKeyValue: + return getIsBaseClassKind(ndkPositioned, base); + case ndkKeyword: + return getIsBaseClassKind(ndkPositioned, base); + case ndkLambda: + return getIsBaseClassKind(ndkExpression, base); + case ndkList: + return getIsBaseClassKind(ndkExpression, base); + case ndkListComp: + return getIsBaseClassKind(ndkExpression, base); + case ndkLiteral: + return getIsBaseClassKind(ndkExpression, base); + case ndkLongInteger: + return getIsBaseClassKind(ndkLiteral, base); + case ndkSet: + return getIsBaseClassKind(ndkExpression, base); + case ndkSetComp: + return getIsBaseClassKind(ndkExpression, base); + case ndkSlice: + return getIsBaseClassKind(ndkSlicing, base); + case ndkSlicing: + return getIsBaseClassKind(ndkUnary, base); + case ndkStringConversion: + return getIsBaseClassKind(ndkExpression, base); + case ndkStringLiteral: + return getIsBaseClassKind(ndkLiteral, base); + case ndkSubscription: + return getIsBaseClassKind(ndkUnary, base); + case ndkUnary: + return getIsBaseClassKind(ndkExpression, base); + case ndkUnaryOperation: + return getIsBaseClassKind(ndkUnary, base); + case ndkYieldExpression: + return getIsBaseClassKind(ndkExpression, base); + case ndkModule: + return getIsBaseClassKind(ndkNamed, base); + case ndkObject: + return getIsBaseClassKind(ndkBase, base); + case ndkPackage: + return getIsBaseClassKind(ndkBase, base); + case ndkAlias: + return getIsBaseClassKind(ndkNamed, base); + case ndkAssert: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkAssign: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkAugAssign: + return getIsBaseClassKind(ndkAssign, base); + case ndkBaseSpecifier: + return getIsBaseClassKind(ndkPositioned, base); + case ndkBreak: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkClassDef: + return getIsBaseClassKind(ndkCompoundStatement, base); + case ndkCompoundStatement: + return getIsBaseClassKind(ndkStatement, base); + case ndkContinue: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkDelete: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkExec: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkFor: + return getIsBaseClassKind(ndkIteration, base); + case ndkFunctionDef: + return getIsBaseClassKind(ndkCompoundStatement, base); + case ndkGlobal: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkHandler: + return getIsBaseClassKind(ndkStatement, base); + case ndkIf: + return getIsBaseClassKind(ndkCompoundStatement, base); + case ndkImportFrom: + return getIsBaseClassKind(ndkImportStatement, base); + case ndkImportStatement: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkIteration: + return getIsBaseClassKind(ndkCompoundStatement, base); + case ndkParameter: + return getIsBaseClassKind(ndkNamed, base); + case ndkPass: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkPrint: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkRaise: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkReturn: + return getIsBaseClassKind(ndkSimpleStatement, base); + case ndkSimpleStatement: + return getIsBaseClassKind(ndkStatement, base); + case ndkStatement: + return getIsBaseClassKind(ndkPositioned, base); + case ndkSuite: + return getIsBaseClassKind(ndkPositioned, base); + case ndkTargetList: + return getIsBaseClassKind(ndkPositioned, base); + case ndkTry: + return getIsBaseClassKind(ndkCompoundStatement, base); + case ndkTryExcept: + return getIsBaseClassKind(ndkTry, base); + case ndkTryFinal: + return getIsBaseClassKind(ndkTry, base); + case ndkWhile: + return getIsBaseClassKind(ndkIteration, base); + case ndkWith: + return getIsBaseClassKind(ndkCompoundStatement, base); + case ndkDictType: + return getIsBaseClassKind(ndkType, base); + case ndkReferenceType: + return getIsBaseClassKind(ndkType, base); + case ndkSequenceType: + return getIsBaseClassKind(ndkType, base); + case ndkSimpleType: + return getIsBaseClassKind(ndkType, base); + case ndkType: + return getIsBaseClassKind(ndkBase, base); + default: + return false; + } + return false; +} + +const std::string toString(AssignmentKind kind) { + switch (kind) { + case askAdd: return "askAdd"; + case askSub: return "askSub"; + case askMult: return "askMult"; + case askDiv: return "askDiv"; + case askMod: return "askMod"; + case askPow: return "askPow"; + case askLShift: return "askLShift"; + case askRShift: return "askRShift"; + case askBitOr: return "askBitOr"; + case askBitXor: return "askBitXor"; + case askBitAnd: return "askBitAnd"; + case askFloorDiv: return "askFloorDiv"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(BinaryArithmeticKind kind) { + switch (kind) { + case bakMultiplication: return "bakMultiplication"; + case bakDivision: return "bakDivision"; + case bakFloorDivision: return "bakFloorDivision"; + case bakModulo: return "bakModulo"; + case bakAddition: return "bakAddition"; + case bakSubtraction: return "bakSubtraction"; + case bakPow: return "bakPow"; + case bakLShift: return "bakLShift"; + case bakRShift: return "bakRShift"; + case bakBitOr: return "bakBitOr"; + case bakBitXor: return "bakBitXor"; + case bakBitAnd: return "bakBitAnd"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(BinaryLogicalKind kind) { + switch (kind) { + case blkEq: return "blkEq"; + case blkNotEq: return "blkNotEq"; + case blkLt: return "blkLt"; + case blkLtE: return "blkLtE"; + case blkGt: return "blkGt"; + case blkGtE: return "blkGtE"; + case blkIs: return "blkIs"; + case blkIsNot: return "blkIsNot"; + case blkIn: return "blkIn"; + case blkNotIn: return "blkNotIn"; + case blkAnd: return "blkAnd"; + case blkOr: return "blkOr"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(OriginKind kind) { + switch (kind) { + case orkAnalyzer: return "orkAnalyzer"; + case orkGenerator: return "orkGenerator"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(ParameterKind kind) { + switch (kind) { + case pmkNormal: return "pmkNormal"; + case pmkKwarg: return "pmkKwarg"; + case pmkVararg: return "pmkVararg"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(SequenceTypeKind kind) { + switch (kind) { + case sekString: return "sekString"; + case sekList: return "sekList"; + case sekTuple: return "sekTuple"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(SimpleTypeKind kind) { + switch (kind) { + case stkInteger: return "stkInteger"; + case stkLong: return "stkLong"; + case stkFloat: return "stkFloat"; + case stkImaginary: return "stkImaginary"; + case stkBoolean: return "stkBoolean"; + case stkNone: return "stkNone"; + case stkUnknown: return "stkUnknown"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(UnaryKind kind) { + switch (kind) { + case unkInvert: return "unkInvert"; + case unkNot: return "unkNot"; + case unkPlus: return "unkPlus"; + case unkMinus: return "unkMinus"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(NodeKind kind) { + switch (kind) { + case ndkBase: return "ndkBase"; + case ndkComment: return "ndkComment"; + case ndkDocstring: return "ndkDocstring"; + case ndkNamed: return "ndkNamed"; + case ndkPositioned: return "ndkPositioned"; + case ndkArgumentList: return "ndkArgumentList"; + case ndkAttributeRef: return "ndkAttributeRef"; + case ndkBinary: return "ndkBinary"; + case ndkBinaryArithmetic: return "ndkBinaryArithmetic"; + case ndkBinaryLogical: return "ndkBinaryLogical"; + case ndkCall: return "ndkCall"; + case ndkDictComp: return "ndkDictComp"; + case ndkDictionary: return "ndkDictionary"; + case ndkEllipsis: return "ndkEllipsis"; + case ndkExpression: return "ndkExpression"; + case ndkExpressionList: return "ndkExpressionList"; + case ndkExtSlice: return "ndkExtSlice"; + case ndkFloatNumber: return "ndkFloatNumber"; + case ndkGenerator: return "ndkGenerator"; + case ndkGeneratorExpression: return "ndkGeneratorExpression"; + case ndkIdentifier: return "ndkIdentifier"; + case ndkIfExpression: return "ndkIfExpression"; + case ndkImagNumber: return "ndkImagNumber"; + case ndkIndex: return "ndkIndex"; + case ndkIntegerLiteral: return "ndkIntegerLiteral"; + case ndkKeyValue: return "ndkKeyValue"; + case ndkKeyword: return "ndkKeyword"; + case ndkLambda: return "ndkLambda"; + case ndkList: return "ndkList"; + case ndkListComp: return "ndkListComp"; + case ndkLiteral: return "ndkLiteral"; + case ndkLongInteger: return "ndkLongInteger"; + case ndkSet: return "ndkSet"; + case ndkSetComp: return "ndkSetComp"; + case ndkSlice: return "ndkSlice"; + case ndkSlicing: return "ndkSlicing"; + case ndkStringConversion: return "ndkStringConversion"; + case ndkStringLiteral: return "ndkStringLiteral"; + case ndkSubscription: return "ndkSubscription"; + case ndkUnary: return "ndkUnary"; + case ndkUnaryOperation: return "ndkUnaryOperation"; + case ndkYieldExpression: return "ndkYieldExpression"; + case ndkModule: return "ndkModule"; + case ndkObject: return "ndkObject"; + case ndkPackage: return "ndkPackage"; + case ndkAlias: return "ndkAlias"; + case ndkAssert: return "ndkAssert"; + case ndkAssign: return "ndkAssign"; + case ndkAugAssign: return "ndkAugAssign"; + case ndkBaseSpecifier: return "ndkBaseSpecifier"; + case ndkBreak: return "ndkBreak"; + case ndkClassDef: return "ndkClassDef"; + case ndkCompoundStatement: return "ndkCompoundStatement"; + case ndkContinue: return "ndkContinue"; + case ndkDelete: return "ndkDelete"; + case ndkExec: return "ndkExec"; + case ndkFor: return "ndkFor"; + case ndkFunctionDef: return "ndkFunctionDef"; + case ndkGlobal: return "ndkGlobal"; + case ndkHandler: return "ndkHandler"; + case ndkIf: return "ndkIf"; + case ndkImportFrom: return "ndkImportFrom"; + case ndkImportStatement: return "ndkImportStatement"; + case ndkIteration: return "ndkIteration"; + case ndkParameter: return "ndkParameter"; + case ndkPass: return "ndkPass"; + case ndkPrint: return "ndkPrint"; + case ndkRaise: return "ndkRaise"; + case ndkReturn: return "ndkReturn"; + case ndkSimpleStatement: return "ndkSimpleStatement"; + case ndkStatement: return "ndkStatement"; + case ndkSuite: return "ndkSuite"; + case ndkTargetList: return "ndkTargetList"; + case ndkTry: return "ndkTry"; + case ndkTryExcept: return "ndkTryExcept"; + case ndkTryFinal: return "ndkTryFinal"; + case ndkWhile: return "ndkWhile"; + case ndkWith: return "ndkWith"; + case ndkDictType: return "ndkDictType"; + case ndkReferenceType: return "ndkReferenceType"; + case ndkSequenceType: return "ndkSequenceType"; + case ndkSimpleType: return "ndkSimpleType"; + case ndkType: return "ndkType"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +const std::string toString(EdgeKind kind) { + switch (kind) { + case edkPositioned_Comments: return "edkPositioned_Comments"; + case edkArgumentList_HasPositionalArguments: return "edkArgumentList_HasPositionalArguments"; + case edkArgumentList_HasDictionary: return "edkArgumentList_HasDictionary"; + case edkArgumentList_HasKeyword: return "edkArgumentList_HasKeyword"; + case edkArgumentList_HasTuple: return "edkArgumentList_HasTuple"; + case edkBinary_HasLeftExpression: return "edkBinary_HasLeftExpression"; + case edkBinary_HasRightExpression: return "edkBinary_HasRightExpression"; + case edkCall_HasArgumentList: return "edkCall_HasArgumentList"; + case edkCall_RefersTo: return "edkCall_RefersTo"; + case edkDictComp_HasKeyValue: return "edkDictComp_HasKeyValue"; + case edkDictComp_HasGenerator: return "edkDictComp_HasGenerator"; + case edkDictionary_HasKeyValue: return "edkDictionary_HasKeyValue"; + case edkExpression_HasType: return "edkExpression_HasType"; + case edkExpressionList_HasExpression: return "edkExpressionList_HasExpression"; + case edkExtSlice_HasItem: return "edkExtSlice_HasItem"; + case edkGenerator_HasCondition: return "edkGenerator_HasCondition"; + case edkGenerator_HasIter: return "edkGenerator_HasIter"; + case edkGenerator_HasTarget: return "edkGenerator_HasTarget"; + case edkGeneratorExpression_HasExpression: return "edkGeneratorExpression_HasExpression"; + case edkGeneratorExpression_HasGenerator: return "edkGeneratorExpression_HasGenerator"; + case edkIdentifier_RefersTo: return "edkIdentifier_RefersTo"; + case edkIfExpression_HasBody: return "edkIfExpression_HasBody"; + case edkIfExpression_HasElseBody: return "edkIfExpression_HasElseBody"; + case edkIfExpression_HasTest: return "edkIfExpression_HasTest"; + case edkKeyValue_HasKey: return "edkKeyValue_HasKey"; + case edkKeyValue_HasValue: return "edkKeyValue_HasValue"; + case edkKeyword_HasKey: return "edkKeyword_HasKey"; + case edkKeyword_HasValue: return "edkKeyword_HasValue"; + case edkLambda_HasObject: return "edkLambda_HasObject"; + case edkLambda_HasParameter: return "edkLambda_HasParameter"; + case edkLambda_HasExpression: return "edkLambda_HasExpression"; + case edkList_HasExpression: return "edkList_HasExpression"; + case edkListComp_HasExpression: return "edkListComp_HasExpression"; + case edkListComp_HasGenerator: return "edkListComp_HasGenerator"; + case edkSet_HasExpression: return "edkSet_HasExpression"; + case edkSetComp_HasExpression: return "edkSetComp_HasExpression"; + case edkSetComp_HasGenerator: return "edkSetComp_HasGenerator"; + case edkSlice_HasLowerBound: return "edkSlice_HasLowerBound"; + case edkSlice_HasStride: return "edkSlice_HasStride"; + case edkSlice_HasUpperBound: return "edkSlice_HasUpperBound"; + case edkStringConversion_HasExpressionList: return "edkStringConversion_HasExpressionList"; + case edkSubscription_HasSlicing: return "edkSubscription_HasSlicing"; + case edkUnary_HasExpression: return "edkUnary_HasExpression"; + case edkYieldExpression_HasYieldExpression: return "edkYieldExpression_HasYieldExpression"; + case edkModule_HasObject: return "edkModule_HasObject"; + case edkModule_HasStatement: return "edkModule_HasStatement"; + case edkModule_Docstring: return "edkModule_Docstring"; + case edkObject_RefersTo: return "edkObject_RefersTo"; + case edkObject_HasType: return "edkObject_HasType"; + case edkPackage_HasModule: return "edkPackage_HasModule"; + case edkPackage_HasPackage: return "edkPackage_HasPackage"; + case edkAlias_RefersTo: return "edkAlias_RefersTo"; + case edkAssert_HasMsgExpression: return "edkAssert_HasMsgExpression"; + case edkAssert_HasTestExpression: return "edkAssert_HasTestExpression"; + case edkAssign_HasExpression: return "edkAssign_HasExpression"; + case edkAssign_HasTargetList: return "edkAssign_HasTargetList"; + case edkBaseSpecifier_HasName: return "edkBaseSpecifier_HasName"; + case edkBaseSpecifier_DerivesFrom: return "edkBaseSpecifier_DerivesFrom"; + case edkClassDef_HasObject: return "edkClassDef_HasObject"; + case edkClassDef_HasBaseSpecifier: return "edkClassDef_HasBaseSpecifier"; + case edkClassDef_HasDecorator: return "edkClassDef_HasDecorator"; + case edkClassDef_RefersTo: return "edkClassDef_RefersTo"; + case edkClassDef_Docstring: return "edkClassDef_Docstring"; + case edkCompoundStatement_HasBody: return "edkCompoundStatement_HasBody"; + case edkDelete_HasTargetList: return "edkDelete_HasTargetList"; + case edkExec_HasExpression: return "edkExec_HasExpression"; + case edkExec_HasGlobals: return "edkExec_HasGlobals"; + case edkExec_HasLocals: return "edkExec_HasLocals"; + case edkFor_HasExpressionList: return "edkFor_HasExpressionList"; + case edkFor_HasTargetList: return "edkFor_HasTargetList"; + case edkFunctionDef_HasDecorator: return "edkFunctionDef_HasDecorator"; + case edkFunctionDef_HasObject: return "edkFunctionDef_HasObject"; + case edkFunctionDef_HasParameter: return "edkFunctionDef_HasParameter"; + case edkFunctionDef_RefersTo: return "edkFunctionDef_RefersTo"; + case edkFunctionDef_ReturnType: return "edkFunctionDef_ReturnType"; + case edkFunctionDef_Docstring: return "edkFunctionDef_Docstring"; + case edkGlobal_HasIdentifier: return "edkGlobal_HasIdentifier"; + case edkHandler_HasName: return "edkHandler_HasName"; + case edkHandler_HasExceptBody: return "edkHandler_HasExceptBody"; + case edkHandler_HasType: return "edkHandler_HasType"; + case edkIf_HasElseBody: return "edkIf_HasElseBody"; + case edkIf_HasTestExpression: return "edkIf_HasTestExpression"; + case edkImportStatement_HasAlias: return "edkImportStatement_HasAlias"; + case edkIteration_HasElseBody: return "edkIteration_HasElseBody"; + case edkParameter_HasDefaultValue: return "edkParameter_HasDefaultValue"; + case edkParameter_RefersTo: return "edkParameter_RefersTo"; + case edkPrint_HasExpressionList: return "edkPrint_HasExpressionList"; + case edkPrint_HasDestination: return "edkPrint_HasDestination"; + case edkRaise_HasTracebackExpression: return "edkRaise_HasTracebackExpression"; + case edkRaise_HasTypeExpression: return "edkRaise_HasTypeExpression"; + case edkRaise_HasValueExpression: return "edkRaise_HasValueExpression"; + case edkReturn_HasExpression: return "edkReturn_HasExpression"; + case edkSuite_HasStatement: return "edkSuite_HasStatement"; + case edkTargetList_HasTarget: return "edkTargetList_HasTarget"; + case edkTryExcept_HasElseBody: return "edkTryExcept_HasElseBody"; + case edkTryExcept_HasHandler: return "edkTryExcept_HasHandler"; + case edkTryExcept_HasFinallyBody: return "edkTryExcept_HasFinallyBody"; + case edkTryFinal_HasFinallyBody: return "edkTryFinal_HasFinallyBody"; + case edkWhile_HasTestExpression: return "edkWhile_HasTestExpression"; + case edkWith_HasExpression: return "edkWith_HasExpression"; + case edkWith_HasTargetList: return "edkWith_HasTargetList"; + case edkReferenceType_RefersTo: return "edkReferenceType_RefersTo"; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } +} + +bool getIsValid(NodeId id) { + return id > 1; +} + +double SimilarityMinimum = 0.1; + +double getSimilarityMinimum() { + return SimilarityMinimum; +} + +void setSimilarityMinimum(double value) { + SimilarityMinimum = value; +} + +double SimilarityMinForStrings = 0.0; + +double getSimilarityMinForStrings() { + return SimilarityMinForStrings; +} + +void setSimilarityMinForStrings(double value) { + SimilarityMinForStrings = value; +} + +double SimilarityMinForEdges = 0.0; + +double getSimilarityMinForEdges() { + return SimilarityMinForEdges; +} + +void setSimilarityMinForEdges(double value) { + SimilarityMinForEdges = value; +} + + + const std::string getQualifiedName(const base::Base& node){ + Factory& fact = node.getFactory(); + std::string parent_name = ""; + std::string ret = ""; + + if (node.getId() == fact.getRoot()->getId()) + return "Python"; + + base::Base* parent = node.getParent(); + if (!parent) + return ""; + + switch (node.getNodeKind()){ + case ndkPackage: + { + if (parent != fact.getRoot()) parent_name = getQualifiedName(*parent); + ret = dynamic_cast(node).getName(); + break; + } + case ndkModule: + { + if (parent != fact.getRoot()) parent_name = getQualifiedName(*parent); + ret = dynamic_cast(node).getName(); + break; + } + case ndkFunctionDef: + { + if (parent != fact.getRoot()) parent_name = getQualifiedName(*parent); + ret = dynamic_cast(node).getName(); + break; + } + case ndkClassDef: + { + if (parent != fact.getRoot()) parent_name = getQualifiedName(*parent); + ret = dynamic_cast(node).getName(); + break; + } + case ndkIdentifier: + { + if (parent != fact.getRoot()) parent_name = getQualifiedName(*parent); + ret = dynamic_cast(node).getName(); + break; + } + case ndkParameter: + { + if (parent != fact.getRoot()) parent_name = getQualifiedName(*parent); + ret = dynamic_cast(node).getName(); + break; + } + default: + { + ret = getQualifiedName(*parent); + } + } + if (!parent_name.empty()) { + ret = parent_name + "." + ret; + } + + return ret; + } + + const std::string getUniqueName(const base::Base& node){ + if (node.getId() == node.getFactory().getRoot()->getId()) + return "Python"; + + if (!node.getParent()) + return ""; + + std::string ret; + std::string name = getQualifiedName(node); + + switch(node.getNodeKind()){ + case ndkPackage: + { + ret = "~Pk"; + break; + } + case ndkModule: + { + ret = "~Mo"; + break; + } + case ndkFunctionDef: + { + ret = "~Fn"; + break; + } + case ndkClassDef: + { + ret = "~Cl"; + break; + } + case ndkIdentifier: + { + ret = "~At"; + break; + } + case ndkParameter: + { + ret = "~At"; + break; + } + default: + { + ret = ""; + } + } + + return name + ret; + } + + char* getUniqueNameForComponent(char* compName) { + return compName; + } + + bool getIsMemberNode(const base::Base& node) { + switch (node.getNodeKind()) { + case ndkPackage: + case ndkModule: + case ndkClassDef: + case ndkFunctionDef: + return true; + default: + return false; + } + } + + base::Base* getScopeParent(const base::Base& node) { + Factory& fact = node.getFactory(); + if (&node == fact.getRoot()) + return NULL; + + base::Base* n = node.getParent(); + while (n) { + switch (n->getNodeKind()) { + case ndkPackage: + case ndkModule: + case ndkFunctionDef: + case ndkClassDef: + return n; + default: + break; + } + n = n->getParent(); + } + + return NULL; + }} // Common + +}}} diff --git a/lib/python/src/Factory.cpp b/lib/python/src/Factory.cpp new file mode 100644 index 0000000..d52c14b --- /dev/null +++ b/lib/python/src/Factory.cpp @@ -0,0 +1,1013 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + +#include +#include +#include + +#include "common/inc/StringSup.h" +#include "common/inc/WriteMessage.h" + +#include "io/inc/ZippedIO.h" + +#include "python/inc/messages.h" + +namespace columbus { namespace python { namespace asg { +Factory::Factory(RefDistributorStrTable& st) : + container(), + strTable(&st), + filter(NULL), + filterOn(true), + reverseEdges(NULL), + registeredPointerStorage(), + root(NULL) +{ + filter = new Filter(*this); + root = dynamic_cast(&createNode(ndkPackage, 100)); + root->setName("Python"); + dictType = 0; +} + +Factory::~Factory() { + if (filter) { + delete filter; + filter = NULL; + } + + if (reverseEdges) + delete reverseEdges; + + for (Container::iterator it = container.begin(); it != container.end(); ++it) + if (*it) + delete *it; + +} + +void Factory::swapStringTable(RefDistributorStrTable& newStrTable){ + if (container.size() > 0 ) { + std::map oldAndNewStrKeyMap; + for (Container::iterator it = container.begin() ;it!= container.end();++it) { + if (*it) { + (*it)->swapStringTable(newStrTable,oldAndNewStrKeyMap); + } + } + } + strTable = &newStrTable; +} + +void Factory::save(const std::string &filename , CsiHeader &header) const { + TurnFilterOffSafely t(*this); + + io::ZippedIO zipIo(filename.c_str(), io::IOBase::omWrite, false); + zipIo.setEndianState(io::BinaryIO::etLittle); + + // saving header ... + header.add(CsiHeader::csih_Type, "PythonLanguage"); + header.add(CsiHeader::csih_APIVersion, APIVersion); + header.add(CsiHeader::csih_BinaryVersion, BinaryVersion); + + header.write(zipIo); + + // saving the ASG + AlgorithmPreorder algPre; + VisitorSave vSave(zipIo); + algPre.run(*this, vSave); + + // Writing the ENDMARK! + zipIo.writeUInt4(0); // NodeId + zipIo.writeUShort2(0); // NodeKind + + // saving string table ... + strTable->save(zipIo, StrTable::strToSave); + + zipIo.close(); + +} + +void Factory::checkHeader(CsiHeader &header) { + // Checking the type + std::string type; + if (!header.get(CsiHeader::csih_Type, type)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_MISSING_FILE_TYPE_INFORMATION); + if (type != "PythonLanguage") + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_WRONG_FILE_TYPE_INFORMATION); + + // Checking API version + std::string apiVersion; + if (!header.get(CsiHeader::csih_APIVersion, apiVersion)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_MISSING_API_VERSION_INFORMATION); + if (apiVersion != APIVersion) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_WRONG_API_VERSION(APIVersion,apiVersion)); + + // Checking binary version + std::string binVersion; + if (!header.get(CsiHeader::csih_BinaryVersion, binVersion)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_MISSING_BINARY_VERSION_INFORMATION); + if (binVersion != BinaryVersion) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_WRONG_BINARY_VERSION(BinaryVersion,binVersion)); + +} + +void Factory::loadHeader(const std::string &filename, CsiHeader &header) { + io::BinaryIO binIo(filename.c_str(), io::IOBase::omRead); + header.read(binIo); + checkHeader(header); + binIo.close(); +} + +void Factory::load(const std::string &filename, CsiHeader &header) { + clear(); + + io::ZippedIO zipIo(filename.c_str(), io::IOBase::omRead, false); + + // loading header + header.read(zipIo); + checkHeader(header); + + // loading the ASG + NodeId id = zipIo.readUInt4(); + NodeKind kind = (NodeKind)zipIo.readUShort2(); + + while (id || kind) { + createNode(kind, id); + container[id]->load(zipIo); + + id = zipIo.readUInt4(); + kind = (NodeKind)zipIo.readUShort2(); + } + + // loading the string table + strTable->loadWithKeepingTheRefMap(zipIo); + + root = dynamic_cast(container[100]); + // fill the deletedNodeIdList with the free ids + for (size_t id = 100; id < container.size(); ++id) + if (container[id] == NULL) + deletedNodeIdList.push_back(id); + + zipIo.close(); + +} + +void Factory::clear() { + disableReverseEdges(); + for (Container::iterator i = container.begin(); i != container.end(); ++i) { + if (*i) { + alertNodeDestroy (*i); + delete *i; + *i = NULL; + } + } + container.clear(); + deletedNodeIdList.clear(); + if (filter) { + delete filter; + filter = new Filter(*this);; + } +} + +void Factory::regPointerStorage(SchemaPointerSorage* storage) { + registeredPointerStorage.push_back(storage); +} + +void Factory::unregPointerStorage(SchemaPointerSorage* storage) { + registeredPointerStorage.erase(std::find(registeredPointerStorage.begin(),registeredPointerStorage.end(),storage)); +} + +void Factory::alertNodeDestroy(const base::Base* node) { + for ( std::list::iterator it = registeredPointerStorage.begin();it != registeredPointerStorage.end();++it) { + (*it)->onDestroyNode(node); + } + +} + +module::Package* Factory::getRoot() const { + return root; +} + +bool Factory::getExist(NodeId id) const { + if (container.size() <= id) + return false; + return container[id] != NULL; +} + +base::Base& Factory::getRef(NodeId id) const { + base::Base* p = NULL; + if (id < container.size()) + p = container[id]; + if (!p) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + return *p; +} + +base::Base* Factory::getPointer(NodeId id) const { + base::Base* p = NULL; + try { + p = container.at(id); + } catch (std::out_of_range e) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + } + return p; +} + +RefDistributorStrTable& Factory::getStringTable() const { + return *strTable; +} + +void Factory::destroyNode(NodeId id) { + if (!reverseEdges) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_YOU_MUST_ENABLE_THE_REVERSE_EDGE_FIRST); + + if (!getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_DOES_NOT_EXISTS); + + std::list nodesToDelete; + VisitorSubtreeCollector visitor(nodesToDelete); + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + ap.run(*this, visitor, id); + + for (std::list::iterator it = nodesToDelete.begin(); it != nodesToDelete.end(); it++) { + alertNodeDestroy(container[*it]); + } + for (std::list::iterator it = nodesToDelete.begin(); it != nodesToDelete.end(); it++) { + container[*it]->prepareDelete(true); + if (reverseEdges) + reverseEdges->removeNode(*it); + + delete container[*it]; + container[*it] = NULL; + deletedNodeIdList.push_back(*it); + common::WriteMsg::write(CMSG_THE_NODE_HAVE_BEEN_DESTROYED, *it); + } +} + +void Factory::destroyThisNodeOnly(NodeId id) { + if (!reverseEdges) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_YOU_MUST_ENABLE_THE_REVERSE_EDGE_FIRST); + + if (id >= container.size()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_DOES_NOT_EXISTS); + + if (!container[id]) + return; + + container[id]->prepareDelete(true); + if (reverseEdges) + reverseEdges->removeNode(id); + + alertNodeDestroy(container[id]); + delete container[id]; + container[id] = NULL; + deletedNodeIdList.push_back(id); +} + +NodeKind Factory::getNodeKind(NodeId id) const { + return getRef(id).getNodeKind(); +} + +Factory::ConstIterator::ConstIterator(const Container* cont, const Factory* fact) : + container(cont), + factory(fact), + i(cont->begin()) +{ +} + +bool Factory::ConstIterator::hasNext() const { + Container::const_iterator j = i; + while (j != container->end() && (!*j || factory->getIsFiltered(*j))) + ++j; + return j != container->end(); +} + +const base::Base& Factory::ConstIterator::next() { + while (i != container->end() && (!*i || factory->getIsFiltered(*i))) + ++i; + if (i == container->end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_NEXT_ELEMENT_DOES_NOT_EXIST); + return **i++; +} + +const Factory::ConstIterator Factory::constIterator() const { + return ConstIterator(&container,this); +} + +bool Factory::isEmpty() const { + for (Container::const_iterator it = container.begin(); it != container.end(); ++it) { + if (*it) { + return false; + } + } + return true; +} + +unsigned Factory::size() const { + return (unsigned)container.size(); +} + +void Factory::turnFilterOn() { + filterOn = true; +} + +void Factory::turnFilterOff() { + filterOn = false; +} + +Factory::TurnFilterOffSafely::TurnFilterOffSafely(Factory& fact) : factory(fact), oldState(fact.getIsFilterTurnedOn()) { + factory.turnFilterOff(); +} + +Factory::TurnFilterOffSafely::TurnFilterOffSafely(const Factory& fact) : factory((Factory&)fact), oldState(fact.getIsFilterTurnedOn()) { + factory.turnFilterOff(); +} + +Factory::TurnFilterOffSafely::~TurnFilterOffSafely() { + if (oldState) + factory.turnFilterOn(); +} + +void* Factory::TurnFilterOffSafely::operator new(size_t) throw() { + return NULL; +} + +void* Factory::TurnFilterOffSafely::operator new[](size_t) throw() { + return NULL; +} + +bool Factory::getIsFilterTurnedOn() const { + return filterOn; +} + +void Factory::initializeFilter() { + filter->initializeFilter(); +} + +bool Factory::getIsFiltered(NodeId id) const { + return !filterOn ? false : filter->getIsFiltered(id); +} + +bool Factory::getIsFiltered(const base::Base* node) const { + if (node == NULL) { + return true; + } + return !filterOn ? false : filter->getIsFiltered(node->getId()); +} + +void Factory::setFiltered(NodeId id) { + filter->setFiltered(id); +} + +void Factory::setNotFiltered(NodeId id) { + filter->setNotFiltered(id); +} + +void Factory::setNotFilteredThisNode(NodeId id) { + filter->setNotFilteredThisNode(id); +} + +Filter::FilterState Factory::getFilterState(NodeId id) const { + return filter->getFilterState(id); +} + +void Factory::loadFilter(const std::string &filename){ + io::BinaryIO binIo(filename.c_str(), io::IOBase::omRead); + + if (!filter) + filter = new Filter(*this); + + filter->load(&binIo); + + if (container.size() > filter->container.size()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_LOADED_FILTER_DOES_NOT_MATCH_TO_THE_CURRENT); + + binIo.close(); +} + +void Factory::saveFilter(const std::string &filename) const { + io::BinaryIO binIo(filename.c_str(), io::IOBase::omWrite); + if (filter) + filter->save(&binIo); + binIo.close(); +} + +void Factory::setFilteredThisNodeOnly(NodeId id) { + filter->setFilteredThisNodeOnly(id); +} + +void Factory::setNotFilteredThisNodeOnly(NodeId id) { + filter->setNotFilteredThisNodeOnly(id); +} + +void Factory::enableReverseEdges(ReverseEdges::FuncPtrWithBaseParameterType newSelector) { + if (!reverseEdges || (newSelector != reverseEdges->selectorFunc)){ + if (reverseEdges){ + delete reverseEdges; + common::WriteMsg::write(CMSG_SELECTOR_FUNCTION_IS_CHANGED); + } + reverseEdges = new ReverseEdges(this, newSelector); + } +} + +void Factory::disableReverseEdges() { + if (reverseEdges) { + delete reverseEdges; + reverseEdges = NULL; + } +} + +const ReverseEdges& Factory::getReverseEdges(ReverseEdges::FuncPtrWithBaseParameterType newSelector) { + if (!reverseEdges|| (newSelector != reverseEdges->selectorFunc)){ + if (reverseEdges){ + delete reverseEdges; + common::WriteMsg::write(CMSG_SELECTOR_FUNCTION_IS_CHANGED); + } + reverseEdges = new ReverseEdges(this, newSelector); + } + return *reverseEdges; +} + +bool Factory::getExistsReverseEdges() const { + return reverseEdges != NULL; +} + +base::Base* Factory::createNode(NodeKind kind) { + base::Base *p = 0; + NodeId id; + if (deletedNodeIdList.empty()) + id = container.size(); + else { + id = deletedNodeIdList.front(); + deletedNodeIdList.pop_front(); + } + switch (kind) { + case ndkArgumentList: p = new expression::ArgumentList(id, this); break; + case ndkAttributeRef: p = new expression::AttributeRef(id, this); break; + case ndkBinaryArithmetic: p = new expression::BinaryArithmetic(id, this); break; + case ndkBinaryLogical: p = new expression::BinaryLogical(id, this); break; + case ndkCall: p = new expression::Call(id, this); break; + case ndkDictComp: p = new expression::DictComp(id, this); break; + case ndkDictionary: p = new expression::Dictionary(id, this); break; + case ndkEllipsis: p = new expression::Ellipsis(id, this); break; + case ndkExpressionList: p = new expression::ExpressionList(id, this); break; + case ndkExtSlice: p = new expression::ExtSlice(id, this); break; + case ndkFloatNumber: p = new expression::FloatNumber(id, this); break; + case ndkGenerator: p = new expression::Generator(id, this); break; + case ndkGeneratorExpression: p = new expression::GeneratorExpression(id, this); break; + case ndkIdentifier: p = new expression::Identifier(id, this); break; + case ndkIfExpression: p = new expression::IfExpression(id, this); break; + case ndkImagNumber: p = new expression::ImagNumber(id, this); break; + case ndkIndex: p = new expression::Index(id, this); break; + case ndkIntegerLiteral: p = new expression::IntegerLiteral(id, this); break; + case ndkKeyValue: p = new expression::KeyValue(id, this); break; + case ndkKeyword: p = new expression::Keyword(id, this); break; + case ndkLambda: p = new expression::Lambda(id, this); break; + case ndkList: p = new expression::List(id, this); break; + case ndkListComp: p = new expression::ListComp(id, this); break; + case ndkLongInteger: p = new expression::LongInteger(id, this); break; + case ndkSet: p = new expression::Set(id, this); break; + case ndkSetComp: p = new expression::SetComp(id, this); break; + case ndkSlice: p = new expression::Slice(id, this); break; + case ndkStringConversion: p = new expression::StringConversion(id, this); break; + case ndkStringLiteral: p = new expression::StringLiteral(id, this); break; + case ndkSubscription: p = new expression::Subscription(id, this); break; + case ndkUnaryOperation: p = new expression::UnaryOperation(id, this); break; + case ndkYieldExpression: p = new expression::YieldExpression(id, this); break; + case ndkModule: p = new module::Module(id, this); break; + case ndkObject: p = new module::Object(id, this); break; + case ndkPackage: p = new module::Package(id, this); break; + case ndkAlias: p = new statement::Alias(id, this); break; + case ndkAssert: p = new statement::Assert(id, this); break; + case ndkAssign: p = new statement::Assign(id, this); break; + case ndkAugAssign: p = new statement::AugAssign(id, this); break; + case ndkBaseSpecifier: p = new statement::BaseSpecifier(id, this); break; + case ndkBreak: p = new statement::Break(id, this); break; + case ndkClassDef: p = new statement::ClassDef(id, this); break; + case ndkContinue: p = new statement::Continue(id, this); break; + case ndkDelete: p = new statement::Delete(id, this); break; + case ndkExec: p = new statement::Exec(id, this); break; + case ndkFor: p = new statement::For(id, this); break; + case ndkFunctionDef: p = new statement::FunctionDef(id, this); break; + case ndkGlobal: p = new statement::Global(id, this); break; + case ndkHandler: p = new statement::Handler(id, this); break; + case ndkIf: p = new statement::If(id, this); break; + case ndkImportFrom: p = new statement::ImportFrom(id, this); break; + case ndkImportStatement: p = new statement::ImportStatement(id, this); break; + case ndkParameter: p = new statement::Parameter(id, this); break; + case ndkPass: p = new statement::Pass(id, this); break; + case ndkPrint: p = new statement::Print(id, this); break; + case ndkRaise: p = new statement::Raise(id, this); break; + case ndkReturn: p = new statement::Return(id, this); break; + case ndkSuite: p = new statement::Suite(id, this); break; + case ndkTargetList: p = new statement::TargetList(id, this); break; + case ndkTryExcept: p = new statement::TryExcept(id, this); break; + case ndkTryFinal: p = new statement::TryFinal(id, this); break; + case ndkWhile: p = new statement::While(id, this); break; + case ndkWith: p = new statement::With(id, this); break; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + + if (container.size() <= id) + container.resize(id + 1); + + container[id] = p; + + if (filter->container.size() < container.size()) + filter->container.resize(container.size()); + filter->container[p->getId()] = Filter::NotFiltered; + + if (reverseEdges) + reverseEdges->insertNode(p->getId()); + + return p; +} + +base::Base& Factory::createNode(NodeKind kind, NodeId i) { + base::Base *p = 0; + switch (kind) { + case ndkComment: p = new base::Comment(i,this); break; + case ndkDocstring: p = new base::Docstring(i,this); break; + case ndkArgumentList: p = new expression::ArgumentList(i,this); break; + case ndkAttributeRef: p = new expression::AttributeRef(i,this); break; + case ndkBinaryArithmetic: p = new expression::BinaryArithmetic(i,this); break; + case ndkBinaryLogical: p = new expression::BinaryLogical(i,this); break; + case ndkCall: p = new expression::Call(i,this); break; + case ndkDictComp: p = new expression::DictComp(i,this); break; + case ndkDictionary: p = new expression::Dictionary(i,this); break; + case ndkEllipsis: p = new expression::Ellipsis(i,this); break; + case ndkExpressionList: p = new expression::ExpressionList(i,this); break; + case ndkExtSlice: p = new expression::ExtSlice(i,this); break; + case ndkFloatNumber: p = new expression::FloatNumber(i,this); break; + case ndkGenerator: p = new expression::Generator(i,this); break; + case ndkGeneratorExpression: p = new expression::GeneratorExpression(i,this); break; + case ndkIdentifier: p = new expression::Identifier(i,this); break; + case ndkIfExpression: p = new expression::IfExpression(i,this); break; + case ndkImagNumber: p = new expression::ImagNumber(i,this); break; + case ndkIndex: p = new expression::Index(i,this); break; + case ndkIntegerLiteral: p = new expression::IntegerLiteral(i,this); break; + case ndkKeyValue: p = new expression::KeyValue(i,this); break; + case ndkKeyword: p = new expression::Keyword(i,this); break; + case ndkLambda: p = new expression::Lambda(i,this); break; + case ndkList: p = new expression::List(i,this); break; + case ndkListComp: p = new expression::ListComp(i,this); break; + case ndkLongInteger: p = new expression::LongInteger(i,this); break; + case ndkSet: p = new expression::Set(i,this); break; + case ndkSetComp: p = new expression::SetComp(i,this); break; + case ndkSlice: p = new expression::Slice(i,this); break; + case ndkStringConversion: p = new expression::StringConversion(i,this); break; + case ndkStringLiteral: p = new expression::StringLiteral(i,this); break; + case ndkSubscription: p = new expression::Subscription(i,this); break; + case ndkUnaryOperation: p = new expression::UnaryOperation(i,this); break; + case ndkYieldExpression: p = new expression::YieldExpression(i,this); break; + case ndkModule: p = new module::Module(i,this); break; + case ndkObject: p = new module::Object(i,this); break; + case ndkPackage: p = new module::Package(i,this); break; + case ndkAlias: p = new statement::Alias(i,this); break; + case ndkAssert: p = new statement::Assert(i,this); break; + case ndkAssign: p = new statement::Assign(i,this); break; + case ndkAugAssign: p = new statement::AugAssign(i,this); break; + case ndkBaseSpecifier: p = new statement::BaseSpecifier(i,this); break; + case ndkBreak: p = new statement::Break(i,this); break; + case ndkClassDef: p = new statement::ClassDef(i,this); break; + case ndkContinue: p = new statement::Continue(i,this); break; + case ndkDelete: p = new statement::Delete(i,this); break; + case ndkExec: p = new statement::Exec(i,this); break; + case ndkFor: p = new statement::For(i,this); break; + case ndkFunctionDef: p = new statement::FunctionDef(i,this); break; + case ndkGlobal: p = new statement::Global(i,this); break; + case ndkHandler: p = new statement::Handler(i,this); break; + case ndkIf: p = new statement::If(i,this); break; + case ndkImportFrom: p = new statement::ImportFrom(i,this); break; + case ndkImportStatement: p = new statement::ImportStatement(i,this); break; + case ndkParameter: p = new statement::Parameter(i,this); break; + case ndkPass: p = new statement::Pass(i,this); break; + case ndkPrint: p = new statement::Print(i,this); break; + case ndkRaise: p = new statement::Raise(i,this); break; + case ndkReturn: p = new statement::Return(i,this); break; + case ndkSuite: p = new statement::Suite(i,this); break; + case ndkTargetList: p = new statement::TargetList(i,this); break; + case ndkTryExcept: p = new statement::TryExcept(i,this); break; + case ndkTryFinal: p = new statement::TryFinal(i,this); break; + case ndkWhile: p = new statement::While(i,this); break; + case ndkWith: p = new statement::With(i,this); break; + case ndkDictType: p = new type::DictType(i,this); break; + case ndkReferenceType: p = new type::ReferenceType(i,this); break; + case ndkSequenceType: p = new type::SequenceType(i,this); break; + case ndkSimpleType: p = new type::SimpleType(i,this); break; + default: throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + + if (container.size() <= i) + container.resize(i + 1); + + container[i] = p; + + if (filter->container.size() < container.size()) + filter->container.resize(container.size()); + filter->container[p->getId()] = Filter::NotFiltered; + + if (reverseEdges) + reverseEdges->insertNode(p->getId()); + + return *p; +} + + expression::ArgumentList* Factory::createArgumentListNode(){ + return dynamic_cast ( createNode(ndkArgumentList)); + } + + expression::AttributeRef* Factory::createAttributeRefNode(){ + return dynamic_cast ( createNode(ndkAttributeRef)); + } + + expression::BinaryArithmetic* Factory::createBinaryArithmeticNode(){ + return dynamic_cast ( createNode(ndkBinaryArithmetic)); + } + + expression::BinaryLogical* Factory::createBinaryLogicalNode(){ + return dynamic_cast ( createNode(ndkBinaryLogical)); + } + + expression::Call* Factory::createCallNode(){ + return dynamic_cast ( createNode(ndkCall)); + } + + expression::DictComp* Factory::createDictCompNode(){ + return dynamic_cast ( createNode(ndkDictComp)); + } + + expression::Dictionary* Factory::createDictionaryNode(){ + return dynamic_cast ( createNode(ndkDictionary)); + } + + expression::Ellipsis* Factory::createEllipsisNode(){ + return dynamic_cast ( createNode(ndkEllipsis)); + } + + expression::ExpressionList* Factory::createExpressionListNode(){ + return dynamic_cast ( createNode(ndkExpressionList)); + } + + expression::ExtSlice* Factory::createExtSliceNode(){ + return dynamic_cast ( createNode(ndkExtSlice)); + } + + expression::FloatNumber* Factory::createFloatNumberNode(){ + return dynamic_cast ( createNode(ndkFloatNumber)); + } + + expression::Generator* Factory::createGeneratorNode(){ + return dynamic_cast ( createNode(ndkGenerator)); + } + + expression::GeneratorExpression* Factory::createGeneratorExpressionNode(){ + return dynamic_cast ( createNode(ndkGeneratorExpression)); + } + + expression::Identifier* Factory::createIdentifierNode(){ + return dynamic_cast ( createNode(ndkIdentifier)); + } + + expression::IfExpression* Factory::createIfExpressionNode(){ + return dynamic_cast ( createNode(ndkIfExpression)); + } + + expression::ImagNumber* Factory::createImagNumberNode(){ + return dynamic_cast ( createNode(ndkImagNumber)); + } + + expression::Index* Factory::createIndexNode(){ + return dynamic_cast ( createNode(ndkIndex)); + } + + expression::IntegerLiteral* Factory::createIntegerLiteralNode(){ + return dynamic_cast ( createNode(ndkIntegerLiteral)); + } + + expression::KeyValue* Factory::createKeyValueNode(){ + return dynamic_cast ( createNode(ndkKeyValue)); + } + + expression::Keyword* Factory::createKeywordNode(){ + return dynamic_cast ( createNode(ndkKeyword)); + } + + expression::Lambda* Factory::createLambdaNode(){ + return dynamic_cast ( createNode(ndkLambda)); + } + + expression::List* Factory::createListNode(){ + return dynamic_cast ( createNode(ndkList)); + } + + expression::ListComp* Factory::createListCompNode(){ + return dynamic_cast ( createNode(ndkListComp)); + } + + expression::LongInteger* Factory::createLongIntegerNode(){ + return dynamic_cast ( createNode(ndkLongInteger)); + } + + expression::Set* Factory::createSetNode(){ + return dynamic_cast ( createNode(ndkSet)); + } + + expression::SetComp* Factory::createSetCompNode(){ + return dynamic_cast ( createNode(ndkSetComp)); + } + + expression::Slice* Factory::createSliceNode(){ + return dynamic_cast ( createNode(ndkSlice)); + } + + expression::StringConversion* Factory::createStringConversionNode(){ + return dynamic_cast ( createNode(ndkStringConversion)); + } + + expression::StringLiteral* Factory::createStringLiteralNode(){ + return dynamic_cast ( createNode(ndkStringLiteral)); + } + + expression::Subscription* Factory::createSubscriptionNode(){ + return dynamic_cast ( createNode(ndkSubscription)); + } + + expression::UnaryOperation* Factory::createUnaryOperationNode(){ + return dynamic_cast ( createNode(ndkUnaryOperation)); + } + + expression::YieldExpression* Factory::createYieldExpressionNode(){ + return dynamic_cast ( createNode(ndkYieldExpression)); + } + + module::Module* Factory::createModuleNode(){ + return dynamic_cast ( createNode(ndkModule)); + } + + module::Object* Factory::createObjectNode(){ + return dynamic_cast ( createNode(ndkObject)); + } + + module::Package* Factory::createPackageNode(){ + return dynamic_cast ( createNode(ndkPackage)); + } + + statement::Alias* Factory::createAliasNode(){ + return dynamic_cast ( createNode(ndkAlias)); + } + + statement::Assert* Factory::createAssertNode(){ + return dynamic_cast ( createNode(ndkAssert)); + } + + statement::Assign* Factory::createAssignNode(){ + return dynamic_cast ( createNode(ndkAssign)); + } + + statement::AugAssign* Factory::createAugAssignNode(){ + return dynamic_cast ( createNode(ndkAugAssign)); + } + + statement::BaseSpecifier* Factory::createBaseSpecifierNode(){ + return dynamic_cast ( createNode(ndkBaseSpecifier)); + } + + statement::Break* Factory::createBreakNode(){ + return dynamic_cast ( createNode(ndkBreak)); + } + + statement::ClassDef* Factory::createClassDefNode(){ + return dynamic_cast ( createNode(ndkClassDef)); + } + + statement::Continue* Factory::createContinueNode(){ + return dynamic_cast ( createNode(ndkContinue)); + } + + statement::Delete* Factory::createDeleteNode(){ + return dynamic_cast ( createNode(ndkDelete)); + } + + statement::Exec* Factory::createExecNode(){ + return dynamic_cast ( createNode(ndkExec)); + } + + statement::For* Factory::createForNode(){ + return dynamic_cast ( createNode(ndkFor)); + } + + statement::FunctionDef* Factory::createFunctionDefNode(){ + return dynamic_cast ( createNode(ndkFunctionDef)); + } + + statement::Global* Factory::createGlobalNode(){ + return dynamic_cast ( createNode(ndkGlobal)); + } + + statement::Handler* Factory::createHandlerNode(){ + return dynamic_cast ( createNode(ndkHandler)); + } + + statement::If* Factory::createIfNode(){ + return dynamic_cast ( createNode(ndkIf)); + } + + statement::ImportFrom* Factory::createImportFromNode(){ + return dynamic_cast ( createNode(ndkImportFrom)); + } + + statement::ImportStatement* Factory::createImportStatementNode(){ + return dynamic_cast ( createNode(ndkImportStatement)); + } + + statement::Parameter* Factory::createParameterNode(){ + return dynamic_cast ( createNode(ndkParameter)); + } + + statement::Pass* Factory::createPassNode(){ + return dynamic_cast ( createNode(ndkPass)); + } + + statement::Print* Factory::createPrintNode(){ + return dynamic_cast ( createNode(ndkPrint)); + } + + statement::Raise* Factory::createRaiseNode(){ + return dynamic_cast ( createNode(ndkRaise)); + } + + statement::Return* Factory::createReturnNode(){ + return dynamic_cast ( createNode(ndkReturn)); + } + + statement::Suite* Factory::createSuiteNode(){ + return dynamic_cast ( createNode(ndkSuite)); + } + + statement::TargetList* Factory::createTargetListNode(){ + return dynamic_cast ( createNode(ndkTargetList)); + } + + statement::TryExcept* Factory::createTryExceptNode(){ + return dynamic_cast ( createNode(ndkTryExcept)); + } + + statement::TryFinal* Factory::createTryFinalNode(){ + return dynamic_cast ( createNode(ndkTryFinal)); + } + + statement::While* Factory::createWhileNode(){ + return dynamic_cast ( createNode(ndkWhile)); + } + + statement::With* Factory::createWithNode(){ + return dynamic_cast ( createNode(ndkWith)); + } + + void Factory::printNodeSizes() { + printf("base::Comment node: %dbyte(s)\n",(int)sizeof(base::Comment)); + printf("base::Docstring node: %dbyte(s)\n",(int)sizeof(base::Docstring)); + printf("expression::ArgumentList node: %dbyte(s)\n",(int)sizeof(expression::ArgumentList)); + printf("expression::AttributeRef node: %dbyte(s)\n",(int)sizeof(expression::AttributeRef)); + printf("expression::BinaryArithmetic node: %dbyte(s)\n",(int)sizeof(expression::BinaryArithmetic)); + printf("expression::BinaryLogical node: %dbyte(s)\n",(int)sizeof(expression::BinaryLogical)); + printf("expression::Call node: %dbyte(s)\n",(int)sizeof(expression::Call)); + printf("expression::DictComp node: %dbyte(s)\n",(int)sizeof(expression::DictComp)); + printf("expression::Dictionary node: %dbyte(s)\n",(int)sizeof(expression::Dictionary)); + printf("expression::Ellipsis node: %dbyte(s)\n",(int)sizeof(expression::Ellipsis)); + printf("expression::ExpressionList node: %dbyte(s)\n",(int)sizeof(expression::ExpressionList)); + printf("expression::ExtSlice node: %dbyte(s)\n",(int)sizeof(expression::ExtSlice)); + printf("expression::FloatNumber node: %dbyte(s)\n",(int)sizeof(expression::FloatNumber)); + printf("expression::Generator node: %dbyte(s)\n",(int)sizeof(expression::Generator)); + printf("expression::GeneratorExpression node: %dbyte(s)\n",(int)sizeof(expression::GeneratorExpression)); + printf("expression::Identifier node: %dbyte(s)\n",(int)sizeof(expression::Identifier)); + printf("expression::IfExpression node: %dbyte(s)\n",(int)sizeof(expression::IfExpression)); + printf("expression::ImagNumber node: %dbyte(s)\n",(int)sizeof(expression::ImagNumber)); + printf("expression::Index node: %dbyte(s)\n",(int)sizeof(expression::Index)); + printf("expression::IntegerLiteral node: %dbyte(s)\n",(int)sizeof(expression::IntegerLiteral)); + printf("expression::KeyValue node: %dbyte(s)\n",(int)sizeof(expression::KeyValue)); + printf("expression::Keyword node: %dbyte(s)\n",(int)sizeof(expression::Keyword)); + printf("expression::Lambda node: %dbyte(s)\n",(int)sizeof(expression::Lambda)); + printf("expression::List node: %dbyte(s)\n",(int)sizeof(expression::List)); + printf("expression::ListComp node: %dbyte(s)\n",(int)sizeof(expression::ListComp)); + printf("expression::LongInteger node: %dbyte(s)\n",(int)sizeof(expression::LongInteger)); + printf("expression::Set node: %dbyte(s)\n",(int)sizeof(expression::Set)); + printf("expression::SetComp node: %dbyte(s)\n",(int)sizeof(expression::SetComp)); + printf("expression::Slice node: %dbyte(s)\n",(int)sizeof(expression::Slice)); + printf("expression::StringConversion node: %dbyte(s)\n",(int)sizeof(expression::StringConversion)); + printf("expression::StringLiteral node: %dbyte(s)\n",(int)sizeof(expression::StringLiteral)); + printf("expression::Subscription node: %dbyte(s)\n",(int)sizeof(expression::Subscription)); + printf("expression::UnaryOperation node: %dbyte(s)\n",(int)sizeof(expression::UnaryOperation)); + printf("expression::YieldExpression node: %dbyte(s)\n",(int)sizeof(expression::YieldExpression)); + printf("module::Module node: %dbyte(s)\n",(int)sizeof(module::Module)); + printf("module::Object node: %dbyte(s)\n",(int)sizeof(module::Object)); + printf("module::Package node: %dbyte(s)\n",(int)sizeof(module::Package)); + printf("statement::Alias node: %dbyte(s)\n",(int)sizeof(statement::Alias)); + printf("statement::Assert node: %dbyte(s)\n",(int)sizeof(statement::Assert)); + printf("statement::Assign node: %dbyte(s)\n",(int)sizeof(statement::Assign)); + printf("statement::AugAssign node: %dbyte(s)\n",(int)sizeof(statement::AugAssign)); + printf("statement::BaseSpecifier node: %dbyte(s)\n",(int)sizeof(statement::BaseSpecifier)); + printf("statement::Break node: %dbyte(s)\n",(int)sizeof(statement::Break)); + printf("statement::ClassDef node: %dbyte(s)\n",(int)sizeof(statement::ClassDef)); + printf("statement::Continue node: %dbyte(s)\n",(int)sizeof(statement::Continue)); + printf("statement::Delete node: %dbyte(s)\n",(int)sizeof(statement::Delete)); + printf("statement::Exec node: %dbyte(s)\n",(int)sizeof(statement::Exec)); + printf("statement::For node: %dbyte(s)\n",(int)sizeof(statement::For)); + printf("statement::FunctionDef node: %dbyte(s)\n",(int)sizeof(statement::FunctionDef)); + printf("statement::Global node: %dbyte(s)\n",(int)sizeof(statement::Global)); + printf("statement::Handler node: %dbyte(s)\n",(int)sizeof(statement::Handler)); + printf("statement::If node: %dbyte(s)\n",(int)sizeof(statement::If)); + printf("statement::ImportFrom node: %dbyte(s)\n",(int)sizeof(statement::ImportFrom)); + printf("statement::ImportStatement node: %dbyte(s)\n",(int)sizeof(statement::ImportStatement)); + printf("statement::Parameter node: %dbyte(s)\n",(int)sizeof(statement::Parameter)); + printf("statement::Pass node: %dbyte(s)\n",(int)sizeof(statement::Pass)); + printf("statement::Print node: %dbyte(s)\n",(int)sizeof(statement::Print)); + printf("statement::Raise node: %dbyte(s)\n",(int)sizeof(statement::Raise)); + printf("statement::Return node: %dbyte(s)\n",(int)sizeof(statement::Return)); + printf("statement::Suite node: %dbyte(s)\n",(int)sizeof(statement::Suite)); + printf("statement::TargetList node: %dbyte(s)\n",(int)sizeof(statement::TargetList)); + printf("statement::TryExcept node: %dbyte(s)\n",(int)sizeof(statement::TryExcept)); + printf("statement::TryFinal node: %dbyte(s)\n",(int)sizeof(statement::TryFinal)); + printf("statement::While node: %dbyte(s)\n",(int)sizeof(statement::While)); + printf("statement::With node: %dbyte(s)\n",(int)sizeof(statement::With)); + printf("type::DictType node: %dbyte(s)\n",(int)sizeof(type::DictType)); + printf("type::ReferenceType node: %dbyte(s)\n",(int)sizeof(type::ReferenceType)); + printf("type::SequenceType node: %dbyte(s)\n",(int)sizeof(type::SequenceType)); + printf("type::SimpleType node: %dbyte(s)\n",(int)sizeof(type::SimpleType)); + } +type::SimpleType& Factory::createSimpleType(SimpleTypeKind kind){ + std::map::iterator it = simpleType.find(kind); + + if(it == simpleType.end()){ + type::SimpleType& type = dynamic_cast(createNode(ndkSimpleType, container.size())); + type.setKind(kind); + simpleType[kind] = type.getId(); + return type; + } + + return dynamic_cast(getRef((*it).second)); +} + +type::SequenceType& Factory::createSequenceType(SequenceTypeKind kind){ + std::map::iterator it = sequenceType.find(kind); + + if(it == sequenceType.end()){ + type::SequenceType& type = dynamic_cast(createNode(ndkSequenceType, container.size())); + type.setKind(kind); + sequenceType[kind] = type.getId(); + return type; + } + + return dynamic_cast(getRef((*it).second)); +} + +type::DictType& Factory::createDictType(){ + if(dictType == 0){ + dictType = container.size(); + createNode(ndkDictType, dictType); + } + + return dynamic_cast(getRef(dictType)); +} + +type::ReferenceType& Factory::createReferenceType(NodeId refersTo){ + std::map::iterator it = referenceType.find(refersTo); + + if(it == referenceType.end()){ + type::ReferenceType& type = dynamic_cast(createNode(ndkReferenceType, container.size())); + type.setRefersTo(refersTo); + referenceType[refersTo] = type.getId(); + return type; + } + + return dynamic_cast(getRef((*it).second)); +} + +base::Docstring& Factory::createDocstring() { + return dynamic_cast(createNode(ndkDocstring, container.size())); +} + +base::Comment& Factory::createComment() { + return dynamic_cast(createNode(ndkComment, container.size())); +} + + +}}} diff --git a/lib/python/src/Filter.cpp b/lib/python/src/Filter.cpp new file mode 100644 index 0000000..847a5fd --- /dev/null +++ b/lib/python/src/Filter.cpp @@ -0,0 +1,111 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/messages.h" + +namespace columbus { namespace python { namespace asg { +Filter::Filter(Factory& fact) : container(),factory(fact) { +} + +void Filter::initializeFilter() { + if (container.size() < factory.size()) + container.resize(factory.size()); + for (Container::iterator i = container.begin(); i != container.end(); ++i) + *i = NotFiltered; +} + +bool Filter::getIsFiltered(NodeId id) const { + if (container.size() <= id) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + return container[id] == Filtered; +} + +void Filter::setFiltered(NodeId id) { + if (Common::getIsValid(id)) { + VisitorFilter v; + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + ap.run(factory, v, id); + } +} + +void Filter::setNotFiltered(NodeId id) { + if (factory.getExist(id)) { + Factory::TurnFilterOffSafely tfos(factory); + VisitorFilter v(false); + AlgorithmPreorder ap; + ap.setVisitSpecialNodes(false, false); + ap.run(factory, v, id); + // none of the ancestors are allowed to be filtered + base::Base *node = factory.getPointer(id); + do { + container[node->getId()] = NotFiltered; + node = node->getParent(); + } while (node); + } +} + +void Filter::setNotFilteredThisNode(NodeId id) { + if (factory.getExist(id)) { + base::Base *node = factory.getPointer(id); + do { + container[node->getId()] = NotFiltered; + node = node->getParent(); + } while (node && container[node->getId()] == Filtered); + } +} + +void Filter::setFilteredThisNodeOnly(NodeId id) { + if (container.size() <= id) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + // do not let filter the root node + if (id == factory.getRoot()->getId()) + return; + container[id] = Filtered; +} + +void Filter::setNotFilteredThisNodeOnly(NodeId id) { + if (container.size() <= id) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + container[id] = NotFiltered; +} + +Filter::FilterState Filter::getFilterState(NodeId id) const { + if (container.size() <= id) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + return container[id]; +} + +void Filter::save(io::BinaryIO *binIo) const { + binIo->writeUInt4((unsigned int)container.size()); + for (Container::const_iterator it = container.begin(); it != container.end(); ++it) + binIo->writeUByte1(*it); +} + +void Filter::load(io::BinaryIO *binIo) { + unsigned long size = binIo->readUInt4(); + container.resize(size); + for (unsigned long i = 0; i < size; ++i) + container[i] = (FilterState)binIo->readUByte1(); +} + + +}}} diff --git a/lib/python/src/ListIterator.cpp b/lib/python/src/ListIterator.cpp new file mode 100644 index 0000000..be531c4 --- /dev/null +++ b/lib/python/src/ListIterator.cpp @@ -0,0 +1,215 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + +#include "python/inc/messages.h" + +namespace columbus { namespace python { namespace asg { + template + ListIteratorBase::ListIteratorBase(const Container *_container, const Factory* factory, bool createAsBegin) : + fact(factory), + container(_container), + it(createAsBegin ? container->begin() : container->end()), + invalid(false) + { + if (createAsBegin) { + if (it != container->end() && fact->getIsFiltered(*it)) + next(); + } + } + + template + ListIteratorBase::ListIteratorBase(const ListIteratorBase &iterator) : + fact(iterator.fact), + container(iterator.container), + it(iterator.it), + invalid(iterator.invalid) + { + } + + template + ListIteratorBase::~ListIteratorBase() { + } + + template + ListIteratorBase& ListIteratorBase::operator=(const ListIteratorBase& otherIt) { + if (this == &otherIt) + return *this; + + if (otherIt.invalid) + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + + fact = otherIt.fact; + container = otherIt.container; + it = otherIt.it; + invalid = otherIt.invalid; + + return *this; + } + + template + const T& ListIteratorBase::operator*() { + T *node = dynamic_cast(fact->getPointer(*it)); + return *node; + } + + template + const T* ListIteratorBase::operator->() { + T *node = dynamic_cast(fact->getPointer(*it)); + return node; + } + + template + ListIteratorBase& ListIteratorBase::operator++() { + next(); + return *this; + } + + template + ListIteratorBase& ListIteratorBase::operator--() { + previous(); + return *this; + } + + template + bool ListIteratorBase::operator==(const ListIteratorBase& rhs) const { + return it == rhs.it; + } + + template + bool ListIteratorBase::operator!=(const ListIteratorBase& rhs) const { + return !(*this == rhs); + } + + template + void ListIteratorBase::next() { + if (invalid) + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + + it = nextItem(); + } + + template + void ListIteratorBase::previous() { + if (invalid) + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + + it = previousItem(); + } + + template + bool ListIteratorBase::equals(const ListIteratorBase& otherIt) const { + if (invalid) + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + + return (it == otherIt.it) ; + } + + template + typename ListIteratorBase::Container::const_iterator ListIteratorBase::findNext(const typename ListIteratorBase::Container::const_iterator& _it) { + typename Container::const_iterator j = _it; + + if (j == container->end() ) + return container->end(); + + ++j; + return j; + } + + template + typename ListIteratorBase::Container::const_iterator ListIteratorBase::findNextNotFiltered(const typename ListIteratorBase::Container::const_iterator& _it) { + typename Container::const_iterator nextElement = findNext( _it); + + while (nextElement != container->end() && fact->getIsFiltered(*nextElement)) + nextElement = findNext( nextElement); + + return nextElement; + } + + template + typename ListIteratorBase::Container::const_iterator ListIteratorBase::nextItem() { + return findNextNotFiltered(it); + } + + template + typename ListIteratorBase::Container::const_iterator ListIteratorBase::findPrevious(const typename ListIteratorBase::Container::const_iterator& _it) { + typename Container::const_iterator j = _it; + + if (j == container->begin() ) + return container->end(); + + --j; + return j; + } + + template + typename ListIteratorBase::Container::const_iterator ListIteratorBase::findPreviousNotFiltered(const typename ListIteratorBase::Container::const_iterator& _it) { + typename Container::const_iterator prevElement = findPrevious( _it); + + while (prevElement != container->end() && fact->getIsFiltered(*prevElement)) + prevElement = findPrevious( prevElement); + + return prevElement; + } + + template + typename ListIteratorBase::Container::const_iterator ListIteratorBase::previousItem() { + return findPreviousNotFiltered(it); + } + + template + ListIterator::ListIterator(const Container *container, const Factory* factory, bool createAsBegin) : ListIteratorBase(container, factory, createAsBegin) { + } + + template + ListIterator::~ListIterator() { + } + + template + ListIterator::ListIterator(const ListIterator& otherIt) : ListIteratorBase(otherIt) { + } + + template + ListIterator& ListIterator::operator=(const ListIterator& otherIt) { + ListIteratorBase::operator=(otherIt); + + return *this; + } + + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + template class ListIterator; + +}}} diff --git a/lib/python/src/PythonCollector.cpp b/lib/python/src/PythonCollector.cpp new file mode 100644 index 0000000..7341ee1 --- /dev/null +++ b/lib/python/src/PythonCollector.cpp @@ -0,0 +1,155 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/messages.h" + +#include +#include + +#include +#include + +using namespace std; +using namespace common; + +namespace columbus { namespace python { + +static bool isIgnored(const boost::filesystem::path& p, const list& ignoreList) { + for (list::const_iterator it = ignoreList.begin(), itEnd = ignoreList.end(); it != itEnd; ++it) { + if (p.filename().string() == *it) { + return true; + } + } + return false; +} + +static void collectPackages(const string& fileOrDir, const list& ignoreList, bool checkSubDirs, list& packagePaths) { + try { + boost::filesystem::path p(fileOrDir); + + if (boost::filesystem::exists(p)) { + + // skip hidden files and directories + std::string filename = p.filename().string(); + if (filename.empty() || (filename[0] == '.' && filename != ".")) { + return; + } + + // skip ignored + if (isIgnored(p, ignoreList)) { + return; + } + + if (boost::filesystem::is_directory(p)) { + + if (boost::filesystem::exists(p / "__init__.py")) { + + packagePaths.push_back(p.string()); + + } else if (checkSubDirs) { + + std::vector paths; + std::copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(paths)); + std::sort(paths.begin(), paths.end()); + for (std::vector::const_iterator it = paths.begin(); it != paths.end(); ++it) { + collectPackages(it->string(), ignoreList, false, packagePaths); + } + + } + } + + } else { + WriteMsg::write(CMSG_PATH_DOES_NOT_EXIST, fileOrDir.c_str()); + } + } catch (const boost::filesystem::filesystem_error& ex) { + WriteMsg::write(CMSG_FILESYSTEM_ERROR, ex.what()); + } +} + +static void collectFiles(const string& fileOrDir, const list& ignoreList, list& filePaths) { + try { + boost::filesystem::path p(fileOrDir); + + if (boost::filesystem::exists(p)) { + + // skip hidden files and directories + std::string filename = p.filename().string(); + if (filename.empty() || (filename[0] == '.' && filename != ".")) { + return; + } + + // skip ignored + if (isIgnored(p, ignoreList)) { + return; + } + + if (boost::filesystem::is_regular_file(p)) { + + if (p.extension().string() == ".py") { + filePaths.push_back(p.string()); + } + + } else if (boost::filesystem::is_directory(p)) { + + if (boost::filesystem::exists(p / "__init__.py")) { + + std::vector paths; + std::copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(paths)); + std::sort(paths.begin(), paths.end()); + for (std::vector::const_iterator it = paths.begin(); it != paths.end(); ++it) { + collectFiles(it->string(), ignoreList, filePaths); + } + + } + + } + + } else { + WriteMsg::write(CMSG_PATH_DOES_NOT_EXIST, fileOrDir.c_str()); + } + } catch (const boost::filesystem::filesystem_error& ex) { + WriteMsg::write(CMSG_FILESYSTEM_ERROR, ex.what()); + } +} + + +void collectPythonPackages(const string& projectBaseDir, const string& ignore, list& packagePaths) { + list ignoreList; + common::split(ignore, ignoreList, ','); + + string baseDir = (boost::filesystem::path(projectBaseDir) / ".").parent_path().string(); // remove trailing slash, if any + + collectPackages(baseDir, ignoreList, true, packagePaths); +} + +void collectPackageFiles(const string& projectBaseDir, const string& ignore, list& filePaths) { + list ignoreList; + common::split(ignore, ignoreList, ','); + + list packagePaths; + collectPythonPackages(projectBaseDir, ignore, packagePaths); + + for (list::const_iterator it = packagePaths.begin(); it != packagePaths.end(); ++it) { + collectFiles(*it, ignoreList, filePaths); + } +} + +}} diff --git a/lib/python/src/PythonException.cpp b/lib/python/src/PythonException.cpp new file mode 100644 index 0000000..32d975a --- /dev/null +++ b/lib/python/src/PythonException.cpp @@ -0,0 +1,78 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { + + /* ---------- Exception ---------- */ + + PythonException::PythonException(const std::string &location, const std::string &message) : columbus::Exception(location, message) { + } + + PythonException::~PythonException() { + } + + const std::string PythonException::getClassName() const { + return "python::PythonException"; + } + + + /* ---------- PythonInvalidIteratorException ---------- */ + + PythonInvalidIteratorException::PythonInvalidIteratorException(const std::string &location, const std::string &message) : PythonException(location, message) { + } + + PythonInvalidIteratorException::~PythonInvalidIteratorException() { + } + + const std::string PythonInvalidIteratorException::getClassName() const { + return "python::PythonInvalidIteratorException"; + } + + + /* ---------- PythonIllegalStateException ---------- */ + + PythonIllegalStateException::PythonIllegalStateException(const std::string &location, const std::string &message) : PythonException(location, message) { + } + + PythonIllegalStateException::~PythonIllegalStateException() { + } + + const std::string PythonIllegalStateException::getClassName() const { + return "python::PythonIllegalStateException"; + } + + + /* ---------- PythonNoSuchElementException ---------- */ + + PythonNoSuchElementException::PythonNoSuchElementException(const std::string &location, const std::string &message) : PythonException(location, message) { + } + + PythonNoSuchElementException::~PythonNoSuchElementException() { + } + + const std::string PythonNoSuchElementException::getClassName() const { + return "python::PythonNoSuchElementException"; + } + + +}}} diff --git a/lib/python/src/Range.cpp b/lib/python/src/Range.cpp new file mode 100644 index 0000000..b8bd0ee --- /dev/null +++ b/lib/python/src/Range.cpp @@ -0,0 +1,304 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "common/inc/StringSup.h" +#include "python/inc/messages.h" +#include + + +namespace columbus { namespace python { namespace asg { + + // ---------- Range ---------- + + static std::string emptyString; + + Range::Range() : strTable(NULL), positionInfo() { + memset(&positionInfo, 0, sizeof(PositionInfo)); + } + + Range::Range(StrTable &_strTable) : strTable(&_strTable), positionInfo() { + memset(&positionInfo, 0, sizeof(PositionInfo)); + } + + Range::Range(StrTable &_strTable, const std::string& pathString, unsigned line, unsigned col, unsigned endLine, unsigned endCol) : strTable(&_strTable), positionInfo() { + positionInfo.path = strTable->set(pathString); + setLine(line); + setCol(col); + setEndLine(endLine); + setEndCol(endCol); + }; + + const std::string& Range::getPath() const { + if (strTable) + return strTable->get(positionInfo.path); + else + return emptyString; + } + + Key Range::getPathKey() const { + return positionInfo.path; + } + + void Range::setPath(const std::string& s) { + if (!strTable) + throw PythonException(COLUMBUS_LOCATION,CMSG_EX_UNTIL_NO_STRTABLE_IS_SET_THE_SETPATH ); + positionInfo.path = strTable->set(s); + } + + unsigned Range::getLine() const { + return positionInfo.line; + } + + void Range::setLine(unsigned i) { + positionInfo.line = i; + } + + unsigned Range::getEndLine() const { + return positionInfo.endLine; + } + + void Range::setEndLine(unsigned i) { + positionInfo.endLine = i; + } + + unsigned Range::getCol() const { + return positionInfo.col; + } + + void Range::setCol(unsigned i) { + positionInfo.col = i; + } + + unsigned Range::getEndCol() const { + return positionInfo.endCol; + } + + void Range::setEndCol(unsigned i) { + positionInfo.endCol = i; + } + + Range::Range(StrTable &_strTable, Key pathKey, unsigned line, unsigned col, unsigned endLine, unsigned endCol) : strTable(&_strTable), positionInfo() { + positionInfo.path = pathKey; + setLine(line); + setCol(col); + setEndLine(endLine); + setEndCol(endCol); + }; + + Range::Range(StrTable &_strTable, PositionInfo _positionInfo) : strTable(&_strTable), positionInfo(_positionInfo) { + }; + + void Range::setPathKey(Key pathKey) { + positionInfo.path = pathKey; + }; + + + // ---------- RangeListIterator ---------- + + RangeListIterator:: RangeListIterator(Container *_container, IteratorContainer *itContainer) : + container(_container), + it(container->end()), + iterators(itContainer), + lastOp(op_None) + { + iterators->push_back(this); + } + + void RangeListIterator::add(const Range &r) { + switch (lastOp) { + case op_None: + it = container->begin(); + break; + case op_Next: + case op_Add: + ++it; + break; + case op_Invalidated: + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + case op_Previous: + case op_Remove: + break; + } + + it = container->insert(it, r); + + lastOp = op_Add; + } + + void RangeListIterator::remove() { + switch (lastOp) { + case op_None: + case op_Add: + case op_Remove: + throw PythonIllegalStateException(COLUMBUS_LOCATION, CMSG_EX_NEITHER_NEXT_NOR_PREVIOUS_HAVE_BEEN_CALLED); + case op_Next: + case op_Previous: + it = safeRemove(it); + break; + case op_Invalidated: + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + } + + lastOp = op_Remove; + } + + RangeListIterator::RangeListIterator() : + container(NULL), + it(), + iterators(NULL), + lastOp(op_Invalidated) + { + } + + RangeListIterator::RangeListIterator(const RangeListIterator &iterator) : + container(iterator.container), + it(iterator.it), + iterators(iterator.iterators), + lastOp(iterator.lastOp) + { + if (lastOp != op_Invalidated && iterators) + iterators->push_back(this); + } + + RangeListIterator::~RangeListIterator() { + if (lastOp != op_Invalidated) { + for (IteratorContainer::iterator _it = iterators->begin(); _it != iterators->end(); ++_it) { + if (*_it == this) { + iterators->erase(_it); + return; + } + } + } + } + + RangeListIterator& RangeListIterator::operator=(const RangeListIterator &otherIt) { + if (this == &otherIt) + return *this; + + if (otherIt.lastOp == op_Invalidated) + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + + bool insertIntoIterators = true; + if (lastOp != op_Invalidated && iterators) { + if (iterators == otherIt.iterators) { + insertIntoIterators = false; + } else { + for (IteratorContainer::iterator _it = iterators->begin(); _it != iterators->end(); ++_it) { + if (*_it == this) { + iterators->erase(_it); + break; + } + } + } + } + + container = otherIt.container; + it = otherIt.it; + iterators = otherIt.iterators; + lastOp = otherIt.lastOp; + + if (lastOp != op_Invalidated && iterators && insertIntoIterators) + iterators->push_back(this); + + return *this; + } + + bool RangeListIterator::hasNext() const { + return nextItem() != container->end(); + } + + const Range& RangeListIterator::next() { + it = nextItem(); + lastOp = op_Next; + + if (it == container->end()) + throw PythonNoSuchElementException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATION_HAS_NOT_NEXT_ELEMENT); + + return *it; + } + + bool RangeListIterator::hasPrevious() const { + return previousItem() != container->end(); + } + + const Range& RangeListIterator::previous() { + it = previousItem(); + lastOp = op_Previous; + + if (it == container->end()) + throw PythonNoSuchElementException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATION_HAS_NOT_PREVIOUS_ELEMENT); + + return *it; + } + + bool RangeListIterator::equals(const RangeListIterator& otherIt) const { + if (lastOp == op_Invalidated) + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + + return (it == otherIt.it) && (lastOp == otherIt.lastOp); + } + + RangeListIterator::Container::iterator RangeListIterator::nextItem() const { + switch (lastOp) { + case op_None: return container->begin(); + case op_Add: + case op_Next: return ++Container::iterator(it); + case op_Remove: + case op_Previous: return it; + case op_Invalidated: + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + } + return container->end(); + } + + RangeListIterator::Container::iterator RangeListIterator::previousItem() const { + switch (lastOp) { + case op_None: return container->end(); + case op_Add: + case op_Next: return it; + case op_Remove: + case op_Previous: return it == container->begin() ? container->end() : --Container::iterator(it); + case op_Invalidated: + throw PythonInvalidIteratorException(COLUMBUS_LOCATION, CMSG_EX_THE_ITERATOR_IS_INVALID); + } + return container->end(); + } + + RangeListIterator::Container::iterator RangeListIterator::safeRemove(const Container::iterator &_it) { + Container::iterator nextElement = _it; + ++nextElement; + + for (IteratorContainer::iterator icIt = iterators->begin(); icIt != iterators->end(); ++icIt) { + if (((*icIt)->it == _it) && (*icIt != this)) { + (*icIt)->it = nextElement; + (*icIt)->lastOp = op_Remove; + } + } + + return container->erase(_it); + } + + void RangeListIterator::invalidate() { + lastOp = op_Invalidated; + } + + +}}} diff --git a/lib/python/src/ReverseEdges.cpp b/lib/python/src/ReverseEdges.cpp new file mode 100644 index 0000000..0408df5 --- /dev/null +++ b/lib/python/src/ReverseEdges.cpp @@ -0,0 +1,279 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "common/inc/WriteMessage.h" +#include "python/inc/messages.h" +#include + + +namespace columbus { namespace python { namespace asg { +ReverseEdges::ReverseEdges(const Factory *factory, FuncPtrWithBaseParameterType selectorFunction) : fact(factory),selectorFunc(selectorFunction),reContainer() { + reContainer.resize(fact->size(), NULL); + AlgorithmPreorder ap; + ap.setSafeMode(); + ap.setVisitSpecialNodes(true, true); + VisitorReverseEdges visitor(this); + Factory::TurnFilterOffSafely tfos(*fact); + ap.run(*fact, visitor); +} + +ReverseEdges::~ReverseEdges() { + for (RevEdgesContainer::iterator it = reContainer.begin(); it != reContainer.end(); ++it) { + if (*it) { + delete *it; + *it = NULL; + } + } +} + +const ListIterator ReverseEdges::constIteratorBegin(NodeId id, EdgeKind edge) const { + if (reContainer.size() <= id || !reContainer[id]) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + + NodeEdgesType::const_iterator it = reContainer[id]->find(edge); + if (it != reContainer[id]->end()) { + return ListIterator((ListIterator::Container*)&(it->second), fact, true); + } else { + base::Base& node = fact->getRef(id); + if (possibleEdges[node.getNodeKind()][edge]) { + // creating an empty container and returning with it + NodeListType nodeList; + NodeEdgesType::const_iterator retIt = reContainer[id]->insert(std::make_pair(edge, nodeList)).first; + return ListIterator((ListIterator::Container*)&(retIt->second), fact, true); + } else { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_EDGE_KIND); + } + } +} + +const ListIterator ReverseEdges::constIteratorEnd(NodeId id, EdgeKind edge) const { + if (reContainer.size() <= id || !reContainer[id]) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + + NodeEdgesType::const_iterator it = reContainer[id]->find(edge); + if (it != reContainer[id]->end()) { + return ListIterator((ListIterator::Container*)&(it->second), fact, false); + } else { + base::Base& node = fact->getRef(id); + if (possibleEdges[node.getNodeKind()][edge]) { + // creating an empty container and returning with it + NodeListType nodeList; + NodeEdgesType::const_iterator retIt = reContainer[id]->insert(std::make_pair(edge, nodeList)).first; + return ListIterator((ListIterator::Container*)&(retIt->second), fact, false); + } else { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_EDGE_KIND); + } + } +} + +void ReverseEdges::getAllExistingEdges(NodeId id, std::vector& edges) const { + if (reContainer.size() <= id || !reContainer[id]) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + + edges.clear(); + for (NodeEdgesType::const_iterator it = reContainer[id]->begin(); it != reContainer[id]->end(); ++it) + edges.push_back(it->first); +} + +void ReverseEdges::getAllExistingEdges(NodeId id, std::set& edges) const { + if (reContainer.size() <= id || !reContainer[id]) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + + edges.clear(); + for (NodeEdgesType::const_iterator it = reContainer[id]->begin(); it != reContainer[id]->end(); ++it) + edges.insert(it->first); +} + +void ReverseEdges::getAllPossibleEdges(NodeKind kind, std::vector& edges) const { + edges.clear(); + for (int i = 0; i < 102; ++i) { + if (possibleEdges[kind][i]) { + edges.push_back(static_cast(i)); + } + } +} + +void ReverseEdges::getAllPossibleEdges(NodeKind kind, std::set& edges) const { + edges.clear(); + for (int i = 0; i < 102; ++i) { + if (possibleEdges[kind][i]) { + edges.insert(static_cast(i)); + } + } +} + +void ReverseEdges::insertNode(NodeId id) { + Factory::TurnFilterOffSafely turnFilterOffSafely(*fact); + if (!fact->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + if (selectorFunc) + if (!selectorFunc(fact->getPointer(id))) + return; + if (reContainer.size() <= id) + reContainer.resize(id + 1, NULL); + if (reContainer[id] == NULL) + reContainer[id] = new NodeEdgesType; +} + +void ReverseEdges::removeNode(NodeId id) { + // TODO + NodeEdgesType* pEdges = reContainer[id]; + if (pEdges == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_NO_REVERSE_EDGE_INFORMATION_FOR(id)); + base::Base* node = fact->getPointer(id); + for (NodeEdgesType::iterator it = pEdges->begin(); it != pEdges->end(); ++it) { + while (it->second.begin() != it->second.end()) { + common::WriteMsg::write(CMSG_REMOVE_FORWARD_EDGE_FORM,*it->second.begin(),id); + const_cast(fact->getPointer(*it->second.begin()))->removeEdge(it->first, node); + } + } + reContainer[id] = NULL; + delete pEdges; +} + +void ReverseEdges::insertEdge(NodeId from, NodeId to, EdgeKind edge) { + try { + if (selectorFunc) + if (!selectorFunc(fact->getPointer(from))) + return; + insertNode(from); + } + catch (PythonException) { + NodeId id = from; + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_ID(id)); + } + + NodeEdgesType::iterator it = reContainer[from]->find(edge); + if (it != reContainer[from]->end()) { + it->second.push_back(to); + } else { + NodeListType nodeList; + nodeList.push_back(to); + reContainer[from]->insert(std::make_pair(edge, nodeList)); + } +} + +void ReverseEdges::insertEdge(const base::Base* from, const base::Base* to, EdgeKind edge) { + if (selectorFunc) + if (!selectorFunc(from)) + return; + insertEdge(from->getId(), to->getId(), edge); +} + +void ReverseEdges::removeEdge(NodeId from, NodeId to, EdgeKind edge) { + if (reContainer.size() < from+1) + return; + if (reContainer[from] == NULL) + return; + NodeEdgesType::iterator itFind = reContainer[from]->find(edge); + if (itFind == reContainer[from]->end()) + return; + itFind->second.erase( find(itFind->second.begin(),itFind->second.end(), to)); +} + +bool ReverseEdges::possibleEdges[83][102] = { // nodes x edges + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,1,0,1,1,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} +}; + + +}}} diff --git a/lib/python/src/Types.cpp b/lib/python/src/Types.cpp new file mode 100644 index 0000000..36dab21 --- /dev/null +++ b/lib/python/src/Types.cpp @@ -0,0 +1,27 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { + + +}}} diff --git a/lib/python/src/algorithms/Algorithm.cpp b/lib/python/src/algorithms/Algorithm.cpp new file mode 100644 index 0000000..47ac593 --- /dev/null +++ b/lib/python/src/algorithms/Algorithm.cpp @@ -0,0 +1,33 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + +namespace columbus { namespace python { namespace asg { +void Algorithm::incVisitorDepth(Visitor& v) { + v.incDepth(); +} + +void Algorithm::decVisitorDepth(Visitor& v) { + v.decDepth(); +} + + +}}} diff --git a/lib/python/src/algorithms/AlgorithmPreorder.cpp b/lib/python/src/algorithms/AlgorithmPreorder.cpp new file mode 100644 index 0000000..e40ea74 --- /dev/null +++ b/lib/python/src/algorithms/AlgorithmPreorder.cpp @@ -0,0 +1,5861 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "common/inc/WriteMessage.h" +#include "python/inc/messages.h" +#include + +#ifdef DEBUG_PREORDER +#include +#endif + + +namespace columbus { namespace python { namespace asg { +AlgorithmPreorder::AlgorithmPreorder() + : Algorithm(), + safeMode(false), + visitedNodes(), + unvisitedNodes(), + visitCrossEdgeTree(false), + needPreorderStop(false), + visitSpecialNodes(true), + visitUsedSpecialNodesOnly(false), + visitFilteredEdge(false), + originalFilterState(false), + apRoot(NULL), + visitorList(false), + fact(NULL), + traversaldCrossEdges() +{ + memset(traversaldCrossEdges,false,sizeof(bool)*102); +} + +AlgorithmPreorder::~AlgorithmPreorder() { +} + +void AlgorithmPreorder::setSafeMode() { + safeMode = true; +} + +void AlgorithmPreorder::setUnsafeMode() { + safeMode = false; +} + +void AlgorithmPreorder::setVisitCrossEdgeTree(bool visit) { + visitCrossEdgeTree = visit; +} + +void AlgorithmPreorder::setVisitFilteredEdges(bool visit) { + visitFilteredEdge = visit; +} + +void AlgorithmPreorder::setVisitSpecialNodes(bool visit, bool usedOnly) { + visitSpecialNodes = visit; + visitUsedSpecialNodesOnly = visit && usedOnly; +} + +void AlgorithmPreorder::run() { + mainRun(NULL, NULL, NULL); +} + +void AlgorithmPreorder::run(const base::Base& node) { + mainRun(NULL, NULL, &node); +} + +void AlgorithmPreorder::run(const Factory& fact, Visitor& visitor) { + mainRun(&fact, &visitor, NULL); +} + +void AlgorithmPreorder::run(const Factory& fact, Visitor& visitor, const base::Base& node) { + mainRun(&fact, &visitor, &node); +} + +void AlgorithmPreorder::run(const Factory& fact, Visitor& visitor, NodeId nodeId) { + mainRun(&fact, &visitor, fact.getPointer(nodeId)); +} + +void AlgorithmPreorder::mainRun(const Factory* _fact, Visitor* visitor, const base::Base* node) { + if (_fact ) { + this->fact = const_cast(_fact); + } + if (visitor) { + this->visitorList.clear(); + this->visitorList.push_back(visitor); + } + this->apRoot = node; + + startPreorder(); + + if (apRoot) { + apRoot->accept(*this); + + if (!needPreorderStop && visitSpecialNodes && !visitUsedSpecialNodesOnly) { + Factory::ConstIterator it = fact->constIterator(); + while (it.hasNext()) { + const base::Base& b = it.next(); + if (!visitedNodes[b.getId()] && Common::getIsAPSpecNode(b)) { + b.accept(*this); + + if(needPreorderStop) + return; + } + } + } + + if (!needPreorderStop && (visitCrossEdgeTree || visitUsedSpecialNodesOnly)) { + bool wasNodeToTraversal = false; + size_t factSize = fact->size(); + do { + wasNodeToTraversal = false; + for (size_t i = 0; i < factSize; ++i) { + if (unvisitedNodes[i] && !visitedNodes[i]) { + fact->getPointer(i)->accept(*this); + wasNodeToTraversal = true; + unvisitedNodes[i] = false; + + if(needPreorderStop) + return; + } + } + } while (wasNodeToTraversal); + } + + } else { + size_t factSize = fact->size(); + for (size_t i = 0; i < factSize; ++i) { + if ((!fact->getIsFiltered(i)) && fact->isIndividual(i)){ + (fact->getPointer(i))->accept(*this); + + if(needPreorderStop) + return; + } + } + } + + endPreorder(); +} + +void AlgorithmPreorder::setFactory(Factory& _fact) { + fact = &_fact; +} + +void AlgorithmPreorder::addVisitor(Visitor& visitor) { + visitorList.push_back( &visitor); +} + +void AlgorithmPreorder::visitAllEdges(const base::Base& node, bool callFirst /*= true*/){ +} + +void AlgorithmPreorder::visitAllEdges(const base::Comment& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const base::Comment& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const base::Docstring& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const base::Docstring& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const base::Named& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visitAllEdges(const base::Positioned& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: comments + for (ListIterator it = node.getCommentsListIteratorBegin(); it != node.getCommentsListIteratorEnd(); ++it) { + const base::Comment& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPositioned_Comments(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkPositioned_Comments]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPositioned_Comments(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visitAllEdges(const expression::ArgumentList& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasPositionalArguments + genNodePtr = node.getPositionalArguments() ; + if (genNodePtr) { + const expression::ExpressionList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitArgumentList_HasPositionalArguments(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndArgumentList_HasPositionalArguments(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasDictionary + genNodePtr = node.getDictionary() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitArgumentList_HasDictionary(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndArgumentList_HasDictionary(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasKeyword + for (ListIterator it = node.getKeywordListIteratorBegin(); it != node.getKeywordListIteratorEnd(); ++it) { + const expression::Keyword& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitArgumentList_HasKeyword(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndArgumentList_HasKeyword(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTuple + genNodePtr = node.getTuple() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitArgumentList_HasTuple(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndArgumentList_HasTuple(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::ArgumentList& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::AttributeRef& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::AttributeRef& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Binary& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasLeftExpression + genNodePtr = node.getLeftExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitBinary_HasLeftExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndBinary_HasLeftExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasRightExpression + genNodePtr = node.getRightExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitBinary_HasRightExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndBinary_HasRightExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visitAllEdges(const expression::BinaryArithmetic& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::BinaryArithmetic& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::BinaryLogical& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::BinaryLogical& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Call& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasArgumentList + genNodePtr = node.getArgumentList() ; + if (genNodePtr) { + const expression::ArgumentList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitCall_HasArgumentList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndCall_HasArgumentList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const statement::CompoundStatement& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitCall_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkCall_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndCall_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Call& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::DictComp& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasKeyValue + genNodePtr = node.getKeyValue() ; + if (genNodePtr) { + const expression::KeyValue& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitDictComp_HasKeyValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndDictComp_HasKeyValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasGenerator + for (ListIterator it = node.getGeneratorListIteratorBegin(); it != node.getGeneratorListIteratorEnd(); ++it) { + const expression::Generator& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitDictComp_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndDictComp_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::DictComp& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Dictionary& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasKeyValue + for (ListIterator it = node.getKeyValueListIteratorBegin(); it != node.getKeyValueListIteratorEnd(); ++it) { + const expression::KeyValue& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitDictionary_HasKeyValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndDictionary_HasKeyValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Dictionary& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Ellipsis& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::Ellipsis& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Expression& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasType + genNodePtr = node.getType() ; + if (genNodePtr) { + const type::Type& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExpression_HasType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkExpression_HasType]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExpression_HasType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visitAllEdges(const expression::ExpressionList& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasExpression + for (ListIterator it = node.getExpressionListIteratorBegin(); it != node.getExpressionListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExpressionList_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExpressionList_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::ExpressionList& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::ExtSlice& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasItem + for (ListIterator it = node.getItemListIteratorBegin(); it != node.getItemListIteratorEnd(); ++it) { + const expression::Slicing& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExtSlice_HasItem(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExtSlice_HasItem(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::ExtSlice& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::FloatNumber& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::FloatNumber& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Generator& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasCondition + for (ListIterator it = node.getConditionListIteratorBegin(); it != node.getConditionListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitGenerator_HasCondition(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndGenerator_HasCondition(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + const base::Base* genNodePtr; + // edge: hasIter + genNodePtr = node.getIter() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitGenerator_HasIter(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndGenerator_HasIter(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTarget + genNodePtr = node.getTarget() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitGenerator_HasTarget(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndGenerator_HasTarget(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Generator& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::GeneratorExpression& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitGeneratorExpression_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndGeneratorExpression_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasGenerator + for (ListIterator it = node.getGeneratorListIteratorBegin(); it != node.getGeneratorListIteratorEnd(); ++it) { + const expression::Generator& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitGeneratorExpression_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndGeneratorExpression_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::GeneratorExpression& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Identifier& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const module::Object& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIdentifier_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkIdentifier_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIdentifier_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Identifier& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::IfExpression& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasBody + genNodePtr = node.getBody() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIfExpression_HasBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIfExpression_HasBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasElseBody + genNodePtr = node.getElseBody() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIfExpression_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIfExpression_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTest + genNodePtr = node.getTest() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIfExpression_HasTest(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIfExpression_HasTest(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::IfExpression& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::ImagNumber& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::ImagNumber& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Index& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::Index& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::IntegerLiteral& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::IntegerLiteral& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::KeyValue& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasKey + genNodePtr = node.getKey() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitKeyValue_HasKey(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndKeyValue_HasKey(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasValue + genNodePtr = node.getValue() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitKeyValue_HasValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndKeyValue_HasValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::KeyValue& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Keyword& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasKey + genNodePtr = node.getKey() ; + if (genNodePtr) { + const expression::Identifier& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitKeyword_HasKey(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndKeyword_HasKey(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasValue + genNodePtr = node.getValue() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitKeyword_HasValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndKeyword_HasValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Keyword& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Lambda& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasObject + for (ListIterator it = node.getObjectListIteratorBegin(); it != node.getObjectListIteratorEnd(); ++it) { + const module::Object& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitLambda_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndLambda_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasParameter + for (ListIterator it = node.getParameterListIteratorBegin(); it != node.getParameterListIteratorEnd(); ++it) { + const statement::Parameter& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitLambda_HasParameter(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndLambda_HasParameter(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitLambda_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndLambda_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Lambda& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::List& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasExpression + for (ListIterator it = node.getExpressionListIteratorBegin(); it != node.getExpressionListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitList_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndList_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::List& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::ListComp& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitListComp_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndListComp_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasGenerator + for (ListIterator it = node.getGeneratorListIteratorBegin(); it != node.getGeneratorListIteratorEnd(); ++it) { + const expression::Generator& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitListComp_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndListComp_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::ListComp& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Literal& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visitAllEdges(const expression::LongInteger& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::LongInteger& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Set& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasExpression + for (ListIterator it = node.getExpressionListIteratorBegin(); it != node.getExpressionListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSet_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSet_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Set& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::SetComp& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSetComp_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSetComp_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasGenerator + for (ListIterator it = node.getGeneratorListIteratorBegin(); it != node.getGeneratorListIteratorEnd(); ++it) { + const expression::Generator& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSetComp_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSetComp_HasGenerator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::SetComp& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Slice& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasLowerBound + genNodePtr = node.getLowerBound() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSlice_HasLowerBound(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSlice_HasLowerBound(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasStride + genNodePtr = node.getStride() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSlice_HasStride(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSlice_HasStride(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasUpperBound + genNodePtr = node.getUpperBound() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSlice_HasUpperBound(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSlice_HasUpperBound(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Slice& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Slicing& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visitAllEdges(const expression::StringConversion& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpressionList + genNodePtr = node.getExpressionList() ; + if (genNodePtr) { + const expression::ExpressionList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitStringConversion_HasExpressionList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndStringConversion_HasExpressionList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::StringConversion& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::StringLiteral& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::StringLiteral& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Subscription& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasSlicing + genNodePtr = node.getSlicing() ; + if (genNodePtr) { + const expression::Slicing& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSubscription_HasSlicing(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSubscription_HasSlicing(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::Subscription& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::Unary& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitUnary_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndUnary_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visitAllEdges(const expression::UnaryOperation& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const expression::UnaryOperation& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const expression::YieldExpression& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasYieldExpression + genNodePtr = node.getYieldExpression() ; + if (genNodePtr) { + const expression::ExpressionList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitYieldExpression_HasYieldExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndYieldExpression_HasYieldExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const expression::YieldExpression& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const module::Module& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasObject + for (ListIterator it = node.getObjectListIteratorBegin(); it != node.getObjectListIteratorEnd(); ++it) { + const module::Object& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitModule_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndModule_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasStatement + for (ListIterator it = node.getStatementListIteratorBegin(); it != node.getStatementListIteratorEnd(); ++it) { + const base::Positioned& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitModule_HasStatement(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndModule_HasStatement(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + const base::Base* genNodePtr; + // edge: docstring + genNodePtr = node.getDocstring() ; + if (genNodePtr) { + const base::Docstring& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitModule_Docstring(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkModule_Docstring]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndModule_Docstring(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const module::Module& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const module::Object& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: refersTo + for (ListIterator it = node.getRefersToListIteratorBegin(); it != node.getRefersToListIteratorEnd(); ++it) { + const base::Positioned& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitObject_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkObject_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndObject_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasType + for (ListIterator it = node.getTypeListIteratorBegin(); it != node.getTypeListIteratorEnd(); ++it) { + const type::Type& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitObject_HasType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkObject_HasType]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndObject_HasType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const module::Object& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const module::Package& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasModule + for (ListIterator it = node.getModuleListIteratorBegin(); it != node.getModuleListIteratorEnd(); ++it) { + const module::Module& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPackage_HasModule(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPackage_HasModule(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasPackage + for (ListIterator it = node.getPackageListIteratorBegin(); it != node.getPackageListIteratorEnd(); ++it) { + const module::Package& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPackage_HasPackage(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPackage_HasPackage(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const module::Package& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Alias& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const base::Base& endNodeRef = *genNodePtr; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitAlias_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkAlias_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndAlias_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Alias& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Assert& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasMsgExpression + genNodePtr = node.getMsgExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitAssert_HasMsgExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndAssert_HasMsgExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTestExpression + genNodePtr = node.getTestExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitAssert_HasTestExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndAssert_HasTestExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Assert& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Assign& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitAssign_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndAssign_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTargetList + genNodePtr = node.getTargetList() ; + if (genNodePtr) { + const statement::TargetList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitAssign_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndAssign_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Assign& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::AugAssign& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const statement::AugAssign& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::BaseSpecifier& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasName + genNodePtr = node.getName() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitBaseSpecifier_HasName(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndBaseSpecifier_HasName(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: derivesFrom + genNodePtr = node.getDerivesFrom() ; + if (genNodePtr) { + const statement::ClassDef& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitBaseSpecifier_DerivesFrom(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkBaseSpecifier_DerivesFrom]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndBaseSpecifier_DerivesFrom(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::BaseSpecifier& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Break& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const statement::Break& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::ClassDef& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasObject + for (ListIterator it = node.getObjectListIteratorBegin(); it != node.getObjectListIteratorEnd(); ++it) { + const module::Object& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitClassDef_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndClassDef_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasBaseSpecifier + for (ListIterator it = node.getBaseSpecifierListIteratorBegin(); it != node.getBaseSpecifierListIteratorEnd(); ++it) { + const statement::BaseSpecifier& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitClassDef_HasBaseSpecifier(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndClassDef_HasBaseSpecifier(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasDecorator + for (ListIterator it = node.getDecoratorListIteratorBegin(); it != node.getDecoratorListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitClassDef_HasDecorator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndClassDef_HasDecorator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + const base::Base* genNodePtr; + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const module::Object& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitClassDef_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkClassDef_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndClassDef_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: docstring + genNodePtr = node.getDocstring() ; + if (genNodePtr) { + const base::Docstring& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitClassDef_Docstring(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkClassDef_Docstring]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndClassDef_Docstring(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::ClassDef& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::CompoundStatement& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasBody + genNodePtr = node.getBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitCompoundStatement_HasBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndCompoundStatement_HasBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visitAllEdges(const statement::Continue& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const statement::Continue& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Delete& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasTargetList + genNodePtr = node.getTargetList() ; + if (genNodePtr) { + const statement::TargetList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitDelete_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndDelete_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Delete& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Exec& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExec_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExec_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasGlobals + genNodePtr = node.getGlobals() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExec_HasGlobals(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExec_HasGlobals(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasLocals + genNodePtr = node.getLocals() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitExec_HasLocals(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndExec_HasLocals(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Exec& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::For& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpressionList + genNodePtr = node.getExpressionList() ; + if (genNodePtr) { + const expression::ExpressionList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFor_HasExpressionList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFor_HasExpressionList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTargetList + genNodePtr = node.getTargetList() ; + if (genNodePtr) { + const statement::TargetList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFor_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFor_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::For& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::FunctionDef& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasDecorator + for (ListIterator it = node.getDecoratorListIteratorBegin(); it != node.getDecoratorListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFunctionDef_HasDecorator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFunctionDef_HasDecorator(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasObject + for (ListIterator it = node.getObjectListIteratorBegin(); it != node.getObjectListIteratorEnd(); ++it) { + const module::Object& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFunctionDef_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFunctionDef_HasObject(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasParameter + for (ListIterator it = node.getParameterListIteratorBegin(); it != node.getParameterListIteratorEnd(); ++it) { + const statement::Parameter& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFunctionDef_HasParameter(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFunctionDef_HasParameter(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + const base::Base* genNodePtr; + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const module::Object& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFunctionDef_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkFunctionDef_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFunctionDef_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: returnType + genNodePtr = node.getReturnType() ; + if (genNodePtr) { + const type::Type& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFunctionDef_ReturnType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkFunctionDef_ReturnType]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFunctionDef_ReturnType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: docstring + genNodePtr = node.getDocstring() ; + if (genNodePtr) { + const base::Docstring& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitFunctionDef_Docstring(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkFunctionDef_Docstring]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndFunctionDef_Docstring(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::FunctionDef& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Global& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasIdentifier + for (ListIterator it = node.getIdentifierListIteratorBegin(); it != node.getIdentifierListIteratorEnd(); ++it) { + const expression::Identifier& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitGlobal_HasIdentifier(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndGlobal_HasIdentifier(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Global& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Handler& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasName + genNodePtr = node.getName() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitHandler_HasName(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndHandler_HasName(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasExceptBody + genNodePtr = node.getExceptBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitHandler_HasExceptBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndHandler_HasExceptBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasType + genNodePtr = node.getType() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitHandler_HasType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndHandler_HasType(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Handler& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::If& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasElseBody + genNodePtr = node.getElseBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIf_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIf_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTestExpression + genNodePtr = node.getTestExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIf_HasTestExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIf_HasTestExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::If& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::ImportFrom& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const statement::ImportFrom& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::ImportStatement& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasAlias + for (ListIterator it = node.getAliasListIteratorBegin(); it != node.getAliasListIteratorEnd(); ++it) { + const statement::Alias& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitImportStatement_HasAlias(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndImportStatement_HasAlias(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::ImportStatement& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Iteration& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasElseBody + genNodePtr = node.getElseBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitIteration_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndIteration_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visitAllEdges(const statement::Parameter& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasDefaultValue + genNodePtr = node.getDefaultValue() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitParameter_HasDefaultValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndParameter_HasDefaultValue(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const module::Object& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitParameter_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkParameter_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndParameter_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Parameter& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Pass& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const statement::Pass& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Print& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpressionList + genNodePtr = node.getExpressionList() ; + if (genNodePtr) { + const expression::ExpressionList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPrint_HasExpressionList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPrint_HasExpressionList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasDestination + genNodePtr = node.getDestination() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitPrint_HasDestination(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndPrint_HasDestination(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Print& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Raise& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasTracebackExpression + genNodePtr = node.getTracebackExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitRaise_HasTracebackExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndRaise_HasTracebackExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTypeExpression + genNodePtr = node.getTypeExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitRaise_HasTypeExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndRaise_HasTypeExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasValueExpression + genNodePtr = node.getValueExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitRaise_HasValueExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndRaise_HasValueExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Raise& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Return& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitReturn_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndReturn_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Return& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::SimpleStatement& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Statement& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Suite& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasStatement + for (ListIterator it = node.getStatementListIteratorBegin(); it != node.getStatementListIteratorEnd(); ++it) { + const base::Positioned& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitSuite_HasStatement(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndSuite_HasStatement(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::Suite& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::TargetList& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + // edge: hasTarget + for (ListIterator it = node.getTargetListIteratorBegin(); it != node.getTargetListIteratorEnd(); ++it) { + const expression::Expression& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitTargetList_HasTarget(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndTargetList_HasTarget(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::TargetList& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::Try& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visitAllEdges(const statement::TryExcept& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasElseBody + genNodePtr = node.getElseBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitTryExcept_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndTryExcept_HasElseBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasHandler + for (ListIterator it = node.getHandlerListIteratorBegin(); it != node.getHandlerListIteratorEnd(); ++it) { + const statement::Handler& endNodeRef = *it; + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitTryExcept_HasHandler(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndTryExcept_HasHandler(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasFinallyBody + genNodePtr = node.getFinallyBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitTryExcept_HasFinallyBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndTryExcept_HasFinallyBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::TryExcept& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::TryFinal& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasFinallyBody + genNodePtr = node.getFinallyBody() ; + if (genNodePtr) { + const statement::Suite& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitTryFinal_HasFinallyBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndTryFinal_HasFinallyBody(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::TryFinal& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::While& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasTestExpression + genNodePtr = node.getTestExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitWhile_HasTestExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndWhile_HasTestExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::While& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const statement::With& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: hasExpression + genNodePtr = node.getExpression() ; + if (genNodePtr) { + const expression::Expression& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitWith_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndWith_HasExpression(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } + + // edge: hasTargetList + genNodePtr = node.getTargetList() ; + if (genNodePtr) { + const statement::TargetList& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitWith_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot && visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef)) { + unvisitedNodes[endNodeRef.getId()] = true; + } else { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndWith_HasTargetList(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const statement::With& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const type::DictType& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const type::DictType& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const type::ReferenceType& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); + + std::list::iterator itVisitors; + + const base::Base* genNodePtr; + // edge: refersTo + genNodePtr = node.getRefersTo() ; + if (genNodePtr) { + const base::Positioned& endNodeRef = dynamic_cast(*genNodePtr); + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitReferenceType_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + if ((!fact->getIsFilterTurnedOn() && !visitFilteredEdge) || (fact->getFilterState(endNodeRef.getId()) == Filter::NotFiltered) || (!originalFilterState && visitFilteredEdge)) { + if (apRoot) { + if (visitCrossEdgeTree || (visitUsedSpecialNodesOnly && Common::getIsAPSpecNode(endNodeRef))) { + unvisitedNodes[endNodeRef.getId()] = true; + } + } + if (traversaldCrossEdges[edkReferenceType_RefersTo]) { + endNodeRef.accept(*this); + } + } + for (itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visitEndReferenceType_RefersTo(node, endNodeRef); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + } +} + +void AlgorithmPreorder::visit(const type::ReferenceType& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const type::SequenceType& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const type::SequenceType& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const type::SimpleType& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::visit(const type::SimpleType& node, bool callFirst /*= true*/){ +#ifdef DEBUG_PREORDER + std::cout << "Rec. run: " << (unsigned int)&node << " " << node.getId() << " " << Common::toString(node.getNodeKind()) << std::endl; +#endif + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + if (safeMode) { + if (visitedNodes[node.getId()]) { // for safemode + common::WriteMsg::write(CMSG_THE_PRE_ORDER_HAS_TOUCHED_A_NODE_TWICE,node.getId(),Common::toString(node.getNodeKind()).c_str() ); + return; + } + } + visitedNodes[node.getId()] = true; + } + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->visit(node); + incVisitorDepth((**itVisitors)); + } + + clearStoppedVisitors(); + if(needPreorderStop) + return; + + visitAllEdges(node,true); + + for (std::list::iterator itVisitors = visitorList.begin();itVisitors != visitorList.end(); ++itVisitors) { + decVisitorDepth(**itVisitors); + (*itVisitors)->visitEnd(node); + } + + clearStoppedVisitors(); +} + +void AlgorithmPreorder::visitAllEdges(const type::Type& node, bool callFirst /*= true*/){ + visitAllEdges(dynamic_cast(node),false); +} + +void AlgorithmPreorder::startPreorder(){ + + if (!fact){ + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_YOU_MUST_GIVE_A_FACTORY_AT_FIRST); + } + + if (visitorList.empty()){ + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_DON_T_HAVE_ANY_VISITOR); + } + + if (safeMode || visitCrossEdgeTree || visitSpecialNodes) { + visitedNodes.clear(); + visitedNodes.resize(fact->size(), false); + } + + if (visitCrossEdgeTree || visitSpecialNodes) { + unvisitedNodes.clear(); + unvisitedNodes.resize(fact->size(), false); + } + + if (visitFilteredEdge){ + originalFilterState = fact->getIsFilterTurnedOn(); + fact->turnFilterOff(); + } + + for (std::list::iterator itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->beginVisit(); + } + +} + +void AlgorithmPreorder::endPreorder(){ + + for (std::list::iterator itVisitors = visitorList.begin(); itVisitors != visitorList.end(); ++itVisitors) { + (*itVisitors)->finishVisit(); + } + + if (visitFilteredEdge){ + if (originalFilterState) + fact->turnFilterOn(); + } + +} + +void AlgorithmPreorder::setCrossEdgeToTraversal(EdgeKind edgekind){ + + traversaldCrossEdges[edgekind] = true;} + +void AlgorithmPreorder::stop(Visitor* visitor){ + stoppeds.insert(visitor);} + +void AlgorithmPreorder::clearStoppedVisitors(){ + if(stoppeds.empty()){ + return; + } + + std::set::iterator iter = stoppeds.begin(); + std::set::iterator iter_end = stoppeds.end(); + + for(; iter != iter_end; ++iter){ + visitorList.remove(*iter); + } + + stoppeds.clear(); + needPreorderStop = visitorList.empty(); +} +}}} diff --git a/lib/python/src/base/Base.cpp b/lib/python/src/base/Base.cpp new file mode 100644 index 0000000..43457e4 --- /dev/null +++ b/lib/python/src/base/Base.cpp @@ -0,0 +1,167 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace base { + Base::Base(NodeId _id, Factory *_factory) : + + hashOk(false), + m_id(_id), + m_originKind(orkAnalyzer), + nodeHashCache(0), + parentEdgeKind((EdgeKind)0), + parent(0), + factory(_factory) + { + } + + Base::~Base() { + } + + void Base::prepareDelete(bool tryOnVirtualParent){ + } + + void Base::setParentEdge(const base::Base *childNode,EdgeKind _parentEdgeKind) const { + if (childNode) { + if (childNode->parent != 0) { + common::WriteMsg::write(CMSG_HAS_ALREADY_PARENT_THE_PARENT_WAS,childNode->getId(),Common::toString(childNode->getNodeKind()).c_str(),childNode->parent,Common::toString(childNode->getParent()->getNodeKind()).c_str() ,this->getId(),Common::toString(this->getNodeKind()).c_str()); + } + childNode->parent = m_id; + childNode->parentEdgeKind = _parentEdgeKind; + } + } + + void Base::removeParentEdge(NodeId childNode) const { + factory->getRef(childNode).parent = 0; + } + + void Base::removeParentEdge(base::Base *childNode) const { + childNode->parent = 0; + } + + base::Base* Base::getParent() const { + if (parent == 0) + return NULL; + return factory->getPointer(parent); + } + + Factory& Base::getFactory() const { + return *factory; + } + NodeId Base::getId() const { + return m_id; + } + + OriginKind Base::getOriginKind() const { + return m_originKind; + } + + void Base::setId(NodeId _id) { + m_id = _id; + } + + void Base::setOriginKind(OriginKind _originKind) { + m_originKind = _originKind; + } + + bool Base::setEdge(EdgeKind edgeKind, base::Base* edgeEnd) { + return setEdge(edgeKind, edgeEnd->getId(), true); + } + + bool Base::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + return false; + } + + bool Base::removeEdge(EdgeKind edgeKind, base::Base* edgeEnd) { + return removeEdge(edgeKind, edgeEnd->getId(), true); + } + + bool Base::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + return false; + } + + void Base::accept(Visitor &visitor) const { + } + + void Base::acceptEnd(Visitor &visitor) const { + } + + double Base::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Base& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getOriginKind() == getOriginKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Base::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Base::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "base::Base", strlen("base::Base")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Base::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + binIo.writeUInt4(m_id); + binIo.writeUShort2(getNodeKind()); + binIo.writeUByte1(m_originKind); + + } + + void Base::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + m_originKind = (OriginKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/base/Comment.cpp b/lib/python/src/base/Comment.cpp new file mode 100644 index 0000000..7c600ea --- /dev/null +++ b/lib/python/src/base/Comment.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace base { + Comment::Comment(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_text(0) + { + } + + Comment::~Comment() { + } + + void Comment::prepareDelete(bool tryOnVirtualParent){ + base::Positioned::prepareDelete(false); + } + + NodeKind Comment::getNodeKind() const { + return ndkComment; + } + + Key Comment::getTextKey() const { + return m_text; + } + + const std::string& Comment::getText() const { + return factory->getStringTable().get(m_text); + } + + void Comment::setTextKey(Key _text) { + m_text = _text; + } + + void Comment::setText(const std::string& _text) { + m_text = factory->getStringTable().set(_text); + } + + bool Comment::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Comment::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Comment::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Comment::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Comment::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Comment& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getText(); + str2 = node.getText(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Comment::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_text); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_text = foundKeyId->second; + } else { + Key oldkey = m_text; + m_text = newStrTable.set(factory->getStringTable().get(m_text)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_text)); } + + } + + NodeHashType Comment::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "base::Comment", strlen("base::Comment")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Comment::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + factory->getStringTable().setType(m_text, StrTable::strToSave); + binIo.writeUInt4(m_text); + + } + + void Comment::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_text = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/base/Docstring.cpp b/lib/python/src/base/Docstring.cpp new file mode 100644 index 0000000..6c47abb --- /dev/null +++ b/lib/python/src/base/Docstring.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace base { + Docstring::Docstring(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_text(0) + { + } + + Docstring::~Docstring() { + } + + void Docstring::prepareDelete(bool tryOnVirtualParent){ + base::Positioned::prepareDelete(false); + } + + NodeKind Docstring::getNodeKind() const { + return ndkDocstring; + } + + Key Docstring::getTextKey() const { + return m_text; + } + + const std::string& Docstring::getText() const { + return factory->getStringTable().get(m_text); + } + + void Docstring::setTextKey(Key _text) { + m_text = _text; + } + + void Docstring::setText(const std::string& _text) { + m_text = factory->getStringTable().set(_text); + } + + bool Docstring::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Docstring::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Docstring::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Docstring::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Docstring::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Docstring& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getText(); + str2 = node.getText(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Docstring::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_text); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_text = foundKeyId->second; + } else { + Key oldkey = m_text; + m_text = newStrTable.set(factory->getStringTable().get(m_text)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_text)); } + + } + + NodeHashType Docstring::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "base::Docstring", strlen("base::Docstring")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Docstring::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + factory->getStringTable().setType(m_text, StrTable::strToSave); + binIo.writeUInt4(m_text); + + } + + void Docstring::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_text = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/base/Named.cpp b/lib/python/src/base/Named.cpp new file mode 100644 index 0000000..30f186e --- /dev/null +++ b/lib/python/src/base/Named.cpp @@ -0,0 +1,147 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace base { + Named::Named(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_name(0) + { + } + + Named::~Named() { + } + + void Named::prepareDelete(bool tryOnVirtualParent){ + base::Positioned::prepareDelete(false); + } + + Key Named::getNameKey() const { + return m_name; + } + + const std::string& Named::getName() const { + return factory->getStringTable().get(m_name); + } + + void Named::setNameKey(Key _name) { + m_name = _name; + } + + void Named::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + bool Named::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Named::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double Named::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Named& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Named::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType Named::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "base::Named", strlen("base::Named")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Named::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + + } + + void Named::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_name = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/base/Positioned.cpp b/lib/python/src/base/Positioned.cpp new file mode 100644 index 0000000..f7725a6 --- /dev/null +++ b/lib/python/src/base/Positioned.cpp @@ -0,0 +1,254 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace base { + Positioned::Positioned(NodeId _id, Factory *_factory) : + Base(_id, _factory), + m_position(), + commentsContainer() + { + m_position.posInfo.path = 0; + m_position.posInfo.line = 0; + m_position.posInfo.col = 0; + m_position.posInfo.endLine = 0; + m_position.posInfo.endCol = 0; + } + + Positioned::~Positioned() { + } + + void Positioned::prepareDelete(bool tryOnVirtualParent){ + while (!commentsContainer.empty()) { + const NodeId id = *commentsContainer.begin(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkPositioned_Comments); + commentsContainer.pop_front(); + } + base::Base::prepareDelete(false); + } + + const Range Positioned::getPosition() const { + return Range(factory->getStringTable(), m_position.posInfo); + } + + int Positioned::compareByPosition(const Positioned& other) const { + if (m_position.posInfo.path != other.m_position.posInfo.path) { + return (m_position.posInfo.path < other.m_position.posInfo.path) ? -1 :1 ; + }; + if (m_position.posInfo.line != other.m_position.posInfo.line) { + return (m_position.posInfo.line < other.m_position.posInfo.line) ? -1 :1 ; + }; + if (m_position.posInfo.col != other.m_position.posInfo.col) { + return (m_position.posInfo.col < other.m_position.posInfo.col) ? -1 :1 ; + }; + if (m_position.posInfo.endLine != other.m_position.posInfo.endLine) { + return (m_position.posInfo.endLine > other.m_position.posInfo.endLine) ? -1 :1 ; + }; + if (m_position.posInfo.endCol != other.m_position.posInfo.endCol) { + return (m_position.posInfo.endCol > other.m_position.posInfo.endCol) ? -1 :1 ; + }; + if (getNodeKind() != other.getNodeKind()) { + return (getNodeKind() < other.getNodeKind()) ? -1 :1 ; + }; + return 0; + } + + void Positioned::setPosition(const Range& _position) { + m_position.posInfo = _position.positionInfo; + if (_position.strTable != &factory->getStringTable()) + m_position.posInfo.path = factory->getStringTable().set(_position.getPath()); + } + + ListIterator Positioned::getCommentsListIteratorBegin() const { + return ListIterator(&commentsContainer, factory, true); + } + + ListIterator Positioned::getCommentsListIteratorEnd() const { + return ListIterator(&commentsContainer, factory, false); + } + + bool Positioned::getCommentsIsEmpty() const { + return getCommentsListIteratorBegin() == getCommentsListIteratorEnd(); + } + + unsigned int Positioned::getCommentsSize() const { + unsigned int size = 0; + ListIterator endIt = getCommentsListIteratorEnd(); + for (ListIterator it = getCommentsListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Positioned::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPositioned_Comments: + addComments(edgeEnd); + return true; + default: + break; + } + if (base::Base::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Positioned::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPositioned_Comments: + removeComments(edgeEnd); + return true; + default: + break; + } + if (base::Base::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Positioned::addComments(const base::Comment *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkComment) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + commentsContainer.push_back(_node->getId()); + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkPositioned_Comments); + } + + void Positioned::addComments(NodeId _id) { + const base::Comment *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addComments( node ); + } + + void Positioned::removeComments(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(commentsContainer.begin(), commentsContainer.end(), id); + + if (it == commentsContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + commentsContainer.erase(it); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkPositioned_Comments); + } + + void Positioned::removeComments(base::Comment *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeComments(_node->getId()); + } + + double Positioned::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Positioned::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Positioned::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "base::Positioned", strlen("base::Positioned")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Positioned::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Base::save(binIo,false); + + factory->getStringTable().setType(m_position.posInfo.path, StrTable::strToSave); + binIo.writeUInt4(m_position.posInfo.path); + binIo.writeUInt4(m_position.posInfo.line); + binIo.writeUInt4(m_position.posInfo.col); + binIo.writeUInt4(m_position.posInfo.endLine); + binIo.writeUInt4(m_position.posInfo.endCol); + + + for (ListIterator::Container::const_iterator it = commentsContainer.begin(); it != commentsContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Positioned::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Base::load(binIo,false); + + m_position.posInfo.path = binIo.readUInt4(); + m_position.posInfo.line = binIo.readUInt4(); + m_position.posInfo.col = binIo.readUInt4(); + m_position.posInfo.endLine = binIo.readUInt4(); + m_position.posInfo.endCol = binIo.readUInt4(); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + commentsContainer.push_back(_id); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/ArgumentList.cpp b/lib/python/src/expression/ArgumentList.cpp new file mode 100644 index 0000000..f939eea --- /dev/null +++ b/lib/python/src/expression/ArgumentList.cpp @@ -0,0 +1,429 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ArgumentList::ArgumentList(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_hasPositionalArguments(0), + m_hasDictionary(0), + hasKeywordContainer(), + m_hasTuple(0) + { + } + + ArgumentList::~ArgumentList() { + } + + void ArgumentList::prepareDelete(bool tryOnVirtualParent){ + removePositionalArguments(); + removeDictionary(); + while (!hasKeywordContainer.empty()) { + const NodeId id = *hasKeywordContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkArgumentList_HasKeyword); + hasKeywordContainer.pop_front(); + } + removeTuple(); + base::Positioned::prepareDelete(false); + } + + NodeKind ArgumentList::getNodeKind() const { + return ndkArgumentList; + } + + expression::ExpressionList* ArgumentList::getPositionalArguments() const { + expression::ExpressionList *_node = NULL; + if (m_hasPositionalArguments != 0) + _node = dynamic_cast(factory->getPointer(m_hasPositionalArguments)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* ArgumentList::getDictionary() const { + expression::Expression *_node = NULL; + if (m_hasDictionary != 0) + _node = dynamic_cast(factory->getPointer(m_hasDictionary)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + ListIterator ArgumentList::getKeywordListIteratorBegin() const { + return ListIterator(&hasKeywordContainer, factory, true); + } + + ListIterator ArgumentList::getKeywordListIteratorEnd() const { + return ListIterator(&hasKeywordContainer, factory, false); + } + + bool ArgumentList::getKeywordIsEmpty() const { + return getKeywordListIteratorBegin() == getKeywordListIteratorEnd(); + } + + unsigned int ArgumentList::getKeywordSize() const { + unsigned int size = 0; + ListIterator endIt = getKeywordListIteratorEnd(); + for (ListIterator it = getKeywordListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + expression::Expression* ArgumentList::getTuple() const { + expression::Expression *_node = NULL; + if (m_hasTuple != 0) + _node = dynamic_cast(factory->getPointer(m_hasTuple)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool ArgumentList::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkArgumentList_HasPositionalArguments: + setPositionalArguments(edgeEnd); + return true; + case edkArgumentList_HasDictionary: + setDictionary(edgeEnd); + return true; + case edkArgumentList_HasKeyword: + addKeyword(edgeEnd); + return true; + case edkArgumentList_HasTuple: + setTuple(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ArgumentList::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkArgumentList_HasPositionalArguments: + removePositionalArguments(); + return true; + case edkArgumentList_HasDictionary: + removeDictionary(); + return true; + case edkArgumentList_HasKeyword: + removeKeyword(edgeEnd); + return true; + case edkArgumentList_HasTuple: + removeTuple(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ArgumentList::setPositionalArguments(NodeId _id) { + expression::ExpressionList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasPositionalArguments) { + removeParentEdge(m_hasPositionalArguments); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasPositionalArguments, m_id, edkArgumentList_HasPositionalArguments); + } + m_hasPositionalArguments = _node->getId(); + if (m_hasPositionalArguments != 0) + setParentEdge(factory->getPointer(m_hasPositionalArguments), edkArgumentList_HasPositionalArguments); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasPositionalArguments, this->getId(), edkArgumentList_HasPositionalArguments); + } else { + if (m_hasPositionalArguments) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ArgumentList::setPositionalArguments(expression::ExpressionList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setPositionalArguments(_node->getId()); + } + + void ArgumentList::removePositionalArguments() { + if (m_hasPositionalArguments) { + removeParentEdge(m_hasPositionalArguments); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasPositionalArguments, m_id, edkArgumentList_HasPositionalArguments); + } + m_hasPositionalArguments = 0; + } + + void ArgumentList::setDictionary(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasDictionary) { + removeParentEdge(m_hasDictionary); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasDictionary, m_id, edkArgumentList_HasDictionary); + } + m_hasDictionary = _node->getId(); + if (m_hasDictionary != 0) + setParentEdge(factory->getPointer(m_hasDictionary), edkArgumentList_HasDictionary); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasDictionary, this->getId(), edkArgumentList_HasDictionary); + } else { + if (m_hasDictionary) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ArgumentList::setDictionary(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDictionary(_node->getId()); + } + + void ArgumentList::removeDictionary() { + if (m_hasDictionary) { + removeParentEdge(m_hasDictionary); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasDictionary, m_id, edkArgumentList_HasDictionary); + } + m_hasDictionary = 0; + } + + void ArgumentList::addKeyword(const expression::Keyword *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkKeyword) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasKeywordContainer.push_back(_node->getId()); + setParentEdge(_node,edkArgumentList_HasKeyword); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkArgumentList_HasKeyword); + } + + void ArgumentList::addKeyword(NodeId _id) { + const expression::Keyword *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addKeyword( node ); + } + + void ArgumentList::removeKeyword(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasKeywordContainer.begin(), hasKeywordContainer.end(), id); + + if (it == hasKeywordContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasKeywordContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkArgumentList_HasKeyword); + } + + void ArgumentList::removeKeyword(expression::Keyword *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeKeyword(_node->getId()); + } + + void ArgumentList::setTuple(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTuple) { + removeParentEdge(m_hasTuple); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTuple, m_id, edkArgumentList_HasTuple); + } + m_hasTuple = _node->getId(); + if (m_hasTuple != 0) + setParentEdge(factory->getPointer(m_hasTuple), edkArgumentList_HasTuple); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTuple, this->getId(), edkArgumentList_HasTuple); + } else { + if (m_hasTuple) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ArgumentList::setTuple(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTuple(_node->getId()); + } + + void ArgumentList::removeTuple() { + if (m_hasTuple) { + removeParentEdge(m_hasTuple); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTuple, m_id, edkArgumentList_HasTuple); + } + m_hasTuple = 0; + } + + void ArgumentList::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ArgumentList::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ArgumentList::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void ArgumentList::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ArgumentList::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ArgumentList", strlen("expression::ArgumentList")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ArgumentList::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + binIo.writeUInt4(m_hasPositionalArguments); + binIo.writeUInt4(m_hasDictionary); + binIo.writeUInt4(m_hasTuple); + + + for (ListIterator::Container::const_iterator it = hasKeywordContainer.begin(); it != hasKeywordContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void ArgumentList::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_hasPositionalArguments = binIo.readUInt4(); + if (m_hasPositionalArguments != 0) + setParentEdge(factory->getPointer(m_hasPositionalArguments),edkArgumentList_HasPositionalArguments); + + m_hasDictionary = binIo.readUInt4(); + if (m_hasDictionary != 0) + setParentEdge(factory->getPointer(m_hasDictionary),edkArgumentList_HasDictionary); + + m_hasTuple = binIo.readUInt4(); + if (m_hasTuple != 0) + setParentEdge(factory->getPointer(m_hasTuple),edkArgumentList_HasTuple); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasKeywordContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkArgumentList_HasKeyword); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/AttributeRef.cpp b/lib/python/src/expression/AttributeRef.cpp new file mode 100644 index 0000000..901d6ba --- /dev/null +++ b/lib/python/src/expression/AttributeRef.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + AttributeRef::AttributeRef(NodeId _id, Factory *_factory) : + Binary(_id, _factory) + { + } + + AttributeRef::~AttributeRef() { + } + + void AttributeRef::prepareDelete(bool tryOnVirtualParent){ + expression::Binary::prepareDelete(false); + } + + NodeKind AttributeRef::getNodeKind() const { + return ndkAttributeRef; + } + + bool AttributeRef::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Binary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool AttributeRef::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Binary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void AttributeRef::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void AttributeRef::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double AttributeRef::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void AttributeRef::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType AttributeRef::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::AttributeRef", strlen("expression::AttributeRef")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void AttributeRef::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Binary::save(binIo,false); + + } + + void AttributeRef::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Binary::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Binary.cpp b/lib/python/src/expression/Binary.cpp new file mode 100644 index 0000000..bc9bfb1 --- /dev/null +++ b/lib/python/src/expression/Binary.cpp @@ -0,0 +1,252 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Binary::Binary(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasLeftExpression(0), + m_hasRightExpression(0) + { + } + + Binary::~Binary() { + } + + void Binary::prepareDelete(bool tryOnVirtualParent){ + removeLeftExpression(); + removeRightExpression(); + expression::Expression::prepareDelete(false); + } + + expression::Expression* Binary::getLeftExpression() const { + expression::Expression *_node = NULL; + if (m_hasLeftExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasLeftExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Binary::getRightExpression() const { + expression::Expression *_node = NULL; + if (m_hasRightExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasRightExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Binary::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkBinary_HasLeftExpression: + setLeftExpression(edgeEnd); + return true; + case edkBinary_HasRightExpression: + setRightExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Binary::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkBinary_HasLeftExpression: + removeLeftExpression(); + return true; + case edkBinary_HasRightExpression: + removeRightExpression(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Binary::setLeftExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasLeftExpression) { + removeParentEdge(m_hasLeftExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLeftExpression, m_id, edkBinary_HasLeftExpression); + } + m_hasLeftExpression = _node->getId(); + if (m_hasLeftExpression != 0) + setParentEdge(factory->getPointer(m_hasLeftExpression), edkBinary_HasLeftExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasLeftExpression, this->getId(), edkBinary_HasLeftExpression); + } else { + if (m_hasLeftExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Binary::setLeftExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setLeftExpression(_node->getId()); + } + + void Binary::removeLeftExpression() { + if (m_hasLeftExpression) { + removeParentEdge(m_hasLeftExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLeftExpression, m_id, edkBinary_HasLeftExpression); + } + m_hasLeftExpression = 0; + } + + void Binary::setRightExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasRightExpression) { + removeParentEdge(m_hasRightExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasRightExpression, m_id, edkBinary_HasRightExpression); + } + m_hasRightExpression = _node->getId(); + if (m_hasRightExpression != 0) + setParentEdge(factory->getPointer(m_hasRightExpression), edkBinary_HasRightExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasRightExpression, this->getId(), edkBinary_HasRightExpression); + } else { + if (m_hasRightExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Binary::setRightExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRightExpression(_node->getId()); + } + + void Binary::removeRightExpression() { + if (m_hasRightExpression) { + removeParentEdge(m_hasRightExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasRightExpression, m_id, edkBinary_HasRightExpression); + } + m_hasRightExpression = 0; + } + + double Binary::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Binary::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Binary::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Binary", strlen("expression::Binary")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Binary::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasLeftExpression); + binIo.writeUInt4(m_hasRightExpression); + + } + + void Binary::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasLeftExpression = binIo.readUInt4(); + if (m_hasLeftExpression != 0) + setParentEdge(factory->getPointer(m_hasLeftExpression),edkBinary_HasLeftExpression); + + m_hasRightExpression = binIo.readUInt4(); + if (m_hasRightExpression != 0) + setParentEdge(factory->getPointer(m_hasRightExpression),edkBinary_HasRightExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/BinaryArithmetic.cpp b/lib/python/src/expression/BinaryArithmetic.cpp new file mode 100644 index 0000000..4375135 --- /dev/null +++ b/lib/python/src/expression/BinaryArithmetic.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + BinaryArithmetic::BinaryArithmetic(NodeId _id, Factory *_factory) : + Binary(_id, _factory), + m_kind(bakMultiplication) + { + } + + BinaryArithmetic::~BinaryArithmetic() { + } + + void BinaryArithmetic::prepareDelete(bool tryOnVirtualParent){ + expression::Binary::prepareDelete(false); + } + + NodeKind BinaryArithmetic::getNodeKind() const { + return ndkBinaryArithmetic; + } + + BinaryArithmeticKind BinaryArithmetic::getKind() const { + return m_kind; + } + + void BinaryArithmetic::setKind(BinaryArithmeticKind _kind) { + m_kind = _kind; + } + + bool BinaryArithmetic::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Binary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool BinaryArithmetic::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Binary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void BinaryArithmetic::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void BinaryArithmetic::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double BinaryArithmetic::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const BinaryArithmetic& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void BinaryArithmetic::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType BinaryArithmetic::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::BinaryArithmetic", strlen("expression::BinaryArithmetic")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void BinaryArithmetic::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Binary::save(binIo,false); + + binIo.writeUByte1(m_kind); + + } + + void BinaryArithmetic::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Binary::load(binIo,false); + + m_kind = (BinaryArithmeticKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/BinaryLogical.cpp b/lib/python/src/expression/BinaryLogical.cpp new file mode 100644 index 0000000..c5e4152 --- /dev/null +++ b/lib/python/src/expression/BinaryLogical.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + BinaryLogical::BinaryLogical(NodeId _id, Factory *_factory) : + Binary(_id, _factory), + m_kind(blkEq) + { + } + + BinaryLogical::~BinaryLogical() { + } + + void BinaryLogical::prepareDelete(bool tryOnVirtualParent){ + expression::Binary::prepareDelete(false); + } + + NodeKind BinaryLogical::getNodeKind() const { + return ndkBinaryLogical; + } + + BinaryLogicalKind BinaryLogical::getKind() const { + return m_kind; + } + + void BinaryLogical::setKind(BinaryLogicalKind _kind) { + m_kind = _kind; + } + + bool BinaryLogical::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Binary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool BinaryLogical::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Binary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void BinaryLogical::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void BinaryLogical::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double BinaryLogical::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const BinaryLogical& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void BinaryLogical::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType BinaryLogical::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::BinaryLogical", strlen("expression::BinaryLogical")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void BinaryLogical::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Binary::save(binIo,false); + + binIo.writeUByte1(m_kind); + + } + + void BinaryLogical::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Binary::load(binIo,false); + + m_kind = (BinaryLogicalKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Call.cpp b/lib/python/src/expression/Call.cpp new file mode 100644 index 0000000..2438bea --- /dev/null +++ b/lib/python/src/expression/Call.cpp @@ -0,0 +1,262 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Call::Call(NodeId _id, Factory *_factory) : + Unary(_id, _factory), + m_hasArgumentList(0), + m_refersTo(0) + { + } + + Call::~Call() { + } + + void Call::prepareDelete(bool tryOnVirtualParent){ + removeArgumentList(); + removeRefersTo(); + expression::Unary::prepareDelete(false); + } + + NodeKind Call::getNodeKind() const { + return ndkCall; + } + + expression::ArgumentList* Call::getArgumentList() const { + expression::ArgumentList *_node = NULL; + if (m_hasArgumentList != 0) + _node = dynamic_cast(factory->getPointer(m_hasArgumentList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + statement::CompoundStatement* Call::getRefersTo() const { + statement::CompoundStatement *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Call::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkCall_HasArgumentList: + setArgumentList(edgeEnd); + return true; + case edkCall_RefersTo: + setRefersTo(edgeEnd); + return true; + default: + break; + } + if (expression::Unary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Call::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkCall_HasArgumentList: + removeArgumentList(); + return true; + case edkCall_RefersTo: + removeRefersTo(); + return true; + default: + break; + } + if (expression::Unary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Call::setArgumentList(NodeId _id) { + expression::ArgumentList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasArgumentList) { + removeParentEdge(m_hasArgumentList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasArgumentList, m_id, edkCall_HasArgumentList); + } + m_hasArgumentList = _node->getId(); + if (m_hasArgumentList != 0) + setParentEdge(factory->getPointer(m_hasArgumentList), edkCall_HasArgumentList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasArgumentList, this->getId(), edkCall_HasArgumentList); + } else { + if (m_hasArgumentList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Call::setArgumentList(expression::ArgumentList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setArgumentList(_node->getId()); + } + + void Call::removeArgumentList() { + if (m_hasArgumentList) { + removeParentEdge(m_hasArgumentList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasArgumentList, m_id, edkCall_HasArgumentList); + } + m_hasArgumentList = 0; + } + + void Call::setRefersTo(NodeId _id) { + statement::CompoundStatement *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (_node->getNodeKind() == ndkFunctionDef || _node->getNodeKind() == ndkClassDef) { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkCall_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkCall_RefersTo); + } else { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Call::setRefersTo(statement::CompoundStatement *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void Call::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkCall_RefersTo); + } + m_refersTo = 0; + } + + void Call::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Call::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Call::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Call::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Call::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Call", strlen("expression::Call")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Call::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Unary::save(binIo,false); + + binIo.writeUInt4(m_hasArgumentList); + binIo.writeUInt4(m_refersTo); + + } + + void Call::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Unary::load(binIo,false); + + m_hasArgumentList = binIo.readUInt4(); + if (m_hasArgumentList != 0) + setParentEdge(factory->getPointer(m_hasArgumentList),edkCall_HasArgumentList); + + m_refersTo = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/DictComp.cpp b/lib/python/src/expression/DictComp.cpp new file mode 100644 index 0000000..f46d88e --- /dev/null +++ b/lib/python/src/expression/DictComp.cpp @@ -0,0 +1,291 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + DictComp::DictComp(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasKeyValue(0), + hasGeneratorContainer() + { + } + + DictComp::~DictComp() { + } + + void DictComp::prepareDelete(bool tryOnVirtualParent){ + removeKeyValue(); + while (!hasGeneratorContainer.empty()) { + const NodeId id = *hasGeneratorContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkDictComp_HasGenerator); + hasGeneratorContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind DictComp::getNodeKind() const { + return ndkDictComp; + } + + expression::KeyValue* DictComp::getKeyValue() const { + expression::KeyValue *_node = NULL; + if (m_hasKeyValue != 0) + _node = dynamic_cast(factory->getPointer(m_hasKeyValue)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + ListIterator DictComp::getGeneratorListIteratorBegin() const { + return ListIterator(&hasGeneratorContainer, factory, true); + } + + ListIterator DictComp::getGeneratorListIteratorEnd() const { + return ListIterator(&hasGeneratorContainer, factory, false); + } + + bool DictComp::getGeneratorIsEmpty() const { + return getGeneratorListIteratorBegin() == getGeneratorListIteratorEnd(); + } + + unsigned int DictComp::getGeneratorSize() const { + unsigned int size = 0; + ListIterator endIt = getGeneratorListIteratorEnd(); + for (ListIterator it = getGeneratorListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool DictComp::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkDictComp_HasKeyValue: + setKeyValue(edgeEnd); + return true; + case edkDictComp_HasGenerator: + addGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool DictComp::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkDictComp_HasKeyValue: + removeKeyValue(); + return true; + case edkDictComp_HasGenerator: + removeGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void DictComp::setKeyValue(NodeId _id) { + expression::KeyValue *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasKeyValue) { + removeParentEdge(m_hasKeyValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKeyValue, m_id, edkDictComp_HasKeyValue); + } + m_hasKeyValue = _node->getId(); + if (m_hasKeyValue != 0) + setParentEdge(factory->getPointer(m_hasKeyValue), edkDictComp_HasKeyValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasKeyValue, this->getId(), edkDictComp_HasKeyValue); + } else { + if (m_hasKeyValue) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void DictComp::setKeyValue(expression::KeyValue *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setKeyValue(_node->getId()); + } + + void DictComp::removeKeyValue() { + if (m_hasKeyValue) { + removeParentEdge(m_hasKeyValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKeyValue, m_id, edkDictComp_HasKeyValue); + } + m_hasKeyValue = 0; + } + + void DictComp::addGenerator(const expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkGenerator) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasGeneratorContainer.push_back(_node->getId()); + setParentEdge(_node,edkDictComp_HasGenerator); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkDictComp_HasGenerator); + } + + void DictComp::addGenerator(NodeId _id) { + const expression::Generator *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addGenerator( node ); + } + + void DictComp::removeGenerator(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasGeneratorContainer.begin(), hasGeneratorContainer.end(), id); + + if (it == hasGeneratorContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasGeneratorContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkDictComp_HasGenerator); + } + + void DictComp::removeGenerator(expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeGenerator(_node->getId()); + } + + void DictComp::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void DictComp::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double DictComp::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void DictComp::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType DictComp::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::DictComp", strlen("expression::DictComp")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void DictComp::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasKeyValue); + + + for (ListIterator::Container::const_iterator it = hasGeneratorContainer.begin(); it != hasGeneratorContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void DictComp::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasKeyValue = binIo.readUInt4(); + if (m_hasKeyValue != 0) + setParentEdge(factory->getPointer(m_hasKeyValue),edkDictComp_HasKeyValue); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasGeneratorContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkDictComp_HasGenerator); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/Dictionary.cpp b/lib/python/src/expression/Dictionary.cpp new file mode 100644 index 0000000..26c8090 --- /dev/null +++ b/lib/python/src/expression/Dictionary.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Dictionary::Dictionary(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + hasKeyValueContainer() + { + } + + Dictionary::~Dictionary() { + } + + void Dictionary::prepareDelete(bool tryOnVirtualParent){ + while (!hasKeyValueContainer.empty()) { + const NodeId id = *hasKeyValueContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkDictionary_HasKeyValue); + hasKeyValueContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind Dictionary::getNodeKind() const { + return ndkDictionary; + } + + ListIterator Dictionary::getKeyValueListIteratorBegin() const { + return ListIterator(&hasKeyValueContainer, factory, true); + } + + ListIterator Dictionary::getKeyValueListIteratorEnd() const { + return ListIterator(&hasKeyValueContainer, factory, false); + } + + bool Dictionary::getKeyValueIsEmpty() const { + return getKeyValueListIteratorBegin() == getKeyValueListIteratorEnd(); + } + + unsigned int Dictionary::getKeyValueSize() const { + unsigned int size = 0; + ListIterator endIt = getKeyValueListIteratorEnd(); + for (ListIterator it = getKeyValueListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Dictionary::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkDictionary_HasKeyValue: + addKeyValue(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Dictionary::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkDictionary_HasKeyValue: + removeKeyValue(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Dictionary::addKeyValue(const expression::KeyValue *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkKeyValue) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasKeyValueContainer.push_back(_node->getId()); + setParentEdge(_node,edkDictionary_HasKeyValue); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkDictionary_HasKeyValue); + } + + void Dictionary::addKeyValue(NodeId _id) { + const expression::KeyValue *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addKeyValue( node ); + } + + void Dictionary::removeKeyValue(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasKeyValueContainer.begin(), hasKeyValueContainer.end(), id); + + if (it == hasKeyValueContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasKeyValueContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkDictionary_HasKeyValue); + } + + void Dictionary::removeKeyValue(expression::KeyValue *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeKeyValue(_node->getId()); + } + + void Dictionary::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Dictionary::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Dictionary::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Dictionary::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Dictionary::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Dictionary", strlen("expression::Dictionary")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Dictionary::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasKeyValueContainer.begin(); it != hasKeyValueContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Dictionary::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasKeyValueContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkDictionary_HasKeyValue); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/Ellipsis.cpp b/lib/python/src/expression/Ellipsis.cpp new file mode 100644 index 0000000..6fc399d --- /dev/null +++ b/lib/python/src/expression/Ellipsis.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Ellipsis::Ellipsis(NodeId _id, Factory *_factory) : + Slicing(_id, _factory) + { + } + + Ellipsis::~Ellipsis() { + } + + void Ellipsis::prepareDelete(bool tryOnVirtualParent){ + expression::Slicing::prepareDelete(false); + } + + NodeKind Ellipsis::getNodeKind() const { + return ndkEllipsis; + } + + bool Ellipsis::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Slicing::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Ellipsis::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Slicing::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Ellipsis::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Ellipsis::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Ellipsis::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Ellipsis::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Ellipsis::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Ellipsis", strlen("expression::Ellipsis")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Ellipsis::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Slicing::save(binIo,false); + + } + + void Ellipsis::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Slicing::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Expression.cpp b/lib/python/src/expression/Expression.cpp new file mode 100644 index 0000000..90c6354 --- /dev/null +++ b/lib/python/src/expression/Expression.cpp @@ -0,0 +1,177 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Expression::Expression(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_hasType(0) + { + } + + Expression::~Expression() { + } + + void Expression::prepareDelete(bool tryOnVirtualParent){ + removeType(); + base::Positioned::prepareDelete(false); + } + + type::Type* Expression::getType() const { + type::Type *_node = NULL; + if (m_hasType != 0) + _node = dynamic_cast(factory->getPointer(m_hasType)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Expression::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExpression_HasType: + setType(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Expression::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExpression_HasType: + removeType(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Expression::setType(NodeId _id) { + type::Type *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasType) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasType, m_id, edkExpression_HasType); + } + m_hasType = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasType, this->getId(), edkExpression_HasType); + } else { + if (m_hasType) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Expression::setType(type::Type *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setType(_node->getId()); + } + + void Expression::removeType() { + if (m_hasType) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasType, m_id, edkExpression_HasType); + } + m_hasType = 0; + } + + double Expression::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Expression::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Expression::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Expression", strlen("expression::Expression")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Expression::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + binIo.writeUInt4(m_hasType); + + } + + void Expression::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_hasType = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/ExpressionList.cpp b/lib/python/src/expression/ExpressionList.cpp new file mode 100644 index 0000000..e00396b --- /dev/null +++ b/lib/python/src/expression/ExpressionList.cpp @@ -0,0 +1,243 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ExpressionList::ExpressionList(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_isYieldExpression(false), + hasExpressionContainer() + { + } + + ExpressionList::~ExpressionList() { + } + + void ExpressionList::prepareDelete(bool tryOnVirtualParent){ + while (!hasExpressionContainer.empty()) { + const NodeId id = *hasExpressionContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkExpressionList_HasExpression); + hasExpressionContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind ExpressionList::getNodeKind() const { + return ndkExpressionList; + } + + bool ExpressionList::getIsYieldExpression() const { + return m_isYieldExpression; + } + + void ExpressionList::setIsYieldExpression(bool _isYieldExpression) { + m_isYieldExpression = _isYieldExpression; + } + + ListIterator ExpressionList::getExpressionListIteratorBegin() const { + return ListIterator(&hasExpressionContainer, factory, true); + } + + ListIterator ExpressionList::getExpressionListIteratorEnd() const { + return ListIterator(&hasExpressionContainer, factory, false); + } + + bool ExpressionList::getExpressionIsEmpty() const { + return getExpressionListIteratorBegin() == getExpressionListIteratorEnd(); + } + + unsigned int ExpressionList::getExpressionSize() const { + unsigned int size = 0; + ListIterator endIt = getExpressionListIteratorEnd(); + for (ListIterator it = getExpressionListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool ExpressionList::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExpressionList_HasExpression: + addExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ExpressionList::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExpressionList_HasExpression: + removeExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ExpressionList::addExpression(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasExpressionContainer.push_back(_node->getId()); + setParentEdge(_node,edkExpressionList_HasExpression); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkExpressionList_HasExpression); + } + + void ExpressionList::addExpression(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addExpression( node ); + } + + void ExpressionList::removeExpression(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasExpressionContainer.begin(), hasExpressionContainer.end(), id); + + if (it == hasExpressionContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasExpressionContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkExpressionList_HasExpression); + } + + void ExpressionList::removeExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeExpression(_node->getId()); + } + + void ExpressionList::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ExpressionList::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ExpressionList::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const ExpressionList& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getIsYieldExpression() == getIsYieldExpression()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void ExpressionList::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ExpressionList::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ExpressionList", strlen("expression::ExpressionList")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ExpressionList::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + unsigned char boolValues = 0; + boolValues <<= 1; + if (m_isYieldExpression) + boolValues |= 1; + binIo.writeUByte1(boolValues); + + + for (ListIterator::Container::const_iterator it = hasExpressionContainer.begin(); it != hasExpressionContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void ExpressionList::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + unsigned char boolValues = binIo.readUByte1(); + m_isYieldExpression = boolValues & 1; + boolValues >>= 1; + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasExpressionContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkExpressionList_HasExpression); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/ExtSlice.cpp b/lib/python/src/expression/ExtSlice.cpp new file mode 100644 index 0000000..7d7cd4c --- /dev/null +++ b/lib/python/src/expression/ExtSlice.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ExtSlice::ExtSlice(NodeId _id, Factory *_factory) : + Slicing(_id, _factory), + hasItemContainer() + { + } + + ExtSlice::~ExtSlice() { + } + + void ExtSlice::prepareDelete(bool tryOnVirtualParent){ + while (!hasItemContainer.empty()) { + const NodeId id = *hasItemContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkExtSlice_HasItem); + hasItemContainer.pop_front(); + } + expression::Slicing::prepareDelete(false); + } + + NodeKind ExtSlice::getNodeKind() const { + return ndkExtSlice; + } + + ListIterator ExtSlice::getItemListIteratorBegin() const { + return ListIterator(&hasItemContainer, factory, true); + } + + ListIterator ExtSlice::getItemListIteratorEnd() const { + return ListIterator(&hasItemContainer, factory, false); + } + + bool ExtSlice::getItemIsEmpty() const { + return getItemListIteratorBegin() == getItemListIteratorEnd(); + } + + unsigned int ExtSlice::getItemSize() const { + unsigned int size = 0; + ListIterator endIt = getItemListIteratorEnd(); + for (ListIterator it = getItemListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool ExtSlice::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExtSlice_HasItem: + addItem(edgeEnd); + return true; + default: + break; + } + if (expression::Slicing::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ExtSlice::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExtSlice_HasItem: + removeItem(edgeEnd); + return true; + default: + break; + } + if (expression::Slicing::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ExtSlice::addItem(const expression::Slicing *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsSlicing(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasItemContainer.push_back(_node->getId()); + setParentEdge(_node,edkExtSlice_HasItem); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkExtSlice_HasItem); + } + + void ExtSlice::addItem(NodeId _id) { + const expression::Slicing *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addItem( node ); + } + + void ExtSlice::removeItem(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasItemContainer.begin(), hasItemContainer.end(), id); + + if (it == hasItemContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasItemContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkExtSlice_HasItem); + } + + void ExtSlice::removeItem(expression::Slicing *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeItem(_node->getId()); + } + + void ExtSlice::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ExtSlice::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ExtSlice::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void ExtSlice::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ExtSlice::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ExtSlice", strlen("expression::ExtSlice")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ExtSlice::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Slicing::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasItemContainer.begin(); it != hasItemContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void ExtSlice::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Slicing::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasItemContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkExtSlice_HasItem); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/FloatNumber.cpp b/lib/python/src/expression/FloatNumber.cpp new file mode 100644 index 0000000..510f66c --- /dev/null +++ b/lib/python/src/expression/FloatNumber.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + FloatNumber::FloatNumber(NodeId _id, Factory *_factory) : + Literal(_id, _factory), + m_value(0.0) + { + } + + FloatNumber::~FloatNumber() { + } + + void FloatNumber::prepareDelete(bool tryOnVirtualParent){ + expression::Literal::prepareDelete(false); + } + + NodeKind FloatNumber::getNodeKind() const { + return ndkFloatNumber; + } + + double FloatNumber::getValue() const { + return m_value; + } + + void FloatNumber::setValue(double _value) { + m_value = _value; + } + + bool FloatNumber::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool FloatNumber::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void FloatNumber::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void FloatNumber::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double FloatNumber::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const FloatNumber& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getValue() == getValue()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void FloatNumber::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType FloatNumber::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::FloatNumber", strlen("expression::FloatNumber")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void FloatNumber::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Literal::save(binIo,false); + + binIo.writeDouble8(m_value); + + } + + void FloatNumber::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Literal::load(binIo,false); + + m_value = binIo.readDouble8(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Generator.cpp b/lib/python/src/expression/Generator.cpp new file mode 100644 index 0000000..11d2e42 --- /dev/null +++ b/lib/python/src/expression/Generator.cpp @@ -0,0 +1,360 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Generator::Generator(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + hasConditionContainer(), + m_hasIter(0), + m_hasTarget(0) + { + } + + Generator::~Generator() { + } + + void Generator::prepareDelete(bool tryOnVirtualParent){ + while (!hasConditionContainer.empty()) { + const NodeId id = *hasConditionContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkGenerator_HasCondition); + hasConditionContainer.pop_front(); + } + removeIter(); + removeTarget(); + base::Positioned::prepareDelete(false); + } + + NodeKind Generator::getNodeKind() const { + return ndkGenerator; + } + + ListIterator Generator::getConditionListIteratorBegin() const { + return ListIterator(&hasConditionContainer, factory, true); + } + + ListIterator Generator::getConditionListIteratorEnd() const { + return ListIterator(&hasConditionContainer, factory, false); + } + + bool Generator::getConditionIsEmpty() const { + return getConditionListIteratorBegin() == getConditionListIteratorEnd(); + } + + unsigned int Generator::getConditionSize() const { + unsigned int size = 0; + ListIterator endIt = getConditionListIteratorEnd(); + for (ListIterator it = getConditionListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + expression::Expression* Generator::getIter() const { + expression::Expression *_node = NULL; + if (m_hasIter != 0) + _node = dynamic_cast(factory->getPointer(m_hasIter)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Generator::getTarget() const { + expression::Expression *_node = NULL; + if (m_hasTarget != 0) + _node = dynamic_cast(factory->getPointer(m_hasTarget)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Generator::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkGenerator_HasCondition: + addCondition(edgeEnd); + return true; + case edkGenerator_HasIter: + setIter(edgeEnd); + return true; + case edkGenerator_HasTarget: + setTarget(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Generator::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkGenerator_HasCondition: + removeCondition(edgeEnd); + return true; + case edkGenerator_HasIter: + removeIter(); + return true; + case edkGenerator_HasTarget: + removeTarget(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Generator::addCondition(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasConditionContainer.push_back(_node->getId()); + setParentEdge(_node,edkGenerator_HasCondition); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkGenerator_HasCondition); + } + + void Generator::addCondition(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addCondition( node ); + } + + void Generator::removeCondition(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasConditionContainer.begin(), hasConditionContainer.end(), id); + + if (it == hasConditionContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasConditionContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkGenerator_HasCondition); + } + + void Generator::removeCondition(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeCondition(_node->getId()); + } + + void Generator::setIter(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasIter) { + removeParentEdge(m_hasIter); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasIter, m_id, edkGenerator_HasIter); + } + m_hasIter = _node->getId(); + if (m_hasIter != 0) + setParentEdge(factory->getPointer(m_hasIter), edkGenerator_HasIter); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasIter, this->getId(), edkGenerator_HasIter); + } else { + if (m_hasIter) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Generator::setIter(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setIter(_node->getId()); + } + + void Generator::removeIter() { + if (m_hasIter) { + removeParentEdge(m_hasIter); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasIter, m_id, edkGenerator_HasIter); + } + m_hasIter = 0; + } + + void Generator::setTarget(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTarget) { + removeParentEdge(m_hasTarget); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTarget, m_id, edkGenerator_HasTarget); + } + m_hasTarget = _node->getId(); + if (m_hasTarget != 0) + setParentEdge(factory->getPointer(m_hasTarget), edkGenerator_HasTarget); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTarget, this->getId(), edkGenerator_HasTarget); + } else { + if (m_hasTarget) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Generator::setTarget(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTarget(_node->getId()); + } + + void Generator::removeTarget() { + if (m_hasTarget) { + removeParentEdge(m_hasTarget); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTarget, m_id, edkGenerator_HasTarget); + } + m_hasTarget = 0; + } + + void Generator::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Generator::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Generator::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Generator::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Generator::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Generator", strlen("expression::Generator")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Generator::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + binIo.writeUInt4(m_hasIter); + binIo.writeUInt4(m_hasTarget); + + + for (ListIterator::Container::const_iterator it = hasConditionContainer.begin(); it != hasConditionContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Generator::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_hasIter = binIo.readUInt4(); + if (m_hasIter != 0) + setParentEdge(factory->getPointer(m_hasIter),edkGenerator_HasIter); + + m_hasTarget = binIo.readUInt4(); + if (m_hasTarget != 0) + setParentEdge(factory->getPointer(m_hasTarget),edkGenerator_HasTarget); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasConditionContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkGenerator_HasCondition); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/GeneratorExpression.cpp b/lib/python/src/expression/GeneratorExpression.cpp new file mode 100644 index 0000000..7d3a377 --- /dev/null +++ b/lib/python/src/expression/GeneratorExpression.cpp @@ -0,0 +1,291 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + GeneratorExpression::GeneratorExpression(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasExpression(0), + hasGeneratorContainer() + { + } + + GeneratorExpression::~GeneratorExpression() { + } + + void GeneratorExpression::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + while (!hasGeneratorContainer.empty()) { + const NodeId id = *hasGeneratorContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkGeneratorExpression_HasGenerator); + hasGeneratorContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind GeneratorExpression::getNodeKind() const { + return ndkGeneratorExpression; + } + + expression::Expression* GeneratorExpression::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + ListIterator GeneratorExpression::getGeneratorListIteratorBegin() const { + return ListIterator(&hasGeneratorContainer, factory, true); + } + + ListIterator GeneratorExpression::getGeneratorListIteratorEnd() const { + return ListIterator(&hasGeneratorContainer, factory, false); + } + + bool GeneratorExpression::getGeneratorIsEmpty() const { + return getGeneratorListIteratorBegin() == getGeneratorListIteratorEnd(); + } + + unsigned int GeneratorExpression::getGeneratorSize() const { + unsigned int size = 0; + ListIterator endIt = getGeneratorListIteratorEnd(); + for (ListIterator it = getGeneratorListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool GeneratorExpression::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkGeneratorExpression_HasExpression: + setExpression(edgeEnd); + return true; + case edkGeneratorExpression_HasGenerator: + addGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool GeneratorExpression::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkGeneratorExpression_HasExpression: + removeExpression(); + return true; + case edkGeneratorExpression_HasGenerator: + removeGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void GeneratorExpression::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkGeneratorExpression_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkGeneratorExpression_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkGeneratorExpression_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void GeneratorExpression::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void GeneratorExpression::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkGeneratorExpression_HasExpression); + } + m_hasExpression = 0; + } + + void GeneratorExpression::addGenerator(const expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkGenerator) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasGeneratorContainer.push_back(_node->getId()); + setParentEdge(_node,edkGeneratorExpression_HasGenerator); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkGeneratorExpression_HasGenerator); + } + + void GeneratorExpression::addGenerator(NodeId _id) { + const expression::Generator *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addGenerator( node ); + } + + void GeneratorExpression::removeGenerator(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasGeneratorContainer.begin(), hasGeneratorContainer.end(), id); + + if (it == hasGeneratorContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasGeneratorContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkGeneratorExpression_HasGenerator); + } + + void GeneratorExpression::removeGenerator(expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeGenerator(_node->getId()); + } + + void GeneratorExpression::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void GeneratorExpression::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double GeneratorExpression::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void GeneratorExpression::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType GeneratorExpression::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::GeneratorExpression", strlen("expression::GeneratorExpression")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void GeneratorExpression::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + + for (ListIterator::Container::const_iterator it = hasGeneratorContainer.begin(); it != hasGeneratorContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void GeneratorExpression::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkGeneratorExpression_HasExpression); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasGeneratorContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkGeneratorExpression_HasGenerator); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/Identifier.cpp b/lib/python/src/expression/Identifier.cpp new file mode 100644 index 0000000..9ab9cef --- /dev/null +++ b/lib/python/src/expression/Identifier.cpp @@ -0,0 +1,231 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Identifier::Identifier(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_name(0), + m_refersTo(0) + { + } + + Identifier::~Identifier() { + } + + void Identifier::prepareDelete(bool tryOnVirtualParent){ + removeRefersTo(); + expression::Expression::prepareDelete(false); + } + + NodeKind Identifier::getNodeKind() const { + return ndkIdentifier; + } + + Key Identifier::getNameKey() const { + return m_name; + } + + const std::string& Identifier::getName() const { + return factory->getStringTable().get(m_name); + } + + void Identifier::setNameKey(Key _name) { + m_name = _name; + } + + void Identifier::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + module::Object* Identifier::getRefersTo() const { + module::Object *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Identifier::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIdentifier_RefersTo: + setRefersTo(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Identifier::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIdentifier_RefersTo: + removeRefersTo(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Identifier::setRefersTo(NodeId _id) { + module::Object *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkIdentifier_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkIdentifier_RefersTo); + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Identifier::setRefersTo(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void Identifier::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkIdentifier_RefersTo); + } + m_refersTo = 0; + } + + void Identifier::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Identifier::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Identifier::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Identifier& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Identifier::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType Identifier::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Identifier", strlen("expression::Identifier")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Identifier::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + + binIo.writeUInt4(m_refersTo); + + } + + void Identifier::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_name = binIo.readUInt4(); + + m_refersTo = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/IfExpression.cpp b/lib/python/src/expression/IfExpression.cpp new file mode 100644 index 0000000..d470a9d --- /dev/null +++ b/lib/python/src/expression/IfExpression.cpp @@ -0,0 +1,333 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + IfExpression::IfExpression(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasBody(0), + m_hasElseBody(0), + m_hasTest(0) + { + } + + IfExpression::~IfExpression() { + } + + void IfExpression::prepareDelete(bool tryOnVirtualParent){ + removeBody(); + removeElseBody(); + removeTest(); + expression::Expression::prepareDelete(false); + } + + NodeKind IfExpression::getNodeKind() const { + return ndkIfExpression; + } + + expression::Expression* IfExpression::getBody() const { + expression::Expression *_node = NULL; + if (m_hasBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* IfExpression::getElseBody() const { + expression::Expression *_node = NULL; + if (m_hasElseBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasElseBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* IfExpression::getTest() const { + expression::Expression *_node = NULL; + if (m_hasTest != 0) + _node = dynamic_cast(factory->getPointer(m_hasTest)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool IfExpression::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIfExpression_HasBody: + setBody(edgeEnd); + return true; + case edkIfExpression_HasElseBody: + setElseBody(edgeEnd); + return true; + case edkIfExpression_HasTest: + setTest(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool IfExpression::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIfExpression_HasBody: + removeBody(); + return true; + case edkIfExpression_HasElseBody: + removeElseBody(); + return true; + case edkIfExpression_HasTest: + removeTest(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void IfExpression::setBody(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasBody) { + removeParentEdge(m_hasBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasBody, m_id, edkIfExpression_HasBody); + } + m_hasBody = _node->getId(); + if (m_hasBody != 0) + setParentEdge(factory->getPointer(m_hasBody), edkIfExpression_HasBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasBody, this->getId(), edkIfExpression_HasBody); + } else { + if (m_hasBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void IfExpression::setBody(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setBody(_node->getId()); + } + + void IfExpression::removeBody() { + if (m_hasBody) { + removeParentEdge(m_hasBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasBody, m_id, edkIfExpression_HasBody); + } + m_hasBody = 0; + } + + void IfExpression::setElseBody(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkIfExpression_HasElseBody); + } + m_hasElseBody = _node->getId(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody), edkIfExpression_HasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasElseBody, this->getId(), edkIfExpression_HasElseBody); + } else { + if (m_hasElseBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void IfExpression::setElseBody(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setElseBody(_node->getId()); + } + + void IfExpression::removeElseBody() { + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkIfExpression_HasElseBody); + } + m_hasElseBody = 0; + } + + void IfExpression::setTest(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTest) { + removeParentEdge(m_hasTest); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTest, m_id, edkIfExpression_HasTest); + } + m_hasTest = _node->getId(); + if (m_hasTest != 0) + setParentEdge(factory->getPointer(m_hasTest), edkIfExpression_HasTest); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTest, this->getId(), edkIfExpression_HasTest); + } else { + if (m_hasTest) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void IfExpression::setTest(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTest(_node->getId()); + } + + void IfExpression::removeTest() { + if (m_hasTest) { + removeParentEdge(m_hasTest); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTest, m_id, edkIfExpression_HasTest); + } + m_hasTest = 0; + } + + void IfExpression::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void IfExpression::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double IfExpression::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void IfExpression::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType IfExpression::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::IfExpression", strlen("expression::IfExpression")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void IfExpression::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasBody); + binIo.writeUInt4(m_hasElseBody); + binIo.writeUInt4(m_hasTest); + + } + + void IfExpression::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasBody = binIo.readUInt4(); + if (m_hasBody != 0) + setParentEdge(factory->getPointer(m_hasBody),edkIfExpression_HasBody); + + m_hasElseBody = binIo.readUInt4(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody),edkIfExpression_HasElseBody); + + m_hasTest = binIo.readUInt4(); + if (m_hasTest != 0) + setParentEdge(factory->getPointer(m_hasTest),edkIfExpression_HasTest); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/ImagNumber.cpp b/lib/python/src/expression/ImagNumber.cpp new file mode 100644 index 0000000..67d08f8 --- /dev/null +++ b/lib/python/src/expression/ImagNumber.cpp @@ -0,0 +1,145 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ImagNumber::ImagNumber(NodeId _id, Factory *_factory) : + Literal(_id, _factory), + m_im(0.0), + m_real(0.0) + { + } + + ImagNumber::~ImagNumber() { + } + + void ImagNumber::prepareDelete(bool tryOnVirtualParent){ + expression::Literal::prepareDelete(false); + } + + NodeKind ImagNumber::getNodeKind() const { + return ndkImagNumber; + } + + double ImagNumber::getIm() const { + return m_im; + } + + double ImagNumber::getReal() const { + return m_real; + } + + void ImagNumber::setIm(double _im) { + m_im = _im; + } + + void ImagNumber::setReal(double _real) { + m_real = _real; + } + + bool ImagNumber::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ImagNumber::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ImagNumber::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ImagNumber::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ImagNumber::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const ImagNumber& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getIm() == getIm()) ++matchAttrs; + if(node.getReal() == getReal()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void ImagNumber::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ImagNumber::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ImagNumber", strlen("expression::ImagNumber")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ImagNumber::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Literal::save(binIo,false); + + binIo.writeDouble8(m_im); + binIo.writeDouble8(m_real); + + } + + void ImagNumber::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Literal::load(binIo,false); + + m_im = binIo.readDouble8(); + m_real = binIo.readDouble8(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Index.cpp b/lib/python/src/expression/Index.cpp new file mode 100644 index 0000000..d28fa80 --- /dev/null +++ b/lib/python/src/expression/Index.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Index::Index(NodeId _id, Factory *_factory) : + Slicing(_id, _factory) + { + } + + Index::~Index() { + } + + void Index::prepareDelete(bool tryOnVirtualParent){ + expression::Slicing::prepareDelete(false); + } + + NodeKind Index::getNodeKind() const { + return ndkIndex; + } + + bool Index::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Slicing::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Index::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Slicing::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Index::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Index::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Index::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Index::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Index::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Index", strlen("expression::Index")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Index::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Slicing::save(binIo,false); + + } + + void Index::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Slicing::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/IntegerLiteral.cpp b/lib/python/src/expression/IntegerLiteral.cpp new file mode 100644 index 0000000..1c15686 --- /dev/null +++ b/lib/python/src/expression/IntegerLiteral.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + IntegerLiteral::IntegerLiteral(NodeId _id, Factory *_factory) : + Literal(_id, _factory), + m_value(0) + { + } + + IntegerLiteral::~IntegerLiteral() { + } + + void IntegerLiteral::prepareDelete(bool tryOnVirtualParent){ + expression::Literal::prepareDelete(false); + } + + NodeKind IntegerLiteral::getNodeKind() const { + return ndkIntegerLiteral; + } + + int IntegerLiteral::getValue() const { + return m_value; + } + + void IntegerLiteral::setValue(int _value) { + m_value = _value; + } + + bool IntegerLiteral::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool IntegerLiteral::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void IntegerLiteral::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void IntegerLiteral::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double IntegerLiteral::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const IntegerLiteral& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getValue() == getValue()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void IntegerLiteral::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType IntegerLiteral::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::IntegerLiteral", strlen("expression::IntegerLiteral")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void IntegerLiteral::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Literal::save(binIo,false); + + binIo.writeUInt4(m_value); + + } + + void IntegerLiteral::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Literal::load(binIo,false); + + m_value = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/KeyValue.cpp b/lib/python/src/expression/KeyValue.cpp new file mode 100644 index 0000000..e2179da --- /dev/null +++ b/lib/python/src/expression/KeyValue.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + KeyValue::KeyValue(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_hasKey(0), + m_hasValue(0) + { + } + + KeyValue::~KeyValue() { + } + + void KeyValue::prepareDelete(bool tryOnVirtualParent){ + removeKey(); + removeValue(); + base::Positioned::prepareDelete(false); + } + + NodeKind KeyValue::getNodeKind() const { + return ndkKeyValue; + } + + expression::Expression* KeyValue::getKey() const { + expression::Expression *_node = NULL; + if (m_hasKey != 0) + _node = dynamic_cast(factory->getPointer(m_hasKey)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* KeyValue::getValue() const { + expression::Expression *_node = NULL; + if (m_hasValue != 0) + _node = dynamic_cast(factory->getPointer(m_hasValue)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool KeyValue::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkKeyValue_HasKey: + setKey(edgeEnd); + return true; + case edkKeyValue_HasValue: + setValue(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool KeyValue::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkKeyValue_HasKey: + removeKey(); + return true; + case edkKeyValue_HasValue: + removeValue(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void KeyValue::setKey(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkKeyValue_HasKey); + } + m_hasKey = _node->getId(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey), edkKeyValue_HasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasKey, this->getId(), edkKeyValue_HasKey); + } else { + if (m_hasKey) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void KeyValue::setKey(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setKey(_node->getId()); + } + + void KeyValue::removeKey() { + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkKeyValue_HasKey); + } + m_hasKey = 0; + } + + void KeyValue::setValue(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasValue) { + removeParentEdge(m_hasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValue, m_id, edkKeyValue_HasValue); + } + m_hasValue = _node->getId(); + if (m_hasValue != 0) + setParentEdge(factory->getPointer(m_hasValue), edkKeyValue_HasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasValue, this->getId(), edkKeyValue_HasValue); + } else { + if (m_hasValue) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void KeyValue::setValue(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setValue(_node->getId()); + } + + void KeyValue::removeValue() { + if (m_hasValue) { + removeParentEdge(m_hasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValue, m_id, edkKeyValue_HasValue); + } + m_hasValue = 0; + } + + void KeyValue::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void KeyValue::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double KeyValue::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void KeyValue::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType KeyValue::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::KeyValue", strlen("expression::KeyValue")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void KeyValue::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + binIo.writeUInt4(m_hasKey); + binIo.writeUInt4(m_hasValue); + + } + + void KeyValue::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_hasKey = binIo.readUInt4(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey),edkKeyValue_HasKey); + + m_hasValue = binIo.readUInt4(); + if (m_hasValue != 0) + setParentEdge(factory->getPointer(m_hasValue),edkKeyValue_HasValue); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Keyword.cpp b/lib/python/src/expression/Keyword.cpp new file mode 100644 index 0000000..1132681 --- /dev/null +++ b/lib/python/src/expression/Keyword.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Keyword::Keyword(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_hasKey(0), + m_hasValue(0) + { + } + + Keyword::~Keyword() { + } + + void Keyword::prepareDelete(bool tryOnVirtualParent){ + removeKey(); + removeValue(); + base::Positioned::prepareDelete(false); + } + + NodeKind Keyword::getNodeKind() const { + return ndkKeyword; + } + + expression::Identifier* Keyword::getKey() const { + expression::Identifier *_node = NULL; + if (m_hasKey != 0) + _node = dynamic_cast(factory->getPointer(m_hasKey)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Keyword::getValue() const { + expression::Expression *_node = NULL; + if (m_hasValue != 0) + _node = dynamic_cast(factory->getPointer(m_hasValue)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Keyword::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkKeyword_HasKey: + setKey(edgeEnd); + return true; + case edkKeyword_HasValue: + setValue(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Keyword::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkKeyword_HasKey: + removeKey(); + return true; + case edkKeyword_HasValue: + removeValue(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Keyword::setKey(NodeId _id) { + expression::Identifier *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkKeyword_HasKey); + } + m_hasKey = _node->getId(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey), edkKeyword_HasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasKey, this->getId(), edkKeyword_HasKey); + } else { + if (m_hasKey) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Keyword::setKey(expression::Identifier *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setKey(_node->getId()); + } + + void Keyword::removeKey() { + if (m_hasKey) { + removeParentEdge(m_hasKey); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasKey, m_id, edkKeyword_HasKey); + } + m_hasKey = 0; + } + + void Keyword::setValue(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasValue) { + removeParentEdge(m_hasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValue, m_id, edkKeyword_HasValue); + } + m_hasValue = _node->getId(); + if (m_hasValue != 0) + setParentEdge(factory->getPointer(m_hasValue), edkKeyword_HasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasValue, this->getId(), edkKeyword_HasValue); + } else { + if (m_hasValue) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Keyword::setValue(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setValue(_node->getId()); + } + + void Keyword::removeValue() { + if (m_hasValue) { + removeParentEdge(m_hasValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValue, m_id, edkKeyword_HasValue); + } + m_hasValue = 0; + } + + void Keyword::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Keyword::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Keyword::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Keyword::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Keyword::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Keyword", strlen("expression::Keyword")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Keyword::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + binIo.writeUInt4(m_hasKey); + binIo.writeUInt4(m_hasValue); + + } + + void Keyword::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_hasKey = binIo.readUInt4(); + if (m_hasKey != 0) + setParentEdge(factory->getPointer(m_hasKey),edkKeyword_HasKey); + + m_hasValue = binIo.readUInt4(); + if (m_hasValue != 0) + setParentEdge(factory->getPointer(m_hasValue),edkKeyword_HasValue); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Lambda.cpp b/lib/python/src/expression/Lambda.cpp new file mode 100644 index 0000000..6f93d64 --- /dev/null +++ b/lib/python/src/expression/Lambda.cpp @@ -0,0 +1,386 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Lambda::Lambda(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + hasObjectContainer(), + hasParameterContainer(), + m_hasExpression(0) + { + } + + Lambda::~Lambda() { + } + + void Lambda::prepareDelete(bool tryOnVirtualParent){ + while (!hasObjectContainer.empty()) { + const NodeId id = *hasObjectContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkLambda_HasObject); + hasObjectContainer.pop_front(); + } + while (!hasParameterContainer.empty()) { + const NodeId id = *hasParameterContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkLambda_HasParameter); + hasParameterContainer.pop_front(); + } + removeExpression(); + expression::Expression::prepareDelete(false); + } + + NodeKind Lambda::getNodeKind() const { + return ndkLambda; + } + + ListIterator Lambda::getObjectListIteratorBegin() const { + return ListIterator(&hasObjectContainer, factory, true); + } + + ListIterator Lambda::getObjectListIteratorEnd() const { + return ListIterator(&hasObjectContainer, factory, false); + } + + bool Lambda::getObjectIsEmpty() const { + return getObjectListIteratorBegin() == getObjectListIteratorEnd(); + } + + unsigned int Lambda::getObjectSize() const { + unsigned int size = 0; + ListIterator endIt = getObjectListIteratorEnd(); + for (ListIterator it = getObjectListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator Lambda::getParameterListIteratorBegin() const { + return ListIterator(&hasParameterContainer, factory, true); + } + + ListIterator Lambda::getParameterListIteratorEnd() const { + return ListIterator(&hasParameterContainer, factory, false); + } + + bool Lambda::getParameterIsEmpty() const { + return getParameterListIteratorBegin() == getParameterListIteratorEnd(); + } + + unsigned int Lambda::getParameterSize() const { + unsigned int size = 0; + ListIterator endIt = getParameterListIteratorEnd(); + for (ListIterator it = getParameterListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + expression::Expression* Lambda::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Lambda::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkLambda_HasObject: + addObject(edgeEnd); + return true; + case edkLambda_HasParameter: + addParameter(edgeEnd); + return true; + case edkLambda_HasExpression: + setExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Lambda::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkLambda_HasObject: + removeObject(edgeEnd); + return true; + case edkLambda_HasParameter: + removeParameter(edgeEnd); + return true; + case edkLambda_HasExpression: + removeExpression(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Lambda::addObject(const module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkObject) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasObjectContainer.push_back(_node->getId()); + setParentEdge(_node,edkLambda_HasObject); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkLambda_HasObject); + } + + void Lambda::addObject(NodeId _id) { + const module::Object *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addObject( node ); + } + + void Lambda::removeObject(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasObjectContainer.begin(), hasObjectContainer.end(), id); + + if (it == hasObjectContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasObjectContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkLambda_HasObject); + } + + void Lambda::removeObject(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeObject(_node->getId()); + } + + void Lambda::addParameter(const statement::Parameter *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkParameter) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasParameterContainer.push_back(_node->getId()); + setParentEdge(_node,edkLambda_HasParameter); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkLambda_HasParameter); + } + + void Lambda::addParameter(NodeId _id) { + const statement::Parameter *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addParameter( node ); + } + + void Lambda::removeParameter(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasParameterContainer.begin(), hasParameterContainer.end(), id); + + if (it == hasParameterContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasParameterContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkLambda_HasParameter); + } + + void Lambda::removeParameter(statement::Parameter *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeParameter(_node->getId()); + } + + void Lambda::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkLambda_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkLambda_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkLambda_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Lambda::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void Lambda::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkLambda_HasExpression); + } + m_hasExpression = 0; + } + + void Lambda::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Lambda::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Lambda::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Lambda::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Lambda::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Lambda", strlen("expression::Lambda")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Lambda::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + + for (ListIterator::Container::const_iterator it = hasObjectContainer.begin(); it != hasObjectContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasParameterContainer.begin(); it != hasParameterContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Lambda::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkLambda_HasExpression); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasObjectContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkLambda_HasObject); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasParameterContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkLambda_HasParameter); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/List.cpp b/lib/python/src/expression/List.cpp new file mode 100644 index 0000000..d87cdd7 --- /dev/null +++ b/lib/python/src/expression/List.cpp @@ -0,0 +1,243 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + List::List(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_isTuple(false), + hasExpressionContainer() + { + } + + List::~List() { + } + + void List::prepareDelete(bool tryOnVirtualParent){ + while (!hasExpressionContainer.empty()) { + const NodeId id = *hasExpressionContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkList_HasExpression); + hasExpressionContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind List::getNodeKind() const { + return ndkList; + } + + bool List::getIsTuple() const { + return m_isTuple; + } + + void List::setIsTuple(bool _isTuple) { + m_isTuple = _isTuple; + } + + ListIterator List::getExpressionListIteratorBegin() const { + return ListIterator(&hasExpressionContainer, factory, true); + } + + ListIterator List::getExpressionListIteratorEnd() const { + return ListIterator(&hasExpressionContainer, factory, false); + } + + bool List::getExpressionIsEmpty() const { + return getExpressionListIteratorBegin() == getExpressionListIteratorEnd(); + } + + unsigned int List::getExpressionSize() const { + unsigned int size = 0; + ListIterator endIt = getExpressionListIteratorEnd(); + for (ListIterator it = getExpressionListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool List::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkList_HasExpression: + addExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool List::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkList_HasExpression: + removeExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void List::addExpression(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasExpressionContainer.push_back(_node->getId()); + setParentEdge(_node,edkList_HasExpression); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkList_HasExpression); + } + + void List::addExpression(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addExpression( node ); + } + + void List::removeExpression(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasExpressionContainer.begin(), hasExpressionContainer.end(), id); + + if (it == hasExpressionContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasExpressionContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkList_HasExpression); + } + + void List::removeExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeExpression(_node->getId()); + } + + void List::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void List::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double List::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const List& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getIsTuple() == getIsTuple()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void List::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType List::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::List", strlen("expression::List")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void List::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + unsigned char boolValues = 0; + boolValues <<= 1; + if (m_isTuple) + boolValues |= 1; + binIo.writeUByte1(boolValues); + + + for (ListIterator::Container::const_iterator it = hasExpressionContainer.begin(); it != hasExpressionContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void List::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + unsigned char boolValues = binIo.readUByte1(); + m_isTuple = boolValues & 1; + boolValues >>= 1; + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasExpressionContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkList_HasExpression); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/ListComp.cpp b/lib/python/src/expression/ListComp.cpp new file mode 100644 index 0000000..8913351 --- /dev/null +++ b/lib/python/src/expression/ListComp.cpp @@ -0,0 +1,291 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + ListComp::ListComp(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasExpression(0), + hasGeneratorContainer() + { + } + + ListComp::~ListComp() { + } + + void ListComp::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + while (!hasGeneratorContainer.empty()) { + const NodeId id = *hasGeneratorContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkListComp_HasGenerator); + hasGeneratorContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind ListComp::getNodeKind() const { + return ndkListComp; + } + + expression::Expression* ListComp::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + ListIterator ListComp::getGeneratorListIteratorBegin() const { + return ListIterator(&hasGeneratorContainer, factory, true); + } + + ListIterator ListComp::getGeneratorListIteratorEnd() const { + return ListIterator(&hasGeneratorContainer, factory, false); + } + + bool ListComp::getGeneratorIsEmpty() const { + return getGeneratorListIteratorBegin() == getGeneratorListIteratorEnd(); + } + + unsigned int ListComp::getGeneratorSize() const { + unsigned int size = 0; + ListIterator endIt = getGeneratorListIteratorEnd(); + for (ListIterator it = getGeneratorListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool ListComp::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkListComp_HasExpression: + setExpression(edgeEnd); + return true; + case edkListComp_HasGenerator: + addGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ListComp::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkListComp_HasExpression: + removeExpression(); + return true; + case edkListComp_HasGenerator: + removeGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ListComp::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkListComp_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkListComp_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkListComp_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ListComp::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void ListComp::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkListComp_HasExpression); + } + m_hasExpression = 0; + } + + void ListComp::addGenerator(const expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkGenerator) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasGeneratorContainer.push_back(_node->getId()); + setParentEdge(_node,edkListComp_HasGenerator); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkListComp_HasGenerator); + } + + void ListComp::addGenerator(NodeId _id) { + const expression::Generator *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addGenerator( node ); + } + + void ListComp::removeGenerator(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasGeneratorContainer.begin(), hasGeneratorContainer.end(), id); + + if (it == hasGeneratorContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasGeneratorContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkListComp_HasGenerator); + } + + void ListComp::removeGenerator(expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeGenerator(_node->getId()); + } + + void ListComp::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ListComp::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ListComp::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void ListComp::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ListComp::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::ListComp", strlen("expression::ListComp")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ListComp::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + + for (ListIterator::Container::const_iterator it = hasGeneratorContainer.begin(); it != hasGeneratorContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void ListComp::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkListComp_HasExpression); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasGeneratorContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkListComp_HasGenerator); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/Literal.cpp b/lib/python/src/expression/Literal.cpp new file mode 100644 index 0000000..4e4a9cd --- /dev/null +++ b/lib/python/src/expression/Literal.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Literal::Literal(NodeId _id, Factory *_factory) : + Expression(_id, _factory) + { + } + + Literal::~Literal() { + } + + void Literal::prepareDelete(bool tryOnVirtualParent){ + expression::Expression::prepareDelete(false); + } + + bool Literal::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Literal::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double Literal::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Literal::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Literal::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Literal", strlen("expression::Literal")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Literal::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + } + + void Literal::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/LongInteger.cpp b/lib/python/src/expression/LongInteger.cpp new file mode 100644 index 0000000..50ab669 --- /dev/null +++ b/lib/python/src/expression/LongInteger.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + LongInteger::LongInteger(NodeId _id, Factory *_factory) : + Literal(_id, _factory), + m_value(0) + { + } + + LongInteger::~LongInteger() { + } + + void LongInteger::prepareDelete(bool tryOnVirtualParent){ + expression::Literal::prepareDelete(false); + } + + NodeKind LongInteger::getNodeKind() const { + return ndkLongInteger; + } + + int LongInteger::getValue() const { + return m_value; + } + + void LongInteger::setValue(int _value) { + m_value = _value; + } + + bool LongInteger::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool LongInteger::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void LongInteger::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void LongInteger::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double LongInteger::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const LongInteger& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getValue() == getValue()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void LongInteger::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType LongInteger::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::LongInteger", strlen("expression::LongInteger")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void LongInteger::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Literal::save(binIo,false); + + binIo.writeUInt4(m_value); + + } + + void LongInteger::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Literal::load(binIo,false); + + m_value = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Set.cpp b/lib/python/src/expression/Set.cpp new file mode 100644 index 0000000..b1dfc4d --- /dev/null +++ b/lib/python/src/expression/Set.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Set::Set(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + hasExpressionContainer() + { + } + + Set::~Set() { + } + + void Set::prepareDelete(bool tryOnVirtualParent){ + while (!hasExpressionContainer.empty()) { + const NodeId id = *hasExpressionContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkSet_HasExpression); + hasExpressionContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind Set::getNodeKind() const { + return ndkSet; + } + + ListIterator Set::getExpressionListIteratorBegin() const { + return ListIterator(&hasExpressionContainer, factory, true); + } + + ListIterator Set::getExpressionListIteratorEnd() const { + return ListIterator(&hasExpressionContainer, factory, false); + } + + bool Set::getExpressionIsEmpty() const { + return getExpressionListIteratorBegin() == getExpressionListIteratorEnd(); + } + + unsigned int Set::getExpressionSize() const { + unsigned int size = 0; + ListIterator endIt = getExpressionListIteratorEnd(); + for (ListIterator it = getExpressionListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Set::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSet_HasExpression: + addExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Set::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSet_HasExpression: + removeExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Set::addExpression(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasExpressionContainer.push_back(_node->getId()); + setParentEdge(_node,edkSet_HasExpression); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkSet_HasExpression); + } + + void Set::addExpression(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addExpression( node ); + } + + void Set::removeExpression(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasExpressionContainer.begin(), hasExpressionContainer.end(), id); + + if (it == hasExpressionContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasExpressionContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkSet_HasExpression); + } + + void Set::removeExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeExpression(_node->getId()); + } + + void Set::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Set::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Set::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Set::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Set::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Set", strlen("expression::Set")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Set::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasExpressionContainer.begin(); it != hasExpressionContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Set::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasExpressionContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkSet_HasExpression); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/SetComp.cpp b/lib/python/src/expression/SetComp.cpp new file mode 100644 index 0000000..ec1e28f --- /dev/null +++ b/lib/python/src/expression/SetComp.cpp @@ -0,0 +1,291 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + SetComp::SetComp(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasExpression(0), + hasGeneratorContainer() + { + } + + SetComp::~SetComp() { + } + + void SetComp::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + while (!hasGeneratorContainer.empty()) { + const NodeId id = *hasGeneratorContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkSetComp_HasGenerator); + hasGeneratorContainer.pop_front(); + } + expression::Expression::prepareDelete(false); + } + + NodeKind SetComp::getNodeKind() const { + return ndkSetComp; + } + + expression::Expression* SetComp::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + ListIterator SetComp::getGeneratorListIteratorBegin() const { + return ListIterator(&hasGeneratorContainer, factory, true); + } + + ListIterator SetComp::getGeneratorListIteratorEnd() const { + return ListIterator(&hasGeneratorContainer, factory, false); + } + + bool SetComp::getGeneratorIsEmpty() const { + return getGeneratorListIteratorBegin() == getGeneratorListIteratorEnd(); + } + + unsigned int SetComp::getGeneratorSize() const { + unsigned int size = 0; + ListIterator endIt = getGeneratorListIteratorEnd(); + for (ListIterator it = getGeneratorListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool SetComp::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSetComp_HasExpression: + setExpression(edgeEnd); + return true; + case edkSetComp_HasGenerator: + addGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool SetComp::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSetComp_HasExpression: + removeExpression(); + return true; + case edkSetComp_HasGenerator: + removeGenerator(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void SetComp::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkSetComp_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkSetComp_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkSetComp_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void SetComp::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void SetComp::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkSetComp_HasExpression); + } + m_hasExpression = 0; + } + + void SetComp::addGenerator(const expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkGenerator) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasGeneratorContainer.push_back(_node->getId()); + setParentEdge(_node,edkSetComp_HasGenerator); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkSetComp_HasGenerator); + } + + void SetComp::addGenerator(NodeId _id) { + const expression::Generator *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addGenerator( node ); + } + + void SetComp::removeGenerator(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasGeneratorContainer.begin(), hasGeneratorContainer.end(), id); + + if (it == hasGeneratorContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasGeneratorContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkSetComp_HasGenerator); + } + + void SetComp::removeGenerator(expression::Generator *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeGenerator(_node->getId()); + } + + void SetComp::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void SetComp::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double SetComp::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void SetComp::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType SetComp::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::SetComp", strlen("expression::SetComp")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void SetComp::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + + for (ListIterator::Container::const_iterator it = hasGeneratorContainer.begin(); it != hasGeneratorContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void SetComp::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkSetComp_HasExpression); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasGeneratorContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkSetComp_HasGenerator); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/expression/Slice.cpp b/lib/python/src/expression/Slice.cpp new file mode 100644 index 0000000..629bb12 --- /dev/null +++ b/lib/python/src/expression/Slice.cpp @@ -0,0 +1,333 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Slice::Slice(NodeId _id, Factory *_factory) : + Slicing(_id, _factory), + m_hasLowerBound(0), + m_hasStride(0), + m_hasUpperBound(0) + { + } + + Slice::~Slice() { + } + + void Slice::prepareDelete(bool tryOnVirtualParent){ + removeLowerBound(); + removeStride(); + removeUpperBound(); + expression::Slicing::prepareDelete(false); + } + + NodeKind Slice::getNodeKind() const { + return ndkSlice; + } + + expression::Expression* Slice::getLowerBound() const { + expression::Expression *_node = NULL; + if (m_hasLowerBound != 0) + _node = dynamic_cast(factory->getPointer(m_hasLowerBound)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Slice::getStride() const { + expression::Expression *_node = NULL; + if (m_hasStride != 0) + _node = dynamic_cast(factory->getPointer(m_hasStride)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Slice::getUpperBound() const { + expression::Expression *_node = NULL; + if (m_hasUpperBound != 0) + _node = dynamic_cast(factory->getPointer(m_hasUpperBound)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Slice::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSlice_HasLowerBound: + setLowerBound(edgeEnd); + return true; + case edkSlice_HasStride: + setStride(edgeEnd); + return true; + case edkSlice_HasUpperBound: + setUpperBound(edgeEnd); + return true; + default: + break; + } + if (expression::Slicing::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Slice::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSlice_HasLowerBound: + removeLowerBound(); + return true; + case edkSlice_HasStride: + removeStride(); + return true; + case edkSlice_HasUpperBound: + removeUpperBound(); + return true; + default: + break; + } + if (expression::Slicing::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Slice::setLowerBound(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasLowerBound) { + removeParentEdge(m_hasLowerBound); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLowerBound, m_id, edkSlice_HasLowerBound); + } + m_hasLowerBound = _node->getId(); + if (m_hasLowerBound != 0) + setParentEdge(factory->getPointer(m_hasLowerBound), edkSlice_HasLowerBound); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasLowerBound, this->getId(), edkSlice_HasLowerBound); + } else { + if (m_hasLowerBound) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Slice::setLowerBound(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setLowerBound(_node->getId()); + } + + void Slice::removeLowerBound() { + if (m_hasLowerBound) { + removeParentEdge(m_hasLowerBound); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLowerBound, m_id, edkSlice_HasLowerBound); + } + m_hasLowerBound = 0; + } + + void Slice::setStride(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasStride) { + removeParentEdge(m_hasStride); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasStride, m_id, edkSlice_HasStride); + } + m_hasStride = _node->getId(); + if (m_hasStride != 0) + setParentEdge(factory->getPointer(m_hasStride), edkSlice_HasStride); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasStride, this->getId(), edkSlice_HasStride); + } else { + if (m_hasStride) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Slice::setStride(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setStride(_node->getId()); + } + + void Slice::removeStride() { + if (m_hasStride) { + removeParentEdge(m_hasStride); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasStride, m_id, edkSlice_HasStride); + } + m_hasStride = 0; + } + + void Slice::setUpperBound(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasUpperBound) { + removeParentEdge(m_hasUpperBound); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasUpperBound, m_id, edkSlice_HasUpperBound); + } + m_hasUpperBound = _node->getId(); + if (m_hasUpperBound != 0) + setParentEdge(factory->getPointer(m_hasUpperBound), edkSlice_HasUpperBound); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasUpperBound, this->getId(), edkSlice_HasUpperBound); + } else { + if (m_hasUpperBound) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Slice::setUpperBound(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setUpperBound(_node->getId()); + } + + void Slice::removeUpperBound() { + if (m_hasUpperBound) { + removeParentEdge(m_hasUpperBound); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasUpperBound, m_id, edkSlice_HasUpperBound); + } + m_hasUpperBound = 0; + } + + void Slice::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Slice::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Slice::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Slice::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Slice::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Slice", strlen("expression::Slice")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Slice::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Slicing::save(binIo,false); + + binIo.writeUInt4(m_hasLowerBound); + binIo.writeUInt4(m_hasStride); + binIo.writeUInt4(m_hasUpperBound); + + } + + void Slice::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Slicing::load(binIo,false); + + m_hasLowerBound = binIo.readUInt4(); + if (m_hasLowerBound != 0) + setParentEdge(factory->getPointer(m_hasLowerBound),edkSlice_HasLowerBound); + + m_hasStride = binIo.readUInt4(); + if (m_hasStride != 0) + setParentEdge(factory->getPointer(m_hasStride),edkSlice_HasStride); + + m_hasUpperBound = binIo.readUInt4(); + if (m_hasUpperBound != 0) + setParentEdge(factory->getPointer(m_hasUpperBound),edkSlice_HasUpperBound); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Slicing.cpp b/lib/python/src/expression/Slicing.cpp new file mode 100644 index 0000000..b9dbd8a --- /dev/null +++ b/lib/python/src/expression/Slicing.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Slicing::Slicing(NodeId _id, Factory *_factory) : + Unary(_id, _factory) + { + } + + Slicing::~Slicing() { + } + + void Slicing::prepareDelete(bool tryOnVirtualParent){ + expression::Unary::prepareDelete(false); + } + + bool Slicing::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Unary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Slicing::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Unary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double Slicing::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Slicing::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Slicing::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Slicing", strlen("expression::Slicing")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Slicing::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Unary::save(binIo,false); + + } + + void Slicing::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Unary::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/StringConversion.cpp b/lib/python/src/expression/StringConversion.cpp new file mode 100644 index 0000000..8fd27ee --- /dev/null +++ b/lib/python/src/expression/StringConversion.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + StringConversion::StringConversion(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasExpressionList(0) + { + } + + StringConversion::~StringConversion() { + } + + void StringConversion::prepareDelete(bool tryOnVirtualParent){ + removeExpressionList(); + expression::Expression::prepareDelete(false); + } + + NodeKind StringConversion::getNodeKind() const { + return ndkStringConversion; + } + + expression::ExpressionList* StringConversion::getExpressionList() const { + expression::ExpressionList *_node = NULL; + if (m_hasExpressionList != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpressionList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool StringConversion::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkStringConversion_HasExpressionList: + setExpressionList(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool StringConversion::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkStringConversion_HasExpressionList: + removeExpressionList(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void StringConversion::setExpressionList(NodeId _id) { + expression::ExpressionList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpressionList) { + removeParentEdge(m_hasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpressionList, m_id, edkStringConversion_HasExpressionList); + } + m_hasExpressionList = _node->getId(); + if (m_hasExpressionList != 0) + setParentEdge(factory->getPointer(m_hasExpressionList), edkStringConversion_HasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpressionList, this->getId(), edkStringConversion_HasExpressionList); + } else { + if (m_hasExpressionList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void StringConversion::setExpressionList(expression::ExpressionList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpressionList(_node->getId()); + } + + void StringConversion::removeExpressionList() { + if (m_hasExpressionList) { + removeParentEdge(m_hasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpressionList, m_id, edkStringConversion_HasExpressionList); + } + m_hasExpressionList = 0; + } + + void StringConversion::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void StringConversion::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double StringConversion::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void StringConversion::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType StringConversion::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::StringConversion", strlen("expression::StringConversion")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void StringConversion::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpressionList); + + } + + void StringConversion::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasExpressionList = binIo.readUInt4(); + if (m_hasExpressionList != 0) + setParentEdge(factory->getPointer(m_hasExpressionList),edkStringConversion_HasExpressionList); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/StringLiteral.cpp b/lib/python/src/expression/StringLiteral.cpp new file mode 100644 index 0000000..6d5c791 --- /dev/null +++ b/lib/python/src/expression/StringLiteral.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + StringLiteral::StringLiteral(NodeId _id, Factory *_factory) : + Literal(_id, _factory), + m_value(0) + { + } + + StringLiteral::~StringLiteral() { + } + + void StringLiteral::prepareDelete(bool tryOnVirtualParent){ + expression::Literal::prepareDelete(false); + } + + NodeKind StringLiteral::getNodeKind() const { + return ndkStringLiteral; + } + + Key StringLiteral::getValueKey() const { + return m_value; + } + + const std::string& StringLiteral::getValue() const { + return factory->getStringTable().get(m_value); + } + + void StringLiteral::setValueKey(Key _value) { + m_value = _value; + } + + void StringLiteral::setValue(const std::string& _value) { + m_value = factory->getStringTable().set(_value); + } + + bool StringLiteral::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool StringLiteral::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Literal::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void StringLiteral::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void StringLiteral::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double StringLiteral::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const StringLiteral& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getValue(); + str2 = node.getValue(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void StringLiteral::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_value); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_value = foundKeyId->second; + } else { + Key oldkey = m_value; + m_value = newStrTable.set(factory->getStringTable().get(m_value)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_value)); } + + } + + NodeHashType StringLiteral::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::StringLiteral", strlen("expression::StringLiteral")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void StringLiteral::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Literal::save(binIo,false); + + factory->getStringTable().setType(m_value, StrTable::strToSave); + binIo.writeUInt4(m_value); + + } + + void StringLiteral::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Literal::load(binIo,false); + + m_value = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Subscription.cpp b/lib/python/src/expression/Subscription.cpp new file mode 100644 index 0000000..878cec0 --- /dev/null +++ b/lib/python/src/expression/Subscription.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Subscription::Subscription(NodeId _id, Factory *_factory) : + Unary(_id, _factory), + m_hasSlicing(0) + { + } + + Subscription::~Subscription() { + } + + void Subscription::prepareDelete(bool tryOnVirtualParent){ + removeSlicing(); + expression::Unary::prepareDelete(false); + } + + NodeKind Subscription::getNodeKind() const { + return ndkSubscription; + } + + expression::Slicing* Subscription::getSlicing() const { + expression::Slicing *_node = NULL; + if (m_hasSlicing != 0) + _node = dynamic_cast(factory->getPointer(m_hasSlicing)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Subscription::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSubscription_HasSlicing: + setSlicing(edgeEnd); + return true; + default: + break; + } + if (expression::Unary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Subscription::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSubscription_HasSlicing: + removeSlicing(); + return true; + default: + break; + } + if (expression::Unary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Subscription::setSlicing(NodeId _id) { + expression::Slicing *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasSlicing) { + removeParentEdge(m_hasSlicing); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasSlicing, m_id, edkSubscription_HasSlicing); + } + m_hasSlicing = _node->getId(); + if (m_hasSlicing != 0) + setParentEdge(factory->getPointer(m_hasSlicing), edkSubscription_HasSlicing); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasSlicing, this->getId(), edkSubscription_HasSlicing); + } else { + if (m_hasSlicing) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Subscription::setSlicing(expression::Slicing *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setSlicing(_node->getId()); + } + + void Subscription::removeSlicing() { + if (m_hasSlicing) { + removeParentEdge(m_hasSlicing); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasSlicing, m_id, edkSubscription_HasSlicing); + } + m_hasSlicing = 0; + } + + void Subscription::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Subscription::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Subscription::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Subscription::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Subscription::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Subscription", strlen("expression::Subscription")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Subscription::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Unary::save(binIo,false); + + binIo.writeUInt4(m_hasSlicing); + + } + + void Subscription::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Unary::load(binIo,false); + + m_hasSlicing = binIo.readUInt4(); + if (m_hasSlicing != 0) + setParentEdge(factory->getPointer(m_hasSlicing),edkSubscription_HasSlicing); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/Unary.cpp b/lib/python/src/expression/Unary.cpp new file mode 100644 index 0000000..389fbfa --- /dev/null +++ b/lib/python/src/expression/Unary.cpp @@ -0,0 +1,183 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + Unary::Unary(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasExpression(0) + { + } + + Unary::~Unary() { + } + + void Unary::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + expression::Expression::prepareDelete(false); + } + + expression::Expression* Unary::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Unary::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkUnary_HasExpression: + setExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Unary::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkUnary_HasExpression: + removeExpression(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Unary::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkUnary_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkUnary_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkUnary_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Unary::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void Unary::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkUnary_HasExpression); + } + m_hasExpression = 0; + } + + double Unary::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Unary::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Unary::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::Unary", strlen("expression::Unary")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Unary::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + } + + void Unary::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkUnary_HasExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/UnaryOperation.cpp b/lib/python/src/expression/UnaryOperation.cpp new file mode 100644 index 0000000..552f1a5 --- /dev/null +++ b/lib/python/src/expression/UnaryOperation.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + UnaryOperation::UnaryOperation(NodeId _id, Factory *_factory) : + Unary(_id, _factory), + m_kind(unkInvert) + { + } + + UnaryOperation::~UnaryOperation() { + } + + void UnaryOperation::prepareDelete(bool tryOnVirtualParent){ + expression::Unary::prepareDelete(false); + } + + NodeKind UnaryOperation::getNodeKind() const { + return ndkUnaryOperation; + } + + UnaryKind UnaryOperation::getKind() const { + return m_kind; + } + + void UnaryOperation::setKind(UnaryKind _kind) { + m_kind = _kind; + } + + bool UnaryOperation::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Unary::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool UnaryOperation::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (expression::Unary::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void UnaryOperation::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void UnaryOperation::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double UnaryOperation::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const UnaryOperation& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void UnaryOperation::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType UnaryOperation::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::UnaryOperation", strlen("expression::UnaryOperation")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void UnaryOperation::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Unary::save(binIo,false); + + binIo.writeUByte1(m_kind); + + } + + void UnaryOperation::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Unary::load(binIo,false); + + m_kind = (UnaryKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/expression/YieldExpression.cpp b/lib/python/src/expression/YieldExpression.cpp new file mode 100644 index 0000000..c613632 --- /dev/null +++ b/lib/python/src/expression/YieldExpression.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace expression { + YieldExpression::YieldExpression(NodeId _id, Factory *_factory) : + Expression(_id, _factory), + m_hasYieldExpression(0) + { + } + + YieldExpression::~YieldExpression() { + } + + void YieldExpression::prepareDelete(bool tryOnVirtualParent){ + removeYieldExpression(); + expression::Expression::prepareDelete(false); + } + + NodeKind YieldExpression::getNodeKind() const { + return ndkYieldExpression; + } + + expression::ExpressionList* YieldExpression::getYieldExpression() const { + expression::ExpressionList *_node = NULL; + if (m_hasYieldExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasYieldExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool YieldExpression::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkYieldExpression_HasYieldExpression: + setYieldExpression(edgeEnd); + return true; + default: + break; + } + if (expression::Expression::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool YieldExpression::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkYieldExpression_HasYieldExpression: + removeYieldExpression(); + return true; + default: + break; + } + if (expression::Expression::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void YieldExpression::setYieldExpression(NodeId _id) { + expression::ExpressionList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasYieldExpression) { + removeParentEdge(m_hasYieldExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasYieldExpression, m_id, edkYieldExpression_HasYieldExpression); + } + m_hasYieldExpression = _node->getId(); + if (m_hasYieldExpression != 0) + setParentEdge(factory->getPointer(m_hasYieldExpression), edkYieldExpression_HasYieldExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasYieldExpression, this->getId(), edkYieldExpression_HasYieldExpression); + } else { + if (m_hasYieldExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void YieldExpression::setYieldExpression(expression::ExpressionList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setYieldExpression(_node->getId()); + } + + void YieldExpression::removeYieldExpression() { + if (m_hasYieldExpression) { + removeParentEdge(m_hasYieldExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasYieldExpression, m_id, edkYieldExpression_HasYieldExpression); + } + m_hasYieldExpression = 0; + } + + void YieldExpression::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void YieldExpression::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double YieldExpression::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void YieldExpression::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType YieldExpression::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "expression::YieldExpression", strlen("expression::YieldExpression")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void YieldExpression::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Expression::save(binIo,false); + + binIo.writeUInt4(m_hasYieldExpression); + + } + + void YieldExpression::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Expression::load(binIo,false); + + m_hasYieldExpression = binIo.readUInt4(); + if (m_hasYieldExpression != 0) + setParentEdge(factory->getPointer(m_hasYieldExpression),edkYieldExpression_HasYieldExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/module/Module.cpp b/lib/python/src/module/Module.cpp new file mode 100644 index 0000000..e9c5294 --- /dev/null +++ b/lib/python/src/module/Module.cpp @@ -0,0 +1,414 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace module { + Module::Module(NodeId _id, Factory *_factory) : + Named(_id, _factory), + m_lloc(0), + hasObjectContainer(), + hasStatementContainer(), + m_docstring(0) + { + } + + Module::~Module() { + } + + void Module::prepareDelete(bool tryOnVirtualParent){ + while (!hasObjectContainer.empty()) { + const NodeId id = *hasObjectContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkModule_HasObject); + hasObjectContainer.pop_front(); + } + while (!hasStatementContainer.empty()) { + const NodeId id = *hasStatementContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkModule_HasStatement); + hasStatementContainer.pop_front(); + } + removeDocstring(); + base::Named::prepareDelete(false); + } + + NodeKind Module::getNodeKind() const { + return ndkModule; + } + + int Module::getLloc() const { + return m_lloc; + } + + void Module::setLloc(int _lloc) { + m_lloc = _lloc; + } + + ListIterator Module::getObjectListIteratorBegin() const { + return ListIterator(&hasObjectContainer, factory, true); + } + + ListIterator Module::getObjectListIteratorEnd() const { + return ListIterator(&hasObjectContainer, factory, false); + } + + bool Module::getObjectIsEmpty() const { + return getObjectListIteratorBegin() == getObjectListIteratorEnd(); + } + + unsigned int Module::getObjectSize() const { + unsigned int size = 0; + ListIterator endIt = getObjectListIteratorEnd(); + for (ListIterator it = getObjectListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator Module::getStatementListIteratorBegin() const { + return ListIterator(&hasStatementContainer, factory, true); + } + + ListIterator Module::getStatementListIteratorEnd() const { + return ListIterator(&hasStatementContainer, factory, false); + } + + bool Module::getStatementIsEmpty() const { + return getStatementListIteratorBegin() == getStatementListIteratorEnd(); + } + + unsigned int Module::getStatementSize() const { + unsigned int size = 0; + ListIterator endIt = getStatementListIteratorEnd(); + for (ListIterator it = getStatementListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + base::Docstring* Module::getDocstring() const { + base::Docstring *_node = NULL; + if (m_docstring != 0) + _node = dynamic_cast(factory->getPointer(m_docstring)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Module::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkModule_HasObject: + addObject(edgeEnd); + return true; + case edkModule_HasStatement: + addStatement(edgeEnd); + return true; + case edkModule_Docstring: + setDocstring(edgeEnd); + return true; + default: + break; + } + if (base::Named::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Module::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkModule_HasObject: + removeObject(edgeEnd); + return true; + case edkModule_HasStatement: + removeStatement(edgeEnd); + return true; + case edkModule_Docstring: + removeDocstring(); + return true; + default: + break; + } + if (base::Named::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Module::addObject(const module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkObject) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasObjectContainer.push_back(_node->getId()); + setParentEdge(_node,edkModule_HasObject); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkModule_HasObject); + } + + void Module::addObject(NodeId _id) { + const module::Object *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addObject( node ); + } + + void Module::removeObject(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasObjectContainer.begin(), hasObjectContainer.end(), id); + + if (it == hasObjectContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasObjectContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkModule_HasObject); + } + + void Module::removeObject(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeObject(_node->getId()); + } + + void Module::addStatement(const base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsStatement(*_node) || Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasStatementContainer.push_back(_node->getId()); + setParentEdge(_node,edkModule_HasStatement); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkModule_HasStatement); + } + + void Module::addStatement(NodeId _id) { + const base::Positioned *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addStatement( node ); + } + + void Module::removeStatement(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasStatementContainer.begin(), hasStatementContainer.end(), id); + + if (it == hasStatementContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasStatementContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkModule_HasStatement); + } + + void Module::removeStatement(base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeStatement(_node->getId()); + } + + void Module::setDocstring(NodeId _id) { + base::Docstring *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_docstring) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_docstring, m_id, edkModule_Docstring); + } + m_docstring = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_docstring, this->getId(), edkModule_Docstring); + } else { + if (m_docstring) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Module::setDocstring(base::Docstring *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDocstring(_node->getId()); + } + + void Module::removeDocstring() { + if (m_docstring) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_docstring, m_id, edkModule_Docstring); + } + m_docstring = 0; + } + + void Module::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Module::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Module::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Module& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + if(node.getLloc() == getLloc()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Module::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType Module::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "module::Module", strlen("module::Module")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Module::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Named::save(binIo,false); + + binIo.writeUInt4(m_lloc); + + binIo.writeUInt4(m_docstring); + + + for (ListIterator::Container::const_iterator it = hasObjectContainer.begin(); it != hasObjectContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasStatementContainer.begin(); it != hasStatementContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Module::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Named::load(binIo,false); + + m_lloc = binIo.readUInt4(); + + m_docstring = binIo.readUInt4(); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasObjectContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkModule_HasObject); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasStatementContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkModule_HasStatement); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/module/Object.cpp b/lib/python/src/module/Object.cpp new file mode 100644 index 0000000..343cf4a --- /dev/null +++ b/lib/python/src/module/Object.cpp @@ -0,0 +1,346 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace module { + Object::Object(NodeId _id, Factory *_factory) : + Base(_id, _factory), + m_name(0), + refersToContainer(), + hasTypeContainer() + { + } + + Object::~Object() { + } + + void Object::prepareDelete(bool tryOnVirtualParent){ + while (!refersToContainer.empty()) { + const NodeId id = *refersToContainer.begin(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkObject_RefersTo); + refersToContainer.pop_front(); + } + while (!hasTypeContainer.empty()) { + const NodeId id = *hasTypeContainer.begin(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkObject_HasType); + hasTypeContainer.pop_front(); + } + base::Base::prepareDelete(false); + } + + NodeKind Object::getNodeKind() const { + return ndkObject; + } + + Key Object::getNameKey() const { + return m_name; + } + + const std::string& Object::getName() const { + return factory->getStringTable().get(m_name); + } + + void Object::setNameKey(Key _name) { + m_name = _name; + } + + void Object::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + ListIterator Object::getRefersToListIteratorBegin() const { + return ListIterator(&refersToContainer, factory, true); + } + + ListIterator Object::getRefersToListIteratorEnd() const { + return ListIterator(&refersToContainer, factory, false); + } + + bool Object::getRefersToIsEmpty() const { + return getRefersToListIteratorBegin() == getRefersToListIteratorEnd(); + } + + unsigned int Object::getRefersToSize() const { + unsigned int size = 0; + ListIterator endIt = getRefersToListIteratorEnd(); + for (ListIterator it = getRefersToListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator Object::getTypeListIteratorBegin() const { + return ListIterator(&hasTypeContainer, factory, true); + } + + ListIterator Object::getTypeListIteratorEnd() const { + return ListIterator(&hasTypeContainer, factory, false); + } + + bool Object::getTypeIsEmpty() const { + return getTypeListIteratorBegin() == getTypeListIteratorEnd(); + } + + unsigned int Object::getTypeSize() const { + unsigned int size = 0; + ListIterator endIt = getTypeListIteratorEnd(); + for (ListIterator it = getTypeListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Object::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkObject_RefersTo: + addRefersTo(edgeEnd); + return true; + case edkObject_HasType: + addType(edgeEnd); + return true; + default: + break; + } + if (base::Base::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Object::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkObject_RefersTo: + removeRefersTo(edgeEnd); + return true; + case edkObject_HasType: + removeType(edgeEnd); + return true; + default: + break; + } + if (base::Base::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Object::addRefersTo(const base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkClassDef) || (_node->getNodeKind() == ndkFunctionDef) || (_node->getNodeKind() == ndkModule) || (_node->getNodeKind() == ndkIdentifier) || (_node->getNodeKind() == ndkParameter) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + refersToContainer.push_back(_node->getId()); + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkObject_RefersTo); + } + + void Object::addRefersTo(NodeId _id) { + const base::Positioned *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addRefersTo( node ); + } + + void Object::removeRefersTo(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(refersToContainer.begin(), refersToContainer.end(), id); + + if (it == refersToContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + refersToContainer.erase(it); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkObject_RefersTo); + } + + void Object::removeRefersTo(base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeRefersTo(_node->getId()); + } + + void Object::addType(const type::Type *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsType(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasTypeContainer.push_back(_node->getId()); + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkObject_HasType); + } + + void Object::addType(NodeId _id) { + const type::Type *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addType( node ); + } + + void Object::removeType(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasTypeContainer.begin(), hasTypeContainer.end(), id); + + if (it == hasTypeContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasTypeContainer.erase(it); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkObject_HasType); + } + + void Object::removeType(type::Type *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeType(_node->getId()); + } + + void Object::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Object::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Object::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Object& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Object::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType Object::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "module::Object", strlen("module::Object")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Object::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Base::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + + + for (ListIterator::Container::const_iterator it = refersToContainer.begin(); it != refersToContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasTypeContainer.begin(); it != hasTypeContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Object::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Base::load(binIo,false); + + m_name = binIo.readUInt4(); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + refersToContainer.push_back(_id); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasTypeContainer.push_back(_id); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/module/Package.cpp b/lib/python/src/module/Package.cpp new file mode 100644 index 0000000..85ccfb9 --- /dev/null +++ b/lib/python/src/module/Package.cpp @@ -0,0 +1,393 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace module { + Package::Package(NodeId _id, Factory *_factory) : + Base(_id, _factory), + m_name(0), + m_path(0), + hasModuleContainer(), + hasPackageContainer() + { + } + + Package::~Package() { + } + + void Package::prepareDelete(bool tryOnVirtualParent){ + while (!hasModuleContainer.empty()) { + const NodeId id = *hasModuleContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkPackage_HasModule); + hasModuleContainer.pop_front(); + } + while (!hasPackageContainer.empty()) { + const NodeId id = *hasPackageContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkPackage_HasPackage); + hasPackageContainer.pop_front(); + } + base::Base::prepareDelete(false); + } + + NodeKind Package::getNodeKind() const { + return ndkPackage; + } + + Key Package::getNameKey() const { + return m_name; + } + + const std::string& Package::getName() const { + return factory->getStringTable().get(m_name); + } + + Key Package::getPathKey() const { + return m_path; + } + + const std::string& Package::getPath() const { + return factory->getStringTable().get(m_path); + } + + void Package::setNameKey(Key _name) { + m_name = _name; + } + + void Package::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + void Package::setPathKey(Key _path) { + m_path = _path; + } + + void Package::setPath(const std::string& _path) { + m_path = factory->getStringTable().set(_path); + } + + ListIterator Package::getModuleListIteratorBegin() const { + return ListIterator(&hasModuleContainer, factory, true); + } + + ListIterator Package::getModuleListIteratorEnd() const { + return ListIterator(&hasModuleContainer, factory, false); + } + + bool Package::getModuleIsEmpty() const { + return getModuleListIteratorBegin() == getModuleListIteratorEnd(); + } + + unsigned int Package::getModuleSize() const { + unsigned int size = 0; + ListIterator endIt = getModuleListIteratorEnd(); + for (ListIterator it = getModuleListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator Package::getPackageListIteratorBegin() const { + return ListIterator(&hasPackageContainer, factory, true); + } + + ListIterator Package::getPackageListIteratorEnd() const { + return ListIterator(&hasPackageContainer, factory, false); + } + + bool Package::getPackageIsEmpty() const { + return getPackageListIteratorBegin() == getPackageListIteratorEnd(); + } + + unsigned int Package::getPackageSize() const { + unsigned int size = 0; + ListIterator endIt = getPackageListIteratorEnd(); + for (ListIterator it = getPackageListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Package::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPackage_HasModule: + addModule(edgeEnd); + return true; + case edkPackage_HasPackage: + addPackage(edgeEnd); + return true; + default: + break; + } + if (base::Base::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Package::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPackage_HasModule: + removeModule(edgeEnd); + return true; + case edkPackage_HasPackage: + removePackage(edgeEnd); + return true; + default: + break; + } + if (base::Base::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Package::addModule(const module::Module *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkModule) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasModuleContainer.push_back(_node->getId()); + setParentEdge(_node,edkPackage_HasModule); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkPackage_HasModule); + } + + void Package::addModule(NodeId _id) { + const module::Module *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addModule( node ); + } + + void Package::removeModule(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasModuleContainer.begin(), hasModuleContainer.end(), id); + + if (it == hasModuleContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasModuleContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkPackage_HasModule); + } + + void Package::removeModule(module::Module *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeModule(_node->getId()); + } + + void Package::addPackage(const module::Package *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkPackage) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasPackageContainer.push_back(_node->getId()); + setParentEdge(_node,edkPackage_HasPackage); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkPackage_HasPackage); + } + + void Package::addPackage(NodeId _id) { + const module::Package *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addPackage( node ); + } + + void Package::removePackage(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasPackageContainer.begin(), hasPackageContainer.end(), id); + + if (it == hasPackageContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasPackageContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkPackage_HasPackage); + } + + void Package::removePackage(module::Package *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removePackage(_node->getId()); + } + + void Package::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Package::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Package::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Package& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + str1 = getPath(); + str2 = node.getPath(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Package::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + foundKeyId = oldAndNewStrKeyMap.find(m_path); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_path = foundKeyId->second; + } else { + Key oldkey = m_path; + m_path = newStrTable.set(factory->getStringTable().get(m_path)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_path)); } + + } + + NodeHashType Package::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "module::Package", strlen("module::Package")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Package::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Base::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + factory->getStringTable().setType(m_path, StrTable::strToSave); + binIo.writeUInt4(m_path); + + + for (ListIterator::Container::const_iterator it = hasModuleContainer.begin(); it != hasModuleContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasPackageContainer.begin(); it != hasPackageContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Package::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Base::load(binIo,false); + + m_name = binIo.readUInt4(); + m_path = binIo.readUInt4(); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasModuleContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkPackage_HasModule); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasPackageContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkPackage_HasPackage); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/python.cpp b/lib/python/src/python.cpp new file mode 100644 index 0000000..56c67cb --- /dev/null +++ b/lib/python/src/python.cpp @@ -0,0 +1,22 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + diff --git a/lib/python/src/statement/Alias.cpp b/lib/python/src/statement/Alias.cpp new file mode 100644 index 0000000..fb58a1a --- /dev/null +++ b/lib/python/src/statement/Alias.cpp @@ -0,0 +1,250 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Alias::Alias(NodeId _id, Factory *_factory) : + Named(_id, _factory), + m_alias(0), + m_refersTo(0) + { + } + + Alias::~Alias() { + } + + void Alias::prepareDelete(bool tryOnVirtualParent){ + removeRefersTo(); + base::Named::prepareDelete(false); + } + + NodeKind Alias::getNodeKind() const { + return ndkAlias; + } + + Key Alias::getAliasKey() const { + return m_alias; + } + + const std::string& Alias::getAlias() const { + return factory->getStringTable().get(m_alias); + } + + void Alias::setAliasKey(Key _alias) { + m_alias = _alias; + } + + void Alias::setAlias(const std::string& _alias) { + m_alias = factory->getStringTable().set(_alias); + } + + base::Base* Alias::getRefersTo() const { + base::Base *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Alias::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkAlias_RefersTo: + setRefersTo(edgeEnd); + return true; + default: + break; + } + if (base::Named::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Alias::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkAlias_RefersTo: + removeRefersTo(); + return true; + default: + break; + } + if (base::Named::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Alias::setRefersTo(NodeId _id) { + base::Base *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (_node->getNodeKind() == ndkModule || _node->getNodeKind() == ndkObject) { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkAlias_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkAlias_RefersTo); + } else { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Alias::setRefersTo(base::Base *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void Alias::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkAlias_RefersTo); + } + m_refersTo = 0; + } + + void Alias::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Alias::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Alias::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Alias& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + str1 = getAlias(); + str2 = node.getAlias(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Alias::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_alias); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_alias = foundKeyId->second; + } else { + Key oldkey = m_alias; + m_alias = newStrTable.set(factory->getStringTable().get(m_alias)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_alias)); } + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType Alias::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Alias", strlen("statement::Alias")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Alias::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Named::save(binIo,false); + + factory->getStringTable().setType(m_alias, StrTable::strToSave); + binIo.writeUInt4(m_alias); + + binIo.writeUInt4(m_refersTo); + + } + + void Alias::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Named::load(binIo,false); + + m_alias = binIo.readUInt4(); + + m_refersTo = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Assert.cpp b/lib/python/src/statement/Assert.cpp new file mode 100644 index 0000000..0013ec8 --- /dev/null +++ b/lib/python/src/statement/Assert.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Assert::Assert(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_hasMsgExpression(0), + m_hasTestExpression(0) + { + } + + Assert::~Assert() { + } + + void Assert::prepareDelete(bool tryOnVirtualParent){ + removeMsgExpression(); + removeTestExpression(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Assert::getNodeKind() const { + return ndkAssert; + } + + expression::Expression* Assert::getMsgExpression() const { + expression::Expression *_node = NULL; + if (m_hasMsgExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasMsgExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Assert::getTestExpression() const { + expression::Expression *_node = NULL; + if (m_hasTestExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasTestExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Assert::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkAssert_HasMsgExpression: + setMsgExpression(edgeEnd); + return true; + case edkAssert_HasTestExpression: + setTestExpression(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Assert::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkAssert_HasMsgExpression: + removeMsgExpression(); + return true; + case edkAssert_HasTestExpression: + removeTestExpression(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Assert::setMsgExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasMsgExpression) { + removeParentEdge(m_hasMsgExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasMsgExpression, m_id, edkAssert_HasMsgExpression); + } + m_hasMsgExpression = _node->getId(); + if (m_hasMsgExpression != 0) + setParentEdge(factory->getPointer(m_hasMsgExpression), edkAssert_HasMsgExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasMsgExpression, this->getId(), edkAssert_HasMsgExpression); + } else { + if (m_hasMsgExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Assert::setMsgExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setMsgExpression(_node->getId()); + } + + void Assert::removeMsgExpression() { + if (m_hasMsgExpression) { + removeParentEdge(m_hasMsgExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasMsgExpression, m_id, edkAssert_HasMsgExpression); + } + m_hasMsgExpression = 0; + } + + void Assert::setTestExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTestExpression) { + removeParentEdge(m_hasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTestExpression, m_id, edkAssert_HasTestExpression); + } + m_hasTestExpression = _node->getId(); + if (m_hasTestExpression != 0) + setParentEdge(factory->getPointer(m_hasTestExpression), edkAssert_HasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTestExpression, this->getId(), edkAssert_HasTestExpression); + } else { + if (m_hasTestExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Assert::setTestExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTestExpression(_node->getId()); + } + + void Assert::removeTestExpression() { + if (m_hasTestExpression) { + removeParentEdge(m_hasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTestExpression, m_id, edkAssert_HasTestExpression); + } + m_hasTestExpression = 0; + } + + void Assert::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Assert::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Assert::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Assert::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Assert::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Assert", strlen("statement::Assert")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Assert::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + binIo.writeUInt4(m_hasMsgExpression); + binIo.writeUInt4(m_hasTestExpression); + + } + + void Assert::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + m_hasMsgExpression = binIo.readUInt4(); + if (m_hasMsgExpression != 0) + setParentEdge(factory->getPointer(m_hasMsgExpression),edkAssert_HasMsgExpression); + + m_hasTestExpression = binIo.readUInt4(); + if (m_hasTestExpression != 0) + setParentEdge(factory->getPointer(m_hasTestExpression),edkAssert_HasTestExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Assign.cpp b/lib/python/src/statement/Assign.cpp new file mode 100644 index 0000000..6cc7c34 --- /dev/null +++ b/lib/python/src/statement/Assign.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Assign::Assign(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_hasExpression(0), + m_hasTargetList(0) + { + } + + Assign::~Assign() { + } + + void Assign::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + removeTargetList(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Assign::getNodeKind() const { + return ndkAssign; + } + + expression::Expression* Assign::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + statement::TargetList* Assign::getTargetList() const { + statement::TargetList *_node = NULL; + if (m_hasTargetList != 0) + _node = dynamic_cast(factory->getPointer(m_hasTargetList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Assign::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkAssign_HasExpression: + setExpression(edgeEnd); + return true; + case edkAssign_HasTargetList: + setTargetList(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Assign::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkAssign_HasExpression: + removeExpression(); + return true; + case edkAssign_HasTargetList: + removeTargetList(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Assign::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkAssign_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkAssign_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkAssign_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Assign::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void Assign::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkAssign_HasExpression); + } + m_hasExpression = 0; + } + + void Assign::setTargetList(NodeId _id) { + statement::TargetList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkAssign_HasTargetList); + } + m_hasTargetList = _node->getId(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList), edkAssign_HasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTargetList, this->getId(), edkAssign_HasTargetList); + } else { + if (m_hasTargetList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Assign::setTargetList(statement::TargetList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTargetList(_node->getId()); + } + + void Assign::removeTargetList() { + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkAssign_HasTargetList); + } + m_hasTargetList = 0; + } + + void Assign::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Assign::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Assign::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Assign::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Assign::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Assign", strlen("statement::Assign")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Assign::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + binIo.writeUInt4(m_hasTargetList); + + } + + void Assign::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkAssign_HasExpression); + + m_hasTargetList = binIo.readUInt4(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList),edkAssign_HasTargetList); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/AugAssign.cpp b/lib/python/src/statement/AugAssign.cpp new file mode 100644 index 0000000..8d78079 --- /dev/null +++ b/lib/python/src/statement/AugAssign.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + AugAssign::AugAssign(NodeId _id, Factory *_factory) : + Assign(_id, _factory), + m_kind(askAdd) + { + } + + AugAssign::~AugAssign() { + } + + void AugAssign::prepareDelete(bool tryOnVirtualParent){ + statement::Assign::prepareDelete(false); + } + + NodeKind AugAssign::getNodeKind() const { + return ndkAugAssign; + } + + AssignmentKind AugAssign::getKind() const { + return m_kind; + } + + void AugAssign::setKind(AssignmentKind _kind) { + m_kind = _kind; + } + + bool AugAssign::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::Assign::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool AugAssign::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::Assign::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void AugAssign::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void AugAssign::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double AugAssign::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const AugAssign& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void AugAssign::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType AugAssign::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::AugAssign", strlen("statement::AugAssign")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void AugAssign::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Assign::save(binIo,false); + + binIo.writeUByte1(m_kind); + + } + + void AugAssign::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Assign::load(binIo,false); + + m_kind = (AssignmentKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/BaseSpecifier.cpp b/lib/python/src/statement/BaseSpecifier.cpp new file mode 100644 index 0000000..7df7871 --- /dev/null +++ b/lib/python/src/statement/BaseSpecifier.cpp @@ -0,0 +1,258 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + BaseSpecifier::BaseSpecifier(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + m_hasName(0), + m_derivesFrom(0) + { + } + + BaseSpecifier::~BaseSpecifier() { + } + + void BaseSpecifier::prepareDelete(bool tryOnVirtualParent){ + removeName(); + removeDerivesFrom(); + base::Positioned::prepareDelete(false); + } + + NodeKind BaseSpecifier::getNodeKind() const { + return ndkBaseSpecifier; + } + + expression::Expression* BaseSpecifier::getName() const { + expression::Expression *_node = NULL; + if (m_hasName != 0) + _node = dynamic_cast(factory->getPointer(m_hasName)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + statement::ClassDef* BaseSpecifier::getDerivesFrom() const { + statement::ClassDef *_node = NULL; + if (m_derivesFrom != 0) + _node = dynamic_cast(factory->getPointer(m_derivesFrom)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool BaseSpecifier::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkBaseSpecifier_HasName: + setName(edgeEnd); + return true; + case edkBaseSpecifier_DerivesFrom: + setDerivesFrom(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool BaseSpecifier::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkBaseSpecifier_HasName: + removeName(); + return true; + case edkBaseSpecifier_DerivesFrom: + removeDerivesFrom(); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void BaseSpecifier::setName(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasName) { + removeParentEdge(m_hasName); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasName, m_id, edkBaseSpecifier_HasName); + } + m_hasName = _node->getId(); + if (m_hasName != 0) + setParentEdge(factory->getPointer(m_hasName), edkBaseSpecifier_HasName); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasName, this->getId(), edkBaseSpecifier_HasName); + } else { + if (m_hasName) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void BaseSpecifier::setName(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setName(_node->getId()); + } + + void BaseSpecifier::removeName() { + if (m_hasName) { + removeParentEdge(m_hasName); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasName, m_id, edkBaseSpecifier_HasName); + } + m_hasName = 0; + } + + void BaseSpecifier::setDerivesFrom(NodeId _id) { + statement::ClassDef *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_derivesFrom) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_derivesFrom, m_id, edkBaseSpecifier_DerivesFrom); + } + m_derivesFrom = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_derivesFrom, this->getId(), edkBaseSpecifier_DerivesFrom); + } else { + if (m_derivesFrom) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void BaseSpecifier::setDerivesFrom(statement::ClassDef *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDerivesFrom(_node->getId()); + } + + void BaseSpecifier::removeDerivesFrom() { + if (m_derivesFrom) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_derivesFrom, m_id, edkBaseSpecifier_DerivesFrom); + } + m_derivesFrom = 0; + } + + void BaseSpecifier::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void BaseSpecifier::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double BaseSpecifier::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void BaseSpecifier::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType BaseSpecifier::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::BaseSpecifier", strlen("statement::BaseSpecifier")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void BaseSpecifier::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + binIo.writeUInt4(m_hasName); + binIo.writeUInt4(m_derivesFrom); + + } + + void BaseSpecifier::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + m_hasName = binIo.readUInt4(); + if (m_hasName != 0) + setParentEdge(factory->getPointer(m_hasName),edkBaseSpecifier_HasName); + + m_derivesFrom = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Break.cpp b/lib/python/src/statement/Break.cpp new file mode 100644 index 0000000..1a4fa80 --- /dev/null +++ b/lib/python/src/statement/Break.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Break::Break(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory) + { + } + + Break::~Break() { + } + + void Break::prepareDelete(bool tryOnVirtualParent){ + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Break::getNodeKind() const { + return ndkBreak; + } + + bool Break::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Break::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Break::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Break::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Break::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Break::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Break::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Break", strlen("statement::Break")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Break::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + } + + void Break::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/ClassDef.cpp b/lib/python/src/statement/ClassDef.cpp new file mode 100644 index 0000000..960ddba --- /dev/null +++ b/lib/python/src/statement/ClassDef.cpp @@ -0,0 +1,592 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + ClassDef::ClassDef(NodeId _id, Factory *_factory) : + CompoundStatement(_id, _factory), + m_lloc(0), + m_name(0), + hasObjectContainer(), + hasBaseSpecifierContainer(), + hasDecoratorContainer(), + m_refersTo(0), + m_docstring(0) + { + } + + ClassDef::~ClassDef() { + } + + void ClassDef::prepareDelete(bool tryOnVirtualParent){ + while (!hasObjectContainer.empty()) { + const NodeId id = *hasObjectContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkClassDef_HasObject); + hasObjectContainer.pop_front(); + } + while (!hasBaseSpecifierContainer.empty()) { + const NodeId id = *hasBaseSpecifierContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkClassDef_HasBaseSpecifier); + hasBaseSpecifierContainer.pop_front(); + } + while (!hasDecoratorContainer.empty()) { + const NodeId id = *hasDecoratorContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkClassDef_HasDecorator); + hasDecoratorContainer.pop_front(); + } + removeRefersTo(); + removeDocstring(); + statement::CompoundStatement::prepareDelete(false); + } + + NodeKind ClassDef::getNodeKind() const { + return ndkClassDef; + } + + Key ClassDef::getNameKey() const { + return m_name; + } + + const std::string& ClassDef::getName() const { + return factory->getStringTable().get(m_name); + } + + int ClassDef::getLloc() const { + return m_lloc; + } + + void ClassDef::setNameKey(Key _name) { + m_name = _name; + } + + void ClassDef::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + void ClassDef::setLloc(int _lloc) { + m_lloc = _lloc; + } + + ListIterator ClassDef::getObjectListIteratorBegin() const { + return ListIterator(&hasObjectContainer, factory, true); + } + + ListIterator ClassDef::getObjectListIteratorEnd() const { + return ListIterator(&hasObjectContainer, factory, false); + } + + bool ClassDef::getObjectIsEmpty() const { + return getObjectListIteratorBegin() == getObjectListIteratorEnd(); + } + + unsigned int ClassDef::getObjectSize() const { + unsigned int size = 0; + ListIterator endIt = getObjectListIteratorEnd(); + for (ListIterator it = getObjectListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator ClassDef::getBaseSpecifierListIteratorBegin() const { + return ListIterator(&hasBaseSpecifierContainer, factory, true); + } + + ListIterator ClassDef::getBaseSpecifierListIteratorEnd() const { + return ListIterator(&hasBaseSpecifierContainer, factory, false); + } + + bool ClassDef::getBaseSpecifierIsEmpty() const { + return getBaseSpecifierListIteratorBegin() == getBaseSpecifierListIteratorEnd(); + } + + unsigned int ClassDef::getBaseSpecifierSize() const { + unsigned int size = 0; + ListIterator endIt = getBaseSpecifierListIteratorEnd(); + for (ListIterator it = getBaseSpecifierListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator ClassDef::getDecoratorListIteratorBegin() const { + return ListIterator(&hasDecoratorContainer, factory, true); + } + + ListIterator ClassDef::getDecoratorListIteratorEnd() const { + return ListIterator(&hasDecoratorContainer, factory, false); + } + + bool ClassDef::getDecoratorIsEmpty() const { + return getDecoratorListIteratorBegin() == getDecoratorListIteratorEnd(); + } + + unsigned int ClassDef::getDecoratorSize() const { + unsigned int size = 0; + ListIterator endIt = getDecoratorListIteratorEnd(); + for (ListIterator it = getDecoratorListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + module::Object* ClassDef::getRefersTo() const { + module::Object *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + base::Docstring* ClassDef::getDocstring() const { + base::Docstring *_node = NULL; + if (m_docstring != 0) + _node = dynamic_cast(factory->getPointer(m_docstring)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool ClassDef::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkClassDef_HasObject: + addObject(edgeEnd); + return true; + case edkClassDef_HasBaseSpecifier: + addBaseSpecifier(edgeEnd); + return true; + case edkClassDef_HasDecorator: + addDecorator(edgeEnd); + return true; + case edkClassDef_RefersTo: + setRefersTo(edgeEnd); + return true; + case edkClassDef_Docstring: + setDocstring(edgeEnd); + return true; + default: + break; + } + if (statement::CompoundStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ClassDef::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkClassDef_HasObject: + removeObject(edgeEnd); + return true; + case edkClassDef_HasBaseSpecifier: + removeBaseSpecifier(edgeEnd); + return true; + case edkClassDef_HasDecorator: + removeDecorator(edgeEnd); + return true; + case edkClassDef_RefersTo: + removeRefersTo(); + return true; + case edkClassDef_Docstring: + removeDocstring(); + return true; + default: + break; + } + if (statement::CompoundStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ClassDef::addObject(const module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkObject) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasObjectContainer.push_back(_node->getId()); + setParentEdge(_node,edkClassDef_HasObject); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkClassDef_HasObject); + } + + void ClassDef::addObject(NodeId _id) { + const module::Object *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addObject( node ); + } + + void ClassDef::removeObject(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasObjectContainer.begin(), hasObjectContainer.end(), id); + + if (it == hasObjectContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasObjectContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkClassDef_HasObject); + } + + void ClassDef::removeObject(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeObject(_node->getId()); + } + + void ClassDef::addBaseSpecifier(const statement::BaseSpecifier *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkBaseSpecifier) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasBaseSpecifierContainer.push_back(_node->getId()); + setParentEdge(_node,edkClassDef_HasBaseSpecifier); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkClassDef_HasBaseSpecifier); + } + + void ClassDef::addBaseSpecifier(NodeId _id) { + const statement::BaseSpecifier *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addBaseSpecifier( node ); + } + + void ClassDef::removeBaseSpecifier(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasBaseSpecifierContainer.begin(), hasBaseSpecifierContainer.end(), id); + + if (it == hasBaseSpecifierContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasBaseSpecifierContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkClassDef_HasBaseSpecifier); + } + + void ClassDef::removeBaseSpecifier(statement::BaseSpecifier *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeBaseSpecifier(_node->getId()); + } + + void ClassDef::addDecorator(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasDecoratorContainer.push_back(_node->getId()); + setParentEdge(_node,edkClassDef_HasDecorator); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkClassDef_HasDecorator); + } + + void ClassDef::addDecorator(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addDecorator( node ); + } + + void ClassDef::removeDecorator(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasDecoratorContainer.begin(), hasDecoratorContainer.end(), id); + + if (it == hasDecoratorContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasDecoratorContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkClassDef_HasDecorator); + } + + void ClassDef::removeDecorator(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeDecorator(_node->getId()); + } + + void ClassDef::setRefersTo(NodeId _id) { + module::Object *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkClassDef_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkClassDef_RefersTo); + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ClassDef::setRefersTo(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void ClassDef::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkClassDef_RefersTo); + } + m_refersTo = 0; + } + + void ClassDef::setDocstring(NodeId _id) { + base::Docstring *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_docstring) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_docstring, m_id, edkClassDef_Docstring); + } + m_docstring = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_docstring, this->getId(), edkClassDef_Docstring); + } else { + if (m_docstring) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ClassDef::setDocstring(base::Docstring *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDocstring(_node->getId()); + } + + void ClassDef::removeDocstring() { + if (m_docstring) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_docstring, m_id, edkClassDef_Docstring); + } + m_docstring = 0; + } + + void ClassDef::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ClassDef::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ClassDef::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const ClassDef& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + if(node.getLloc() == getLloc()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void ClassDef::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType ClassDef::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::ClassDef", strlen("statement::ClassDef")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ClassDef::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + CompoundStatement::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + binIo.writeUInt4(m_lloc); + + binIo.writeUInt4(m_refersTo); + binIo.writeUInt4(m_docstring); + + + for (ListIterator::Container::const_iterator it = hasObjectContainer.begin(); it != hasObjectContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasBaseSpecifierContainer.begin(); it != hasBaseSpecifierContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasDecoratorContainer.begin(); it != hasDecoratorContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void ClassDef::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + CompoundStatement::load(binIo,false); + + m_name = binIo.readUInt4(); + m_lloc = binIo.readUInt4(); + + m_refersTo = binIo.readUInt4(); + + m_docstring = binIo.readUInt4(); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasObjectContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkClassDef_HasObject); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasBaseSpecifierContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkClassDef_HasBaseSpecifier); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasDecoratorContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkClassDef_HasDecorator); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/CompoundStatement.cpp b/lib/python/src/statement/CompoundStatement.cpp new file mode 100644 index 0000000..f54eee2 --- /dev/null +++ b/lib/python/src/statement/CompoundStatement.cpp @@ -0,0 +1,183 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + CompoundStatement::CompoundStatement(NodeId _id, Factory *_factory) : + Statement(_id, _factory), + m_hasBody(0) + { + } + + CompoundStatement::~CompoundStatement() { + } + + void CompoundStatement::prepareDelete(bool tryOnVirtualParent){ + removeBody(); + statement::Statement::prepareDelete(false); + } + + statement::Suite* CompoundStatement::getBody() const { + statement::Suite *_node = NULL; + if (m_hasBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool CompoundStatement::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkCompoundStatement_HasBody: + setBody(edgeEnd); + return true; + default: + break; + } + if (statement::Statement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool CompoundStatement::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkCompoundStatement_HasBody: + removeBody(); + return true; + default: + break; + } + if (statement::Statement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void CompoundStatement::setBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasBody) { + removeParentEdge(m_hasBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasBody, m_id, edkCompoundStatement_HasBody); + } + m_hasBody = _node->getId(); + if (m_hasBody != 0) + setParentEdge(factory->getPointer(m_hasBody), edkCompoundStatement_HasBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasBody, this->getId(), edkCompoundStatement_HasBody); + } else { + if (m_hasBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void CompoundStatement::setBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setBody(_node->getId()); + } + + void CompoundStatement::removeBody() { + if (m_hasBody) { + removeParentEdge(m_hasBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasBody, m_id, edkCompoundStatement_HasBody); + } + m_hasBody = 0; + } + + double CompoundStatement::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void CompoundStatement::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType CompoundStatement::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::CompoundStatement", strlen("statement::CompoundStatement")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void CompoundStatement::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Statement::save(binIo,false); + + binIo.writeUInt4(m_hasBody); + + } + + void CompoundStatement::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Statement::load(binIo,false); + + m_hasBody = binIo.readUInt4(); + if (m_hasBody != 0) + setParentEdge(factory->getPointer(m_hasBody),edkCompoundStatement_HasBody); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Continue.cpp b/lib/python/src/statement/Continue.cpp new file mode 100644 index 0000000..0c4225c --- /dev/null +++ b/lib/python/src/statement/Continue.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Continue::Continue(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory) + { + } + + Continue::~Continue() { + } + + void Continue::prepareDelete(bool tryOnVirtualParent){ + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Continue::getNodeKind() const { + return ndkContinue; + } + + bool Continue::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Continue::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Continue::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Continue::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Continue::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Continue::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Continue::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Continue", strlen("statement::Continue")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Continue::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + } + + void Continue::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Delete.cpp b/lib/python/src/statement/Delete.cpp new file mode 100644 index 0000000..90669ef --- /dev/null +++ b/lib/python/src/statement/Delete.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Delete::Delete(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_hasTargetList(0) + { + } + + Delete::~Delete() { + } + + void Delete::prepareDelete(bool tryOnVirtualParent){ + removeTargetList(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Delete::getNodeKind() const { + return ndkDelete; + } + + statement::TargetList* Delete::getTargetList() const { + statement::TargetList *_node = NULL; + if (m_hasTargetList != 0) + _node = dynamic_cast(factory->getPointer(m_hasTargetList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Delete::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkDelete_HasTargetList: + setTargetList(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Delete::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkDelete_HasTargetList: + removeTargetList(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Delete::setTargetList(NodeId _id) { + statement::TargetList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkDelete_HasTargetList); + } + m_hasTargetList = _node->getId(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList), edkDelete_HasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTargetList, this->getId(), edkDelete_HasTargetList); + } else { + if (m_hasTargetList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Delete::setTargetList(statement::TargetList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTargetList(_node->getId()); + } + + void Delete::removeTargetList() { + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkDelete_HasTargetList); + } + m_hasTargetList = 0; + } + + void Delete::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Delete::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Delete::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Delete::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Delete::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Delete", strlen("statement::Delete")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Delete::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + binIo.writeUInt4(m_hasTargetList); + + } + + void Delete::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + m_hasTargetList = binIo.readUInt4(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList),edkDelete_HasTargetList); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Exec.cpp b/lib/python/src/statement/Exec.cpp new file mode 100644 index 0000000..11db720 --- /dev/null +++ b/lib/python/src/statement/Exec.cpp @@ -0,0 +1,333 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Exec::Exec(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_hasExpression(0), + m_hasGlobals(0), + m_hasLocals(0) + { + } + + Exec::~Exec() { + } + + void Exec::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + removeGlobals(); + removeLocals(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Exec::getNodeKind() const { + return ndkExec; + } + + expression::Expression* Exec::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Exec::getGlobals() const { + expression::Expression *_node = NULL; + if (m_hasGlobals != 0) + _node = dynamic_cast(factory->getPointer(m_hasGlobals)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Exec::getLocals() const { + expression::Expression *_node = NULL; + if (m_hasLocals != 0) + _node = dynamic_cast(factory->getPointer(m_hasLocals)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Exec::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExec_HasExpression: + setExpression(edgeEnd); + return true; + case edkExec_HasGlobals: + setGlobals(edgeEnd); + return true; + case edkExec_HasLocals: + setLocals(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Exec::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkExec_HasExpression: + removeExpression(); + return true; + case edkExec_HasGlobals: + removeGlobals(); + return true; + case edkExec_HasLocals: + removeLocals(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Exec::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkExec_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkExec_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkExec_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Exec::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void Exec::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkExec_HasExpression); + } + m_hasExpression = 0; + } + + void Exec::setGlobals(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasGlobals) { + removeParentEdge(m_hasGlobals); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasGlobals, m_id, edkExec_HasGlobals); + } + m_hasGlobals = _node->getId(); + if (m_hasGlobals != 0) + setParentEdge(factory->getPointer(m_hasGlobals), edkExec_HasGlobals); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasGlobals, this->getId(), edkExec_HasGlobals); + } else { + if (m_hasGlobals) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Exec::setGlobals(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setGlobals(_node->getId()); + } + + void Exec::removeGlobals() { + if (m_hasGlobals) { + removeParentEdge(m_hasGlobals); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasGlobals, m_id, edkExec_HasGlobals); + } + m_hasGlobals = 0; + } + + void Exec::setLocals(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasLocals) { + removeParentEdge(m_hasLocals); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLocals, m_id, edkExec_HasLocals); + } + m_hasLocals = _node->getId(); + if (m_hasLocals != 0) + setParentEdge(factory->getPointer(m_hasLocals), edkExec_HasLocals); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasLocals, this->getId(), edkExec_HasLocals); + } else { + if (m_hasLocals) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Exec::setLocals(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setLocals(_node->getId()); + } + + void Exec::removeLocals() { + if (m_hasLocals) { + removeParentEdge(m_hasLocals); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasLocals, m_id, edkExec_HasLocals); + } + m_hasLocals = 0; + } + + void Exec::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Exec::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Exec::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Exec::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Exec::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Exec", strlen("statement::Exec")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Exec::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + binIo.writeUInt4(m_hasGlobals); + binIo.writeUInt4(m_hasLocals); + + } + + void Exec::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkExec_HasExpression); + + m_hasGlobals = binIo.readUInt4(); + if (m_hasGlobals != 0) + setParentEdge(factory->getPointer(m_hasGlobals),edkExec_HasGlobals); + + m_hasLocals = binIo.readUInt4(); + if (m_hasLocals != 0) + setParentEdge(factory->getPointer(m_hasLocals),edkExec_HasLocals); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/For.cpp b/lib/python/src/statement/For.cpp new file mode 100644 index 0000000..6654842 --- /dev/null +++ b/lib/python/src/statement/For.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + For::For(NodeId _id, Factory *_factory) : + Iteration(_id, _factory), + m_hasExpressionList(0), + m_hasTargetList(0) + { + } + + For::~For() { + } + + void For::prepareDelete(bool tryOnVirtualParent){ + removeExpressionList(); + removeTargetList(); + statement::Iteration::prepareDelete(false); + } + + NodeKind For::getNodeKind() const { + return ndkFor; + } + + expression::ExpressionList* For::getExpressionList() const { + expression::ExpressionList *_node = NULL; + if (m_hasExpressionList != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpressionList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + statement::TargetList* For::getTargetList() const { + statement::TargetList *_node = NULL; + if (m_hasTargetList != 0) + _node = dynamic_cast(factory->getPointer(m_hasTargetList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool For::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkFor_HasExpressionList: + setExpressionList(edgeEnd); + return true; + case edkFor_HasTargetList: + setTargetList(edgeEnd); + return true; + default: + break; + } + if (statement::Iteration::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool For::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkFor_HasExpressionList: + removeExpressionList(); + return true; + case edkFor_HasTargetList: + removeTargetList(); + return true; + default: + break; + } + if (statement::Iteration::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void For::setExpressionList(NodeId _id) { + expression::ExpressionList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpressionList) { + removeParentEdge(m_hasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpressionList, m_id, edkFor_HasExpressionList); + } + m_hasExpressionList = _node->getId(); + if (m_hasExpressionList != 0) + setParentEdge(factory->getPointer(m_hasExpressionList), edkFor_HasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpressionList, this->getId(), edkFor_HasExpressionList); + } else { + if (m_hasExpressionList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void For::setExpressionList(expression::ExpressionList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpressionList(_node->getId()); + } + + void For::removeExpressionList() { + if (m_hasExpressionList) { + removeParentEdge(m_hasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpressionList, m_id, edkFor_HasExpressionList); + } + m_hasExpressionList = 0; + } + + void For::setTargetList(NodeId _id) { + statement::TargetList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkFor_HasTargetList); + } + m_hasTargetList = _node->getId(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList), edkFor_HasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTargetList, this->getId(), edkFor_HasTargetList); + } else { + if (m_hasTargetList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void For::setTargetList(statement::TargetList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTargetList(_node->getId()); + } + + void For::removeTargetList() { + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkFor_HasTargetList); + } + m_hasTargetList = 0; + } + + void For::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void For::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double For::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void For::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType For::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::For", strlen("statement::For")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void For::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Iteration::save(binIo,false); + + binIo.writeUInt4(m_hasExpressionList); + binIo.writeUInt4(m_hasTargetList); + + } + + void For::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Iteration::load(binIo,false); + + m_hasExpressionList = binIo.readUInt4(); + if (m_hasExpressionList != 0) + setParentEdge(factory->getPointer(m_hasExpressionList),edkFor_HasExpressionList); + + m_hasTargetList = binIo.readUInt4(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList),edkFor_HasTargetList); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/FunctionDef.cpp b/lib/python/src/statement/FunctionDef.cpp new file mode 100644 index 0000000..c607daf --- /dev/null +++ b/lib/python/src/statement/FunctionDef.cpp @@ -0,0 +1,655 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + FunctionDef::FunctionDef(NodeId _id, Factory *_factory) : + CompoundStatement(_id, _factory), + m_lloc(0), + m_name(0), + hasDecoratorContainer(), + hasObjectContainer(), + hasParameterContainer(), + m_refersTo(0), + m_returnType(0), + m_docstring(0) + { + } + + FunctionDef::~FunctionDef() { + } + + void FunctionDef::prepareDelete(bool tryOnVirtualParent){ + while (!hasDecoratorContainer.empty()) { + const NodeId id = *hasDecoratorContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkFunctionDef_HasDecorator); + hasDecoratorContainer.pop_front(); + } + while (!hasObjectContainer.empty()) { + const NodeId id = *hasObjectContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkFunctionDef_HasObject); + hasObjectContainer.pop_front(); + } + while (!hasParameterContainer.empty()) { + const NodeId id = *hasParameterContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkFunctionDef_HasParameter); + hasParameterContainer.pop_front(); + } + removeRefersTo(); + removeReturnType(); + removeDocstring(); + statement::CompoundStatement::prepareDelete(false); + } + + NodeKind FunctionDef::getNodeKind() const { + return ndkFunctionDef; + } + + Key FunctionDef::getNameKey() const { + return m_name; + } + + const std::string& FunctionDef::getName() const { + return factory->getStringTable().get(m_name); + } + + int FunctionDef::getLloc() const { + return m_lloc; + } + + void FunctionDef::setNameKey(Key _name) { + m_name = _name; + } + + void FunctionDef::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + void FunctionDef::setLloc(int _lloc) { + m_lloc = _lloc; + } + + ListIterator FunctionDef::getDecoratorListIteratorBegin() const { + return ListIterator(&hasDecoratorContainer, factory, true); + } + + ListIterator FunctionDef::getDecoratorListIteratorEnd() const { + return ListIterator(&hasDecoratorContainer, factory, false); + } + + bool FunctionDef::getDecoratorIsEmpty() const { + return getDecoratorListIteratorBegin() == getDecoratorListIteratorEnd(); + } + + unsigned int FunctionDef::getDecoratorSize() const { + unsigned int size = 0; + ListIterator endIt = getDecoratorListIteratorEnd(); + for (ListIterator it = getDecoratorListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator FunctionDef::getObjectListIteratorBegin() const { + return ListIterator(&hasObjectContainer, factory, true); + } + + ListIterator FunctionDef::getObjectListIteratorEnd() const { + return ListIterator(&hasObjectContainer, factory, false); + } + + bool FunctionDef::getObjectIsEmpty() const { + return getObjectListIteratorBegin() == getObjectListIteratorEnd(); + } + + unsigned int FunctionDef::getObjectSize() const { + unsigned int size = 0; + ListIterator endIt = getObjectListIteratorEnd(); + for (ListIterator it = getObjectListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + ListIterator FunctionDef::getParameterListIteratorBegin() const { + return ListIterator(&hasParameterContainer, factory, true); + } + + ListIterator FunctionDef::getParameterListIteratorEnd() const { + return ListIterator(&hasParameterContainer, factory, false); + } + + bool FunctionDef::getParameterIsEmpty() const { + return getParameterListIteratorBegin() == getParameterListIteratorEnd(); + } + + unsigned int FunctionDef::getParameterSize() const { + unsigned int size = 0; + ListIterator endIt = getParameterListIteratorEnd(); + for (ListIterator it = getParameterListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + module::Object* FunctionDef::getRefersTo() const { + module::Object *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + type::Type* FunctionDef::getReturnType() const { + type::Type *_node = NULL; + if (m_returnType != 0) + _node = dynamic_cast(factory->getPointer(m_returnType)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + base::Docstring* FunctionDef::getDocstring() const { + base::Docstring *_node = NULL; + if (m_docstring != 0) + _node = dynamic_cast(factory->getPointer(m_docstring)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool FunctionDef::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkFunctionDef_HasDecorator: + addDecorator(edgeEnd); + return true; + case edkFunctionDef_HasObject: + addObject(edgeEnd); + return true; + case edkFunctionDef_HasParameter: + addParameter(edgeEnd); + return true; + case edkFunctionDef_RefersTo: + setRefersTo(edgeEnd); + return true; + case edkFunctionDef_ReturnType: + setReturnType(edgeEnd); + return true; + case edkFunctionDef_Docstring: + setDocstring(edgeEnd); + return true; + default: + break; + } + if (statement::CompoundStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool FunctionDef::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkFunctionDef_HasDecorator: + removeDecorator(edgeEnd); + return true; + case edkFunctionDef_HasObject: + removeObject(edgeEnd); + return true; + case edkFunctionDef_HasParameter: + removeParameter(edgeEnd); + return true; + case edkFunctionDef_RefersTo: + removeRefersTo(); + return true; + case edkFunctionDef_ReturnType: + removeReturnType(); + return true; + case edkFunctionDef_Docstring: + removeDocstring(); + return true; + default: + break; + } + if (statement::CompoundStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void FunctionDef::addDecorator(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasDecoratorContainer.push_back(_node->getId()); + setParentEdge(_node,edkFunctionDef_HasDecorator); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkFunctionDef_HasDecorator); + } + + void FunctionDef::addDecorator(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addDecorator( node ); + } + + void FunctionDef::removeDecorator(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasDecoratorContainer.begin(), hasDecoratorContainer.end(), id); + + if (it == hasDecoratorContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasDecoratorContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkFunctionDef_HasDecorator); + } + + void FunctionDef::removeDecorator(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeDecorator(_node->getId()); + } + + void FunctionDef::addObject(const module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkObject) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasObjectContainer.push_back(_node->getId()); + setParentEdge(_node,edkFunctionDef_HasObject); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkFunctionDef_HasObject); + } + + void FunctionDef::addObject(NodeId _id) { + const module::Object *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addObject( node ); + } + + void FunctionDef::removeObject(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasObjectContainer.begin(), hasObjectContainer.end(), id); + + if (it == hasObjectContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasObjectContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkFunctionDef_HasObject); + } + + void FunctionDef::removeObject(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeObject(_node->getId()); + } + + void FunctionDef::addParameter(const statement::Parameter *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkParameter) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasParameterContainer.push_back(_node->getId()); + setParentEdge(_node,edkFunctionDef_HasParameter); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkFunctionDef_HasParameter); + } + + void FunctionDef::addParameter(NodeId _id) { + const statement::Parameter *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addParameter( node ); + } + + void FunctionDef::removeParameter(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasParameterContainer.begin(), hasParameterContainer.end(), id); + + if (it == hasParameterContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasParameterContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkFunctionDef_HasParameter); + } + + void FunctionDef::removeParameter(statement::Parameter *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeParameter(_node->getId()); + } + + void FunctionDef::setRefersTo(NodeId _id) { + module::Object *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkFunctionDef_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkFunctionDef_RefersTo); + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void FunctionDef::setRefersTo(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void FunctionDef::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkFunctionDef_RefersTo); + } + m_refersTo = 0; + } + + void FunctionDef::setReturnType(NodeId _id) { + type::Type *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_returnType) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_returnType, m_id, edkFunctionDef_ReturnType); + } + m_returnType = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_returnType, this->getId(), edkFunctionDef_ReturnType); + } else { + if (m_returnType) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void FunctionDef::setReturnType(type::Type *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setReturnType(_node->getId()); + } + + void FunctionDef::removeReturnType() { + if (m_returnType) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_returnType, m_id, edkFunctionDef_ReturnType); + } + m_returnType = 0; + } + + void FunctionDef::setDocstring(NodeId _id) { + base::Docstring *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_docstring) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_docstring, m_id, edkFunctionDef_Docstring); + } + m_docstring = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_docstring, this->getId(), edkFunctionDef_Docstring); + } else { + if (m_docstring) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void FunctionDef::setDocstring(base::Docstring *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDocstring(_node->getId()); + } + + void FunctionDef::removeDocstring() { + if (m_docstring) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_docstring, m_id, edkFunctionDef_Docstring); + } + m_docstring = 0; + } + + void FunctionDef::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void FunctionDef::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double FunctionDef::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const FunctionDef& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + if(node.getLloc() == getLloc()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void FunctionDef::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType FunctionDef::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::FunctionDef", strlen("statement::FunctionDef")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void FunctionDef::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + CompoundStatement::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + binIo.writeUInt4(m_lloc); + + binIo.writeUInt4(m_refersTo); + binIo.writeUInt4(m_returnType); + binIo.writeUInt4(m_docstring); + + + for (ListIterator::Container::const_iterator it = hasDecoratorContainer.begin(); it != hasDecoratorContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasObjectContainer.begin(); it != hasObjectContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + + for (ListIterator::Container::const_iterator it = hasParameterContainer.begin(); it != hasParameterContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void FunctionDef::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + CompoundStatement::load(binIo,false); + + m_name = binIo.readUInt4(); + m_lloc = binIo.readUInt4(); + + m_refersTo = binIo.readUInt4(); + + m_returnType = binIo.readUInt4(); + + m_docstring = binIo.readUInt4(); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasDecoratorContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkFunctionDef_HasDecorator); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasObjectContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkFunctionDef_HasObject); + _id = binIo.readUInt4(); + } + + _id = binIo.readUInt4(); + while (_id) { + hasParameterContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkFunctionDef_HasParameter); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/Global.cpp b/lib/python/src/statement/Global.cpp new file mode 100644 index 0000000..2d0cbfa --- /dev/null +++ b/lib/python/src/statement/Global.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Global::Global(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + hasIdentifierContainer() + { + } + + Global::~Global() { + } + + void Global::prepareDelete(bool tryOnVirtualParent){ + while (!hasIdentifierContainer.empty()) { + const NodeId id = *hasIdentifierContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkGlobal_HasIdentifier); + hasIdentifierContainer.pop_front(); + } + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Global::getNodeKind() const { + return ndkGlobal; + } + + ListIterator Global::getIdentifierListIteratorBegin() const { + return ListIterator(&hasIdentifierContainer, factory, true); + } + + ListIterator Global::getIdentifierListIteratorEnd() const { + return ListIterator(&hasIdentifierContainer, factory, false); + } + + bool Global::getIdentifierIsEmpty() const { + return getIdentifierListIteratorBegin() == getIdentifierListIteratorEnd(); + } + + unsigned int Global::getIdentifierSize() const { + unsigned int size = 0; + ListIterator endIt = getIdentifierListIteratorEnd(); + for (ListIterator it = getIdentifierListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Global::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkGlobal_HasIdentifier: + addIdentifier(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Global::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkGlobal_HasIdentifier: + removeIdentifier(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Global::addIdentifier(const expression::Identifier *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkIdentifier) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasIdentifierContainer.push_back(_node->getId()); + setParentEdge(_node,edkGlobal_HasIdentifier); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkGlobal_HasIdentifier); + } + + void Global::addIdentifier(NodeId _id) { + const expression::Identifier *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addIdentifier( node ); + } + + void Global::removeIdentifier(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasIdentifierContainer.begin(), hasIdentifierContainer.end(), id); + + if (it == hasIdentifierContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasIdentifierContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkGlobal_HasIdentifier); + } + + void Global::removeIdentifier(expression::Identifier *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeIdentifier(_node->getId()); + } + + void Global::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Global::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Global::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Global::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Global::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Global", strlen("statement::Global")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Global::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasIdentifierContainer.begin(); it != hasIdentifierContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Global::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasIdentifierContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkGlobal_HasIdentifier); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/Handler.cpp b/lib/python/src/statement/Handler.cpp new file mode 100644 index 0000000..dd8086d --- /dev/null +++ b/lib/python/src/statement/Handler.cpp @@ -0,0 +1,333 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Handler::Handler(NodeId _id, Factory *_factory) : + Statement(_id, _factory), + m_hasName(0), + m_hasExceptBody(0), + m_hasType(0) + { + } + + Handler::~Handler() { + } + + void Handler::prepareDelete(bool tryOnVirtualParent){ + removeName(); + removeExceptBody(); + removeType(); + statement::Statement::prepareDelete(false); + } + + NodeKind Handler::getNodeKind() const { + return ndkHandler; + } + + expression::Expression* Handler::getName() const { + expression::Expression *_node = NULL; + if (m_hasName != 0) + _node = dynamic_cast(factory->getPointer(m_hasName)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + statement::Suite* Handler::getExceptBody() const { + statement::Suite *_node = NULL; + if (m_hasExceptBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasExceptBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Handler::getType() const { + expression::Expression *_node = NULL; + if (m_hasType != 0) + _node = dynamic_cast(factory->getPointer(m_hasType)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Handler::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkHandler_HasName: + setName(edgeEnd); + return true; + case edkHandler_HasExceptBody: + setExceptBody(edgeEnd); + return true; + case edkHandler_HasType: + setType(edgeEnd); + return true; + default: + break; + } + if (statement::Statement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Handler::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkHandler_HasName: + removeName(); + return true; + case edkHandler_HasExceptBody: + removeExceptBody(); + return true; + case edkHandler_HasType: + removeType(); + return true; + default: + break; + } + if (statement::Statement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Handler::setName(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasName) { + removeParentEdge(m_hasName); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasName, m_id, edkHandler_HasName); + } + m_hasName = _node->getId(); + if (m_hasName != 0) + setParentEdge(factory->getPointer(m_hasName), edkHandler_HasName); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasName, this->getId(), edkHandler_HasName); + } else { + if (m_hasName) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Handler::setName(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setName(_node->getId()); + } + + void Handler::removeName() { + if (m_hasName) { + removeParentEdge(m_hasName); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasName, m_id, edkHandler_HasName); + } + m_hasName = 0; + } + + void Handler::setExceptBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExceptBody) { + removeParentEdge(m_hasExceptBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExceptBody, m_id, edkHandler_HasExceptBody); + } + m_hasExceptBody = _node->getId(); + if (m_hasExceptBody != 0) + setParentEdge(factory->getPointer(m_hasExceptBody), edkHandler_HasExceptBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExceptBody, this->getId(), edkHandler_HasExceptBody); + } else { + if (m_hasExceptBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Handler::setExceptBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExceptBody(_node->getId()); + } + + void Handler::removeExceptBody() { + if (m_hasExceptBody) { + removeParentEdge(m_hasExceptBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExceptBody, m_id, edkHandler_HasExceptBody); + } + m_hasExceptBody = 0; + } + + void Handler::setType(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasType) { + removeParentEdge(m_hasType); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasType, m_id, edkHandler_HasType); + } + m_hasType = _node->getId(); + if (m_hasType != 0) + setParentEdge(factory->getPointer(m_hasType), edkHandler_HasType); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasType, this->getId(), edkHandler_HasType); + } else { + if (m_hasType) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Handler::setType(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setType(_node->getId()); + } + + void Handler::removeType() { + if (m_hasType) { + removeParentEdge(m_hasType); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasType, m_id, edkHandler_HasType); + } + m_hasType = 0; + } + + void Handler::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Handler::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Handler::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Handler::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Handler::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Handler", strlen("statement::Handler")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Handler::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Statement::save(binIo,false); + + binIo.writeUInt4(m_hasName); + binIo.writeUInt4(m_hasExceptBody); + binIo.writeUInt4(m_hasType); + + } + + void Handler::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Statement::load(binIo,false); + + m_hasName = binIo.readUInt4(); + if (m_hasName != 0) + setParentEdge(factory->getPointer(m_hasName),edkHandler_HasName); + + m_hasExceptBody = binIo.readUInt4(); + if (m_hasExceptBody != 0) + setParentEdge(factory->getPointer(m_hasExceptBody),edkHandler_HasExceptBody); + + m_hasType = binIo.readUInt4(); + if (m_hasType != 0) + setParentEdge(factory->getPointer(m_hasType),edkHandler_HasType); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/If.cpp b/lib/python/src/statement/If.cpp new file mode 100644 index 0000000..2b3274a --- /dev/null +++ b/lib/python/src/statement/If.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + If::If(NodeId _id, Factory *_factory) : + CompoundStatement(_id, _factory), + m_hasElseBody(0), + m_hasTestExpression(0) + { + } + + If::~If() { + } + + void If::prepareDelete(bool tryOnVirtualParent){ + removeElseBody(); + removeTestExpression(); + statement::CompoundStatement::prepareDelete(false); + } + + NodeKind If::getNodeKind() const { + return ndkIf; + } + + statement::Suite* If::getElseBody() const { + statement::Suite *_node = NULL; + if (m_hasElseBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasElseBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* If::getTestExpression() const { + expression::Expression *_node = NULL; + if (m_hasTestExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasTestExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool If::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIf_HasElseBody: + setElseBody(edgeEnd); + return true; + case edkIf_HasTestExpression: + setTestExpression(edgeEnd); + return true; + default: + break; + } + if (statement::CompoundStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool If::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIf_HasElseBody: + removeElseBody(); + return true; + case edkIf_HasTestExpression: + removeTestExpression(); + return true; + default: + break; + } + if (statement::CompoundStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void If::setElseBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkIf_HasElseBody); + } + m_hasElseBody = _node->getId(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody), edkIf_HasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasElseBody, this->getId(), edkIf_HasElseBody); + } else { + if (m_hasElseBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void If::setElseBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setElseBody(_node->getId()); + } + + void If::removeElseBody() { + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkIf_HasElseBody); + } + m_hasElseBody = 0; + } + + void If::setTestExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTestExpression) { + removeParentEdge(m_hasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTestExpression, m_id, edkIf_HasTestExpression); + } + m_hasTestExpression = _node->getId(); + if (m_hasTestExpression != 0) + setParentEdge(factory->getPointer(m_hasTestExpression), edkIf_HasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTestExpression, this->getId(), edkIf_HasTestExpression); + } else { + if (m_hasTestExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void If::setTestExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTestExpression(_node->getId()); + } + + void If::removeTestExpression() { + if (m_hasTestExpression) { + removeParentEdge(m_hasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTestExpression, m_id, edkIf_HasTestExpression); + } + m_hasTestExpression = 0; + } + + void If::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void If::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double If::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void If::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType If::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::If", strlen("statement::If")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void If::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + CompoundStatement::save(binIo,false); + + binIo.writeUInt4(m_hasElseBody); + binIo.writeUInt4(m_hasTestExpression); + + } + + void If::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + CompoundStatement::load(binIo,false); + + m_hasElseBody = binIo.readUInt4(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody),edkIf_HasElseBody); + + m_hasTestExpression = binIo.readUInt4(); + if (m_hasTestExpression != 0) + setParentEdge(factory->getPointer(m_hasTestExpression),edkIf_HasTestExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/ImportFrom.cpp b/lib/python/src/statement/ImportFrom.cpp new file mode 100644 index 0000000..556b24b --- /dev/null +++ b/lib/python/src/statement/ImportFrom.cpp @@ -0,0 +1,171 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + ImportFrom::ImportFrom(NodeId _id, Factory *_factory) : + ImportStatement(_id, _factory), + m_level(0), + m_modulname(0) + { + } + + ImportFrom::~ImportFrom() { + } + + void ImportFrom::prepareDelete(bool tryOnVirtualParent){ + statement::ImportStatement::prepareDelete(false); + } + + NodeKind ImportFrom::getNodeKind() const { + return ndkImportFrom; + } + + Key ImportFrom::getModulnameKey() const { + return m_modulname; + } + + const std::string& ImportFrom::getModulname() const { + return factory->getStringTable().get(m_modulname); + } + + int ImportFrom::getLevel() const { + return m_level; + } + + void ImportFrom::setModulnameKey(Key _modulname) { + m_modulname = _modulname; + } + + void ImportFrom::setModulname(const std::string& _modulname) { + m_modulname = factory->getStringTable().set(_modulname); + } + + void ImportFrom::setLevel(int _level) { + m_level = _level; + } + + bool ImportFrom::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::ImportStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ImportFrom::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::ImportStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ImportFrom::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ImportFrom::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ImportFrom::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const ImportFrom& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getModulname(); + str2 = node.getModulname(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + if(node.getLevel() == getLevel()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void ImportFrom::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_modulname); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_modulname = foundKeyId->second; + } else { + Key oldkey = m_modulname; + m_modulname = newStrTable.set(factory->getStringTable().get(m_modulname)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_modulname)); } + + } + + NodeHashType ImportFrom::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::ImportFrom", strlen("statement::ImportFrom")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ImportFrom::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + ImportStatement::save(binIo,false); + + factory->getStringTable().setType(m_modulname, StrTable::strToSave); + binIo.writeUInt4(m_modulname); + binIo.writeUInt4(m_level); + + } + + void ImportFrom::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + ImportStatement::load(binIo,false); + + m_modulname = binIo.readUInt4(); + m_level = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/ImportStatement.cpp b/lib/python/src/statement/ImportStatement.cpp new file mode 100644 index 0000000..02d4fb7 --- /dev/null +++ b/lib/python/src/statement/ImportStatement.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + ImportStatement::ImportStatement(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + hasAliasContainer() + { + } + + ImportStatement::~ImportStatement() { + } + + void ImportStatement::prepareDelete(bool tryOnVirtualParent){ + while (!hasAliasContainer.empty()) { + const NodeId id = *hasAliasContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkImportStatement_HasAlias); + hasAliasContainer.pop_front(); + } + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind ImportStatement::getNodeKind() const { + return ndkImportStatement; + } + + ListIterator ImportStatement::getAliasListIteratorBegin() const { + return ListIterator(&hasAliasContainer, factory, true); + } + + ListIterator ImportStatement::getAliasListIteratorEnd() const { + return ListIterator(&hasAliasContainer, factory, false); + } + + bool ImportStatement::getAliasIsEmpty() const { + return getAliasListIteratorBegin() == getAliasListIteratorEnd(); + } + + unsigned int ImportStatement::getAliasSize() const { + unsigned int size = 0; + ListIterator endIt = getAliasListIteratorEnd(); + for (ListIterator it = getAliasListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool ImportStatement::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkImportStatement_HasAlias: + addAlias(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ImportStatement::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkImportStatement_HasAlias: + removeAlias(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ImportStatement::addAlias(const statement::Alias *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkAlias) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasAliasContainer.push_back(_node->getId()); + setParentEdge(_node,edkImportStatement_HasAlias); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkImportStatement_HasAlias); + } + + void ImportStatement::addAlias(NodeId _id) { + const statement::Alias *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addAlias( node ); + } + + void ImportStatement::removeAlias(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasAliasContainer.begin(), hasAliasContainer.end(), id); + + if (it == hasAliasContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasAliasContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkImportStatement_HasAlias); + } + + void ImportStatement::removeAlias(statement::Alias *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeAlias(_node->getId()); + } + + void ImportStatement::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ImportStatement::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ImportStatement::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void ImportStatement::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType ImportStatement::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::ImportStatement", strlen("statement::ImportStatement")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ImportStatement::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasAliasContainer.begin(); it != hasAliasContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void ImportStatement::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasAliasContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkImportStatement_HasAlias); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/Iteration.cpp b/lib/python/src/statement/Iteration.cpp new file mode 100644 index 0000000..eac4db5 --- /dev/null +++ b/lib/python/src/statement/Iteration.cpp @@ -0,0 +1,183 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Iteration::Iteration(NodeId _id, Factory *_factory) : + CompoundStatement(_id, _factory), + m_hasElseBody(0) + { + } + + Iteration::~Iteration() { + } + + void Iteration::prepareDelete(bool tryOnVirtualParent){ + removeElseBody(); + statement::CompoundStatement::prepareDelete(false); + } + + statement::Suite* Iteration::getElseBody() const { + statement::Suite *_node = NULL; + if (m_hasElseBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasElseBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Iteration::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIteration_HasElseBody: + setElseBody(edgeEnd); + return true; + default: + break; + } + if (statement::CompoundStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Iteration::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkIteration_HasElseBody: + removeElseBody(); + return true; + default: + break; + } + if (statement::CompoundStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Iteration::setElseBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkIteration_HasElseBody); + } + m_hasElseBody = _node->getId(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody), edkIteration_HasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasElseBody, this->getId(), edkIteration_HasElseBody); + } else { + if (m_hasElseBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Iteration::setElseBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setElseBody(_node->getId()); + } + + void Iteration::removeElseBody() { + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkIteration_HasElseBody); + } + m_hasElseBody = 0; + } + + double Iteration::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Iteration::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Iteration::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Iteration", strlen("statement::Iteration")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Iteration::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + CompoundStatement::save(binIo,false); + + binIo.writeUInt4(m_hasElseBody); + + } + + void Iteration::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + CompoundStatement::load(binIo,false); + + m_hasElseBody = binIo.readUInt4(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody),edkIteration_HasElseBody); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Parameter.cpp b/lib/python/src/statement/Parameter.cpp new file mode 100644 index 0000000..67872cd --- /dev/null +++ b/lib/python/src/statement/Parameter.cpp @@ -0,0 +1,292 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Parameter::Parameter(NodeId _id, Factory *_factory) : + Named(_id, _factory), + m_kind(pmkNormal), + m_hasDefaultValue(0), + m_refersTo(0) + { + } + + Parameter::~Parameter() { + } + + void Parameter::prepareDelete(bool tryOnVirtualParent){ + removeDefaultValue(); + removeRefersTo(); + base::Named::prepareDelete(false); + } + + NodeKind Parameter::getNodeKind() const { + return ndkParameter; + } + + ParameterKind Parameter::getKind() const { + return m_kind; + } + + void Parameter::setKind(ParameterKind _kind) { + m_kind = _kind; + } + + expression::Expression* Parameter::getDefaultValue() const { + expression::Expression *_node = NULL; + if (m_hasDefaultValue != 0) + _node = dynamic_cast(factory->getPointer(m_hasDefaultValue)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + module::Object* Parameter::getRefersTo() const { + module::Object *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Parameter::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkParameter_HasDefaultValue: + setDefaultValue(edgeEnd); + return true; + case edkParameter_RefersTo: + setRefersTo(edgeEnd); + return true; + default: + break; + } + if (base::Named::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Parameter::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkParameter_HasDefaultValue: + removeDefaultValue(); + return true; + case edkParameter_RefersTo: + removeRefersTo(); + return true; + default: + break; + } + if (base::Named::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Parameter::setDefaultValue(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasDefaultValue) { + removeParentEdge(m_hasDefaultValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasDefaultValue, m_id, edkParameter_HasDefaultValue); + } + m_hasDefaultValue = _node->getId(); + if (m_hasDefaultValue != 0) + setParentEdge(factory->getPointer(m_hasDefaultValue), edkParameter_HasDefaultValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasDefaultValue, this->getId(), edkParameter_HasDefaultValue); + } else { + if (m_hasDefaultValue) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Parameter::setDefaultValue(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDefaultValue(_node->getId()); + } + + void Parameter::removeDefaultValue() { + if (m_hasDefaultValue) { + removeParentEdge(m_hasDefaultValue); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasDefaultValue, m_id, edkParameter_HasDefaultValue); + } + m_hasDefaultValue = 0; + } + + void Parameter::setRefersTo(NodeId _id) { + module::Object *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkParameter_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkParameter_RefersTo); + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Parameter::setRefersTo(module::Object *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void Parameter::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkParameter_RefersTo); + } + m_refersTo = 0; + } + + void Parameter::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Parameter::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Parameter::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Parameter& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (2 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Parameter::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType Parameter::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Parameter", strlen("statement::Parameter")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Parameter::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Named::save(binIo,false); + + binIo.writeUByte1(m_kind); + + binIo.writeUInt4(m_hasDefaultValue); + binIo.writeUInt4(m_refersTo); + + } + + void Parameter::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Named::load(binIo,false); + + m_kind = (ParameterKind)binIo.readUByte1(); + + m_hasDefaultValue = binIo.readUInt4(); + if (m_hasDefaultValue != 0) + setParentEdge(factory->getPointer(m_hasDefaultValue),edkParameter_HasDefaultValue); + + m_refersTo = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Pass.cpp b/lib/python/src/statement/Pass.cpp new file mode 100644 index 0000000..bdc9869 --- /dev/null +++ b/lib/python/src/statement/Pass.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Pass::Pass(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory) + { + } + + Pass::~Pass() { + } + + void Pass::prepareDelete(bool tryOnVirtualParent){ + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Pass::getNodeKind() const { + return ndkPass; + } + + bool Pass::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Pass::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Pass::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Pass::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Pass::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Pass::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Pass::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Pass", strlen("statement::Pass")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Pass::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + } + + void Pass::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Print.cpp b/lib/python/src/statement/Print.cpp new file mode 100644 index 0000000..f881637 --- /dev/null +++ b/lib/python/src/statement/Print.cpp @@ -0,0 +1,286 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Print::Print(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_nl(false), + m_hasExpressionList(0), + m_hasDestination(0) + { + } + + Print::~Print() { + } + + void Print::prepareDelete(bool tryOnVirtualParent){ + removeExpressionList(); + removeDestination(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Print::getNodeKind() const { + return ndkPrint; + } + + bool Print::getNl() const { + return m_nl; + } + + void Print::setNl(bool _nl) { + m_nl = _nl; + } + + expression::ExpressionList* Print::getExpressionList() const { + expression::ExpressionList *_node = NULL; + if (m_hasExpressionList != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpressionList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Print::getDestination() const { + expression::Expression *_node = NULL; + if (m_hasDestination != 0) + _node = dynamic_cast(factory->getPointer(m_hasDestination)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Print::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPrint_HasExpressionList: + setExpressionList(edgeEnd); + return true; + case edkPrint_HasDestination: + setDestination(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Print::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkPrint_HasExpressionList: + removeExpressionList(); + return true; + case edkPrint_HasDestination: + removeDestination(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Print::setExpressionList(NodeId _id) { + expression::ExpressionList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpressionList) { + removeParentEdge(m_hasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpressionList, m_id, edkPrint_HasExpressionList); + } + m_hasExpressionList = _node->getId(); + if (m_hasExpressionList != 0) + setParentEdge(factory->getPointer(m_hasExpressionList), edkPrint_HasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpressionList, this->getId(), edkPrint_HasExpressionList); + } else { + if (m_hasExpressionList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Print::setExpressionList(expression::ExpressionList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpressionList(_node->getId()); + } + + void Print::removeExpressionList() { + if (m_hasExpressionList) { + removeParentEdge(m_hasExpressionList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpressionList, m_id, edkPrint_HasExpressionList); + } + m_hasExpressionList = 0; + } + + void Print::setDestination(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasDestination) { + removeParentEdge(m_hasDestination); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasDestination, m_id, edkPrint_HasDestination); + } + m_hasDestination = _node->getId(); + if (m_hasDestination != 0) + setParentEdge(factory->getPointer(m_hasDestination), edkPrint_HasDestination); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasDestination, this->getId(), edkPrint_HasDestination); + } else { + if (m_hasDestination) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Print::setDestination(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setDestination(_node->getId()); + } + + void Print::removeDestination() { + if (m_hasDestination) { + removeParentEdge(m_hasDestination); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasDestination, m_id, edkPrint_HasDestination); + } + m_hasDestination = 0; + } + + void Print::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Print::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Print::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const Print& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getNl() == getNl()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void Print::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Print::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Print", strlen("statement::Print")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Print::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + unsigned char boolValues = 0; + boolValues <<= 1; + if (m_nl) + boolValues |= 1; + binIo.writeUByte1(boolValues); + + binIo.writeUInt4(m_hasExpressionList); + binIo.writeUInt4(m_hasDestination); + + } + + void Print::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + unsigned char boolValues = binIo.readUByte1(); + m_nl = boolValues & 1; + boolValues >>= 1; + + m_hasExpressionList = binIo.readUInt4(); + if (m_hasExpressionList != 0) + setParentEdge(factory->getPointer(m_hasExpressionList),edkPrint_HasExpressionList); + + m_hasDestination = binIo.readUInt4(); + if (m_hasDestination != 0) + setParentEdge(factory->getPointer(m_hasDestination),edkPrint_HasDestination); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Raise.cpp b/lib/python/src/statement/Raise.cpp new file mode 100644 index 0000000..12814be --- /dev/null +++ b/lib/python/src/statement/Raise.cpp @@ -0,0 +1,333 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Raise::Raise(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_hasTracebackExpression(0), + m_hasTypeExpression(0), + m_hasValueExpression(0) + { + } + + Raise::~Raise() { + } + + void Raise::prepareDelete(bool tryOnVirtualParent){ + removeTracebackExpression(); + removeTypeExpression(); + removeValueExpression(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Raise::getNodeKind() const { + return ndkRaise; + } + + expression::Expression* Raise::getTracebackExpression() const { + expression::Expression *_node = NULL; + if (m_hasTracebackExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasTracebackExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Raise::getTypeExpression() const { + expression::Expression *_node = NULL; + if (m_hasTypeExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasTypeExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + expression::Expression* Raise::getValueExpression() const { + expression::Expression *_node = NULL; + if (m_hasValueExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasValueExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Raise::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkRaise_HasTracebackExpression: + setTracebackExpression(edgeEnd); + return true; + case edkRaise_HasTypeExpression: + setTypeExpression(edgeEnd); + return true; + case edkRaise_HasValueExpression: + setValueExpression(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Raise::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkRaise_HasTracebackExpression: + removeTracebackExpression(); + return true; + case edkRaise_HasTypeExpression: + removeTypeExpression(); + return true; + case edkRaise_HasValueExpression: + removeValueExpression(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Raise::setTracebackExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTracebackExpression) { + removeParentEdge(m_hasTracebackExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTracebackExpression, m_id, edkRaise_HasTracebackExpression); + } + m_hasTracebackExpression = _node->getId(); + if (m_hasTracebackExpression != 0) + setParentEdge(factory->getPointer(m_hasTracebackExpression), edkRaise_HasTracebackExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTracebackExpression, this->getId(), edkRaise_HasTracebackExpression); + } else { + if (m_hasTracebackExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Raise::setTracebackExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTracebackExpression(_node->getId()); + } + + void Raise::removeTracebackExpression() { + if (m_hasTracebackExpression) { + removeParentEdge(m_hasTracebackExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTracebackExpression, m_id, edkRaise_HasTracebackExpression); + } + m_hasTracebackExpression = 0; + } + + void Raise::setTypeExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTypeExpression) { + removeParentEdge(m_hasTypeExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTypeExpression, m_id, edkRaise_HasTypeExpression); + } + m_hasTypeExpression = _node->getId(); + if (m_hasTypeExpression != 0) + setParentEdge(factory->getPointer(m_hasTypeExpression), edkRaise_HasTypeExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTypeExpression, this->getId(), edkRaise_HasTypeExpression); + } else { + if (m_hasTypeExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Raise::setTypeExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTypeExpression(_node->getId()); + } + + void Raise::removeTypeExpression() { + if (m_hasTypeExpression) { + removeParentEdge(m_hasTypeExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTypeExpression, m_id, edkRaise_HasTypeExpression); + } + m_hasTypeExpression = 0; + } + + void Raise::setValueExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasValueExpression) { + removeParentEdge(m_hasValueExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValueExpression, m_id, edkRaise_HasValueExpression); + } + m_hasValueExpression = _node->getId(); + if (m_hasValueExpression != 0) + setParentEdge(factory->getPointer(m_hasValueExpression), edkRaise_HasValueExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasValueExpression, this->getId(), edkRaise_HasValueExpression); + } else { + if (m_hasValueExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Raise::setValueExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setValueExpression(_node->getId()); + } + + void Raise::removeValueExpression() { + if (m_hasValueExpression) { + removeParentEdge(m_hasValueExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasValueExpression, m_id, edkRaise_HasValueExpression); + } + m_hasValueExpression = 0; + } + + void Raise::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Raise::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Raise::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Raise::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Raise::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Raise", strlen("statement::Raise")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Raise::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + binIo.writeUInt4(m_hasTracebackExpression); + binIo.writeUInt4(m_hasTypeExpression); + binIo.writeUInt4(m_hasValueExpression); + + } + + void Raise::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + m_hasTracebackExpression = binIo.readUInt4(); + if (m_hasTracebackExpression != 0) + setParentEdge(factory->getPointer(m_hasTracebackExpression),edkRaise_HasTracebackExpression); + + m_hasTypeExpression = binIo.readUInt4(); + if (m_hasTypeExpression != 0) + setParentEdge(factory->getPointer(m_hasTypeExpression),edkRaise_HasTypeExpression); + + m_hasValueExpression = binIo.readUInt4(); + if (m_hasValueExpression != 0) + setParentEdge(factory->getPointer(m_hasValueExpression),edkRaise_HasValueExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Return.cpp b/lib/python/src/statement/Return.cpp new file mode 100644 index 0000000..7856829 --- /dev/null +++ b/lib/python/src/statement/Return.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Return::Return(NodeId _id, Factory *_factory) : + SimpleStatement(_id, _factory), + m_hasExpression(0) + { + } + + Return::~Return() { + } + + void Return::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + statement::SimpleStatement::prepareDelete(false); + } + + NodeKind Return::getNodeKind() const { + return ndkReturn; + } + + expression::Expression* Return::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool Return::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkReturn_HasExpression: + setExpression(edgeEnd); + return true; + default: + break; + } + if (statement::SimpleStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Return::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkReturn_HasExpression: + removeExpression(); + return true; + default: + break; + } + if (statement::SimpleStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Return::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkReturn_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkReturn_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkReturn_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void Return::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void Return::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkReturn_HasExpression); + } + m_hasExpression = 0; + } + + void Return::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Return::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Return::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Return::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Return::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Return", strlen("statement::Return")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Return::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + SimpleStatement::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + + } + + void Return::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + SimpleStatement::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkReturn_HasExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/SimpleStatement.cpp b/lib/python/src/statement/SimpleStatement.cpp new file mode 100644 index 0000000..86939fd --- /dev/null +++ b/lib/python/src/statement/SimpleStatement.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + SimpleStatement::SimpleStatement(NodeId _id, Factory *_factory) : + Statement(_id, _factory) + { + } + + SimpleStatement::~SimpleStatement() { + } + + void SimpleStatement::prepareDelete(bool tryOnVirtualParent){ + statement::Statement::prepareDelete(false); + } + + bool SimpleStatement::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::Statement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool SimpleStatement::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::Statement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double SimpleStatement::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void SimpleStatement::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType SimpleStatement::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::SimpleStatement", strlen("statement::SimpleStatement")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void SimpleStatement::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Statement::save(binIo,false); + + } + + void SimpleStatement::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Statement::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Statement.cpp b/lib/python/src/statement/Statement.cpp new file mode 100644 index 0000000..d934c1e --- /dev/null +++ b/lib/python/src/statement/Statement.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Statement::Statement(NodeId _id, Factory *_factory) : + Positioned(_id, _factory) + { + } + + Statement::~Statement() { + } + + void Statement::prepareDelete(bool tryOnVirtualParent){ + base::Positioned::prepareDelete(false); + } + + bool Statement::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Statement::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double Statement::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Statement::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Statement::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Statement", strlen("statement::Statement")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Statement::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + } + + void Statement::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/Suite.cpp b/lib/python/src/statement/Suite.cpp new file mode 100644 index 0000000..694bf13 --- /dev/null +++ b/lib/python/src/statement/Suite.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Suite::Suite(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + hasStatementContainer() + { + } + + Suite::~Suite() { + } + + void Suite::prepareDelete(bool tryOnVirtualParent){ + while (!hasStatementContainer.empty()) { + const NodeId id = *hasStatementContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkSuite_HasStatement); + hasStatementContainer.pop_front(); + } + base::Positioned::prepareDelete(false); + } + + NodeKind Suite::getNodeKind() const { + return ndkSuite; + } + + ListIterator Suite::getStatementListIteratorBegin() const { + return ListIterator(&hasStatementContainer, factory, true); + } + + ListIterator Suite::getStatementListIteratorEnd() const { + return ListIterator(&hasStatementContainer, factory, false); + } + + bool Suite::getStatementIsEmpty() const { + return getStatementListIteratorBegin() == getStatementListIteratorEnd(); + } + + unsigned int Suite::getStatementSize() const { + unsigned int size = 0; + ListIterator endIt = getStatementListIteratorEnd(); + for (ListIterator it = getStatementListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool Suite::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSuite_HasStatement: + addStatement(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Suite::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkSuite_HasStatement: + removeStatement(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void Suite::addStatement(const base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!(Common::getIsStatement(*_node) || Common::getIsExpression(*_node))) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasStatementContainer.push_back(_node->getId()); + setParentEdge(_node,edkSuite_HasStatement); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkSuite_HasStatement); + } + + void Suite::addStatement(NodeId _id) { + const base::Positioned *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addStatement( node ); + } + + void Suite::removeStatement(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasStatementContainer.begin(), hasStatementContainer.end(), id); + + if (it == hasStatementContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasStatementContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkSuite_HasStatement); + } + + void Suite::removeStatement(base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeStatement(_node->getId()); + } + + void Suite::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void Suite::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double Suite::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Suite::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Suite::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Suite", strlen("statement::Suite")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Suite::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasStatementContainer.begin(); it != hasStatementContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void Suite::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasStatementContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkSuite_HasStatement); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/TargetList.cpp b/lib/python/src/statement/TargetList.cpp new file mode 100644 index 0000000..ddd457e --- /dev/null +++ b/lib/python/src/statement/TargetList.cpp @@ -0,0 +1,221 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + TargetList::TargetList(NodeId _id, Factory *_factory) : + Positioned(_id, _factory), + hasTargetContainer() + { + } + + TargetList::~TargetList() { + } + + void TargetList::prepareDelete(bool tryOnVirtualParent){ + while (!hasTargetContainer.empty()) { + const NodeId id = *hasTargetContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkTargetList_HasTarget); + hasTargetContainer.pop_front(); + } + base::Positioned::prepareDelete(false); + } + + NodeKind TargetList::getNodeKind() const { + return ndkTargetList; + } + + ListIterator TargetList::getTargetListIteratorBegin() const { + return ListIterator(&hasTargetContainer, factory, true); + } + + ListIterator TargetList::getTargetListIteratorEnd() const { + return ListIterator(&hasTargetContainer, factory, false); + } + + bool TargetList::getTargetIsEmpty() const { + return getTargetListIteratorBegin() == getTargetListIteratorEnd(); + } + + unsigned int TargetList::getTargetSize() const { + unsigned int size = 0; + ListIterator endIt = getTargetListIteratorEnd(); + for (ListIterator it = getTargetListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + bool TargetList::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkTargetList_HasTarget: + addTarget(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool TargetList::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkTargetList_HasTarget: + removeTarget(edgeEnd); + return true; + default: + break; + } + if (base::Positioned::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void TargetList::addTarget(const expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkList) || (_node->getNodeKind() == ndkSubscription) || (_node->getNodeKind() == ndkAttributeRef) || Common::getIsSlicing(*_node) || (_node->getNodeKind() == ndkIdentifier) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasTargetContainer.push_back(_node->getId()); + setParentEdge(_node,edkTargetList_HasTarget); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkTargetList_HasTarget); + } + + void TargetList::addTarget(NodeId _id) { + const expression::Expression *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addTarget( node ); + } + + void TargetList::removeTarget(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasTargetContainer.begin(), hasTargetContainer.end(), id); + + if (it == hasTargetContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasTargetContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkTargetList_HasTarget); + } + + void TargetList::removeTarget(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeTarget(_node->getId()); + } + + void TargetList::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void TargetList::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double TargetList::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void TargetList::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType TargetList::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::TargetList", strlen("statement::TargetList")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void TargetList::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Positioned::save(binIo,false); + + + for (ListIterator::Container::const_iterator it = hasTargetContainer.begin(); it != hasTargetContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void TargetList::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Positioned::load(binIo,false); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasTargetContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkTargetList_HasTarget); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/Try.cpp b/lib/python/src/statement/Try.cpp new file mode 100644 index 0000000..dddd377 --- /dev/null +++ b/lib/python/src/statement/Try.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + Try::Try(NodeId _id, Factory *_factory) : + CompoundStatement(_id, _factory) + { + } + + Try::~Try() { + } + + void Try::prepareDelete(bool tryOnVirtualParent){ + statement::CompoundStatement::prepareDelete(false); + } + + bool Try::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::CompoundStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Try::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (statement::CompoundStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double Try::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Try::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Try::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::Try", strlen("statement::Try")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Try::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + CompoundStatement::save(binIo,false); + + } + + void Try::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + CompoundStatement::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/TryExcept.cpp b/lib/python/src/statement/TryExcept.cpp new file mode 100644 index 0000000..4df1b98 --- /dev/null +++ b/lib/python/src/statement/TryExcept.cpp @@ -0,0 +1,360 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + TryExcept::TryExcept(NodeId _id, Factory *_factory) : + Try(_id, _factory), + m_hasElseBody(0), + hasHandlerContainer(), + m_hasFinallyBody(0) + { + } + + TryExcept::~TryExcept() { + } + + void TryExcept::prepareDelete(bool tryOnVirtualParent){ + removeElseBody(); + while (!hasHandlerContainer.empty()) { + const NodeId id = *hasHandlerContainer.begin(); + removeParentEdge(id); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkTryExcept_HasHandler); + hasHandlerContainer.pop_front(); + } + removeFinallyBody(); + statement::Try::prepareDelete(false); + } + + NodeKind TryExcept::getNodeKind() const { + return ndkTryExcept; + } + + statement::Suite* TryExcept::getElseBody() const { + statement::Suite *_node = NULL; + if (m_hasElseBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasElseBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + ListIterator TryExcept::getHandlerListIteratorBegin() const { + return ListIterator(&hasHandlerContainer, factory, true); + } + + ListIterator TryExcept::getHandlerListIteratorEnd() const { + return ListIterator(&hasHandlerContainer, factory, false); + } + + bool TryExcept::getHandlerIsEmpty() const { + return getHandlerListIteratorBegin() == getHandlerListIteratorEnd(); + } + + unsigned int TryExcept::getHandlerSize() const { + unsigned int size = 0; + ListIterator endIt = getHandlerListIteratorEnd(); + for (ListIterator it = getHandlerListIteratorBegin(); it != endIt; ++it) { + ++size; + } + return size; + } + + statement::Suite* TryExcept::getFinallyBody() const { + statement::Suite *_node = NULL; + if (m_hasFinallyBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasFinallyBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool TryExcept::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkTryExcept_HasElseBody: + setElseBody(edgeEnd); + return true; + case edkTryExcept_HasHandler: + addHandler(edgeEnd); + return true; + case edkTryExcept_HasFinallyBody: + setFinallyBody(edgeEnd); + return true; + default: + break; + } + if (statement::Try::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool TryExcept::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkTryExcept_HasElseBody: + removeElseBody(); + return true; + case edkTryExcept_HasHandler: + removeHandler(edgeEnd); + return true; + case edkTryExcept_HasFinallyBody: + removeFinallyBody(); + return true; + default: + break; + } + if (statement::Try::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void TryExcept::setElseBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkTryExcept_HasElseBody); + } + m_hasElseBody = _node->getId(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody), edkTryExcept_HasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasElseBody, this->getId(), edkTryExcept_HasElseBody); + } else { + if (m_hasElseBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void TryExcept::setElseBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setElseBody(_node->getId()); + } + + void TryExcept::removeElseBody() { + if (m_hasElseBody) { + removeParentEdge(m_hasElseBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasElseBody, m_id, edkTryExcept_HasElseBody); + } + m_hasElseBody = 0; + } + + void TryExcept::addHandler(const statement::Handler *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_NODE_IS_NULL); + + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH); + + if (!((_node->getNodeKind() == ndkHandler) )) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + + hasHandlerContainer.push_back(_node->getId()); + setParentEdge(_node,edkTryExcept_HasHandler); + + if (factory->reverseEdges) + factory->reverseEdges->insertEdge(_node, this, edkTryExcept_HasHandler); + } + + void TryExcept::addHandler(NodeId _id) { + const statement::Handler *node = dynamic_cast(factory->getPointer(_id)); + if (node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + addHandler( node ); + } + + void TryExcept::removeHandler(NodeId id) { + if (!factory->getExist(id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + ListIterator::Container::iterator it = find(hasHandlerContainer.begin(), hasHandlerContainer.end(), id); + + if (it == hasHandlerContainer.end()) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + hasHandlerContainer.erase(it); + + removeParentEdge(id); + + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(id, this->getId(), edkTryExcept_HasHandler); + } + + void TryExcept::removeHandler(statement::Handler *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_EDGE_IS_NULL); + + removeHandler(_node->getId()); + } + + void TryExcept::setFinallyBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasFinallyBody) { + removeParentEdge(m_hasFinallyBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasFinallyBody, m_id, edkTryExcept_HasFinallyBody); + } + m_hasFinallyBody = _node->getId(); + if (m_hasFinallyBody != 0) + setParentEdge(factory->getPointer(m_hasFinallyBody), edkTryExcept_HasFinallyBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasFinallyBody, this->getId(), edkTryExcept_HasFinallyBody); + } else { + if (m_hasFinallyBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void TryExcept::setFinallyBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setFinallyBody(_node->getId()); + } + + void TryExcept::removeFinallyBody() { + if (m_hasFinallyBody) { + removeParentEdge(m_hasFinallyBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasFinallyBody, m_id, edkTryExcept_HasFinallyBody); + } + m_hasFinallyBody = 0; + } + + void TryExcept::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void TryExcept::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double TryExcept::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void TryExcept::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType TryExcept::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::TryExcept", strlen("statement::TryExcept")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void TryExcept::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Try::save(binIo,false); + + binIo.writeUInt4(m_hasElseBody); + binIo.writeUInt4(m_hasFinallyBody); + + + for (ListIterator::Container::const_iterator it = hasHandlerContainer.begin(); it != hasHandlerContainer.end(); ++it) { + binIo.writeUInt4(*it); + } + binIo.writeUInt4(0); // This is the end sign + } + + void TryExcept::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Try::load(binIo,false); + + m_hasElseBody = binIo.readUInt4(); + if (m_hasElseBody != 0) + setParentEdge(factory->getPointer(m_hasElseBody),edkTryExcept_HasElseBody); + + m_hasFinallyBody = binIo.readUInt4(); + if (m_hasFinallyBody != 0) + setParentEdge(factory->getPointer(m_hasFinallyBody),edkTryExcept_HasFinallyBody); + + NodeId _id; + + _id = binIo.readUInt4(); + while (_id) { + hasHandlerContainer.push_back(_id); + setParentEdge(factory->getPointer(_id),edkTryExcept_HasHandler); + _id = binIo.readUInt4(); + } + } + + +} + + +}}} diff --git a/lib/python/src/statement/TryFinal.cpp b/lib/python/src/statement/TryFinal.cpp new file mode 100644 index 0000000..d400f61 --- /dev/null +++ b/lib/python/src/statement/TryFinal.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + TryFinal::TryFinal(NodeId _id, Factory *_factory) : + Try(_id, _factory), + m_hasFinallyBody(0) + { + } + + TryFinal::~TryFinal() { + } + + void TryFinal::prepareDelete(bool tryOnVirtualParent){ + removeFinallyBody(); + statement::Try::prepareDelete(false); + } + + NodeKind TryFinal::getNodeKind() const { + return ndkTryFinal; + } + + statement::Suite* TryFinal::getFinallyBody() const { + statement::Suite *_node = NULL; + if (m_hasFinallyBody != 0) + _node = dynamic_cast(factory->getPointer(m_hasFinallyBody)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool TryFinal::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkTryFinal_HasFinallyBody: + setFinallyBody(edgeEnd); + return true; + default: + break; + } + if (statement::Try::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool TryFinal::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkTryFinal_HasFinallyBody: + removeFinallyBody(); + return true; + default: + break; + } + if (statement::Try::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void TryFinal::setFinallyBody(NodeId _id) { + statement::Suite *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasFinallyBody) { + removeParentEdge(m_hasFinallyBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasFinallyBody, m_id, edkTryFinal_HasFinallyBody); + } + m_hasFinallyBody = _node->getId(); + if (m_hasFinallyBody != 0) + setParentEdge(factory->getPointer(m_hasFinallyBody), edkTryFinal_HasFinallyBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasFinallyBody, this->getId(), edkTryFinal_HasFinallyBody); + } else { + if (m_hasFinallyBody) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void TryFinal::setFinallyBody(statement::Suite *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setFinallyBody(_node->getId()); + } + + void TryFinal::removeFinallyBody() { + if (m_hasFinallyBody) { + removeParentEdge(m_hasFinallyBody); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasFinallyBody, m_id, edkTryFinal_HasFinallyBody); + } + m_hasFinallyBody = 0; + } + + void TryFinal::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void TryFinal::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double TryFinal::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void TryFinal::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType TryFinal::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::TryFinal", strlen("statement::TryFinal")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void TryFinal::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Try::save(binIo,false); + + binIo.writeUInt4(m_hasFinallyBody); + + } + + void TryFinal::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Try::load(binIo,false); + + m_hasFinallyBody = binIo.readUInt4(); + if (m_hasFinallyBody != 0) + setParentEdge(factory->getPointer(m_hasFinallyBody),edkTryFinal_HasFinallyBody); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/While.cpp b/lib/python/src/statement/While.cpp new file mode 100644 index 0000000..4e3f906 --- /dev/null +++ b/lib/python/src/statement/While.cpp @@ -0,0 +1,195 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + While::While(NodeId _id, Factory *_factory) : + Iteration(_id, _factory), + m_hasTestExpression(0) + { + } + + While::~While() { + } + + void While::prepareDelete(bool tryOnVirtualParent){ + removeTestExpression(); + statement::Iteration::prepareDelete(false); + } + + NodeKind While::getNodeKind() const { + return ndkWhile; + } + + expression::Expression* While::getTestExpression() const { + expression::Expression *_node = NULL; + if (m_hasTestExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasTestExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool While::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkWhile_HasTestExpression: + setTestExpression(edgeEnd); + return true; + default: + break; + } + if (statement::Iteration::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool While::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkWhile_HasTestExpression: + removeTestExpression(); + return true; + default: + break; + } + if (statement::Iteration::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void While::setTestExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTestExpression) { + removeParentEdge(m_hasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTestExpression, m_id, edkWhile_HasTestExpression); + } + m_hasTestExpression = _node->getId(); + if (m_hasTestExpression != 0) + setParentEdge(factory->getPointer(m_hasTestExpression), edkWhile_HasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTestExpression, this->getId(), edkWhile_HasTestExpression); + } else { + if (m_hasTestExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void While::setTestExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTestExpression(_node->getId()); + } + + void While::removeTestExpression() { + if (m_hasTestExpression) { + removeParentEdge(m_hasTestExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTestExpression, m_id, edkWhile_HasTestExpression); + } + m_hasTestExpression = 0; + } + + void While::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void While::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double While::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void While::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType While::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::While", strlen("statement::While")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void While::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Iteration::save(binIo,false); + + binIo.writeUInt4(m_hasTestExpression); + + } + + void While::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Iteration::load(binIo,false); + + m_hasTestExpression = binIo.readUInt4(); + if (m_hasTestExpression != 0) + setParentEdge(factory->getPointer(m_hasTestExpression),edkWhile_HasTestExpression); + + } + + +} + + +}}} diff --git a/lib/python/src/statement/With.cpp b/lib/python/src/statement/With.cpp new file mode 100644 index 0000000..7b3a440 --- /dev/null +++ b/lib/python/src/statement/With.cpp @@ -0,0 +1,264 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace statement { + With::With(NodeId _id, Factory *_factory) : + CompoundStatement(_id, _factory), + m_hasExpression(0), + m_hasTargetList(0) + { + } + + With::~With() { + } + + void With::prepareDelete(bool tryOnVirtualParent){ + removeExpression(); + removeTargetList(); + statement::CompoundStatement::prepareDelete(false); + } + + NodeKind With::getNodeKind() const { + return ndkWith; + } + + expression::Expression* With::getExpression() const { + expression::Expression *_node = NULL; + if (m_hasExpression != 0) + _node = dynamic_cast(factory->getPointer(m_hasExpression)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + statement::TargetList* With::getTargetList() const { + statement::TargetList *_node = NULL; + if (m_hasTargetList != 0) + _node = dynamic_cast(factory->getPointer(m_hasTargetList)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool With::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkWith_HasExpression: + setExpression(edgeEnd); + return true; + case edkWith_HasTargetList: + setTargetList(edgeEnd); + return true; + default: + break; + } + if (statement::CompoundStatement::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool With::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkWith_HasExpression: + removeExpression(); + return true; + case edkWith_HasTargetList: + removeTargetList(); + return true; + default: + break; + } + if (statement::CompoundStatement::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void With::setExpression(NodeId _id) { + expression::Expression *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkWith_HasExpression); + } + m_hasExpression = _node->getId(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression), edkWith_HasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasExpression, this->getId(), edkWith_HasExpression); + } else { + if (m_hasExpression) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void With::setExpression(expression::Expression *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setExpression(_node->getId()); + } + + void With::removeExpression() { + if (m_hasExpression) { + removeParentEdge(m_hasExpression); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasExpression, m_id, edkWith_HasExpression); + } + m_hasExpression = 0; + } + + void With::setTargetList(NodeId _id) { + statement::TargetList *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkWith_HasTargetList); + } + m_hasTargetList = _node->getId(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList), edkWith_HasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_hasTargetList, this->getId(), edkWith_HasTargetList); + } else { + if (m_hasTargetList) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void With::setTargetList(statement::TargetList *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setTargetList(_node->getId()); + } + + void With::removeTargetList() { + if (m_hasTargetList) { + removeParentEdge(m_hasTargetList); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_hasTargetList, m_id, edkWith_HasTargetList); + } + m_hasTargetList = 0; + } + + void With::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void With::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double With::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void With::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType With::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "statement::With", strlen("statement::With")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void With::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + CompoundStatement::save(binIo,false); + + binIo.writeUInt4(m_hasExpression); + binIo.writeUInt4(m_hasTargetList); + + } + + void With::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + CompoundStatement::load(binIo,false); + + m_hasExpression = binIo.readUInt4(); + if (m_hasExpression != 0) + setParentEdge(factory->getPointer(m_hasExpression),edkWith_HasExpression); + + m_hasTargetList = binIo.readUInt4(); + if (m_hasTargetList != 0) + setParentEdge(factory->getPointer(m_hasTargetList),edkWith_HasTargetList); + + } + + +} + + +}}} diff --git a/lib/python/src/type/DictType.cpp b/lib/python/src/type/DictType.cpp new file mode 100644 index 0000000..57d04a3 --- /dev/null +++ b/lib/python/src/type/DictType.cpp @@ -0,0 +1,117 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace type { + DictType::DictType(NodeId _id, Factory *_factory) : + Type(_id, _factory) + { + } + + DictType::~DictType() { + } + + void DictType::prepareDelete(bool tryOnVirtualParent){ + type::Type::prepareDelete(false); + } + + NodeKind DictType::getNodeKind() const { + return ndkDictType; + } + + bool DictType::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (type::Type::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool DictType::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (type::Type::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void DictType::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void DictType::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double DictType::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void DictType::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType DictType::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "type::DictType", strlen("type::DictType")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void DictType::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Type::save(binIo,false); + + } + + void DictType::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Type::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/type/ReferenceType.cpp b/lib/python/src/type/ReferenceType.cpp new file mode 100644 index 0000000..10328f8 --- /dev/null +++ b/lib/python/src/type/ReferenceType.cpp @@ -0,0 +1,235 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace type { + ReferenceType::ReferenceType(NodeId _id, Factory *_factory) : + Type(_id, _factory), + m_name(0), + m_refersTo(0) + { + } + + ReferenceType::~ReferenceType() { + } + + void ReferenceType::prepareDelete(bool tryOnVirtualParent){ + removeRefersTo(); + type::Type::prepareDelete(false); + } + + NodeKind ReferenceType::getNodeKind() const { + return ndkReferenceType; + } + + Key ReferenceType::getNameKey() const { + return m_name; + } + + const std::string& ReferenceType::getName() const { + return factory->getStringTable().get(m_name); + } + + void ReferenceType::setNameKey(Key _name) { + m_name = _name; + } + + void ReferenceType::setName(const std::string& _name) { + m_name = factory->getStringTable().set(_name); + } + + base::Positioned* ReferenceType::getRefersTo() const { + base::Positioned *_node = NULL; + if (m_refersTo != 0) + _node = dynamic_cast(factory->getPointer(m_refersTo)); + if ( (_node == NULL) || factory->getIsFiltered(_node)) + return NULL; + + return _node; + } + + bool ReferenceType::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkReferenceType_RefersTo: + setRefersTo(edgeEnd); + return true; + default: + break; + } + if (type::Type::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool ReferenceType::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + switch (edgeKind) { + case edkReferenceType_RefersTo: + removeRefersTo(); + return true; + default: + break; + } + if (type::Type::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void ReferenceType::setRefersTo(NodeId _id) { + base::Positioned *_node = NULL; + if (_id) { + if (!factory->getExist(_id)) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_END_POINT_OF_THE_EDGE_DOES_NOT_EXIST); + + _node = dynamic_cast (factory->getPointer(_id)); + if ( _node == NULL) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + if (&(_node->getFactory()) != this->factory) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_THE_FACTORY_OF_NODES_DOES_NOT_MATCH ); + + if (_node->getNodeKind() == ndkFunctionDef || _node->getNodeKind() == ndkClassDef || _node->getNodeKind() == ndkModule) { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkReferenceType_RefersTo); + } + m_refersTo = _node->getId(); + if (factory->getExistsReverseEdges()) + factory->reverseEdges->insertEdge(m_refersTo, this->getId(), edkReferenceType_RefersTo); + } else { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_INVALID_NODE_KIND); + } + } else { + if (m_refersTo) { + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + } + } + } + + void ReferenceType::setRefersTo(base::Positioned *_node) { + if (_node == NULL) + throw PythonException(COLUMBUS_LOCATION, CMSG_EX_CAN_T_SET_EDGE_TO_NULL); + + setRefersTo(_node->getId()); + } + + void ReferenceType::removeRefersTo() { + if (m_refersTo) { + if (factory->getExistsReverseEdges()) + factory->reverseEdges->removeEdge(m_refersTo, m_id, edkReferenceType_RefersTo); + } + m_refersTo = 0; + } + + void ReferenceType::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void ReferenceType::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double ReferenceType::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const ReferenceType& node = dynamic_cast(base); + double matchAttrs = 0; + std::string str1, str2; + size_t strMax; + double strSim; + str1 = getName(); + str2 = node.getName(); + strMax = std::max(str1.size(), str2.size()); + strSim = 1 - ((double)common::math::editDistance(str1, str2) / (strMax > 0 ? strMax : 1)); + if (strSim < Common::SimilarityMinForStrings) + return 0.0; + matchAttrs += strSim; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void ReferenceType::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + foundKeyId = oldAndNewStrKeyMap.find(m_name); + if (foundKeyId != oldAndNewStrKeyMap.end()) { + m_name = foundKeyId->second; + } else { + Key oldkey = m_name; + m_name = newStrTable.set(factory->getStringTable().get(m_name)); + oldAndNewStrKeyMap.insert(std::pair(oldkey,m_name)); } + + } + + NodeHashType ReferenceType::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "type::ReferenceType", strlen("type::ReferenceType")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void ReferenceType::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Type::save(binIo,false); + + factory->getStringTable().setType(m_name, StrTable::strToSave); + binIo.writeUInt4(m_name); + + binIo.writeUInt4(m_refersTo); + + } + + void ReferenceType::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Type::load(binIo,false); + + m_name = binIo.readUInt4(); + + m_refersTo = binIo.readUInt4(); + + } + + +} + + +}}} diff --git a/lib/python/src/type/SequenceType.cpp b/lib/python/src/type/SequenceType.cpp new file mode 100644 index 0000000..6b7186f --- /dev/null +++ b/lib/python/src/type/SequenceType.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace type { + SequenceType::SequenceType(NodeId _id, Factory *_factory) : + Type(_id, _factory), + m_kind(sekString) + { + } + + SequenceType::~SequenceType() { + } + + void SequenceType::prepareDelete(bool tryOnVirtualParent){ + type::Type::prepareDelete(false); + } + + NodeKind SequenceType::getNodeKind() const { + return ndkSequenceType; + } + + SequenceTypeKind SequenceType::getKind() const { + return m_kind; + } + + void SequenceType::setKind(SequenceTypeKind _kind) { + m_kind = _kind; + } + + bool SequenceType::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (type::Type::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool SequenceType::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (type::Type::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void SequenceType::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void SequenceType::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double SequenceType::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const SequenceType& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void SequenceType::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType SequenceType::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "type::SequenceType", strlen("type::SequenceType")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void SequenceType::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Type::save(binIo,false); + + binIo.writeUByte1(m_kind); + + } + + void SequenceType::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Type::load(binIo,false); + + m_kind = (SequenceTypeKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/type/SimpleType.cpp b/lib/python/src/type/SimpleType.cpp new file mode 100644 index 0000000..31175b6 --- /dev/null +++ b/lib/python/src/type/SimpleType.cpp @@ -0,0 +1,133 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace type { + SimpleType::SimpleType(NodeId _id, Factory *_factory) : + Type(_id, _factory), + m_kind(stkInteger) + { + } + + SimpleType::~SimpleType() { + } + + void SimpleType::prepareDelete(bool tryOnVirtualParent){ + type::Type::prepareDelete(false); + } + + NodeKind SimpleType::getNodeKind() const { + return ndkSimpleType; + } + + SimpleTypeKind SimpleType::getKind() const { + return m_kind; + } + + void SimpleType::setKind(SimpleTypeKind _kind) { + m_kind = _kind; + } + + bool SimpleType::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (type::Type::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool SimpleType::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (type::Type::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + void SimpleType::accept(Visitor &visitor) const { + visitor.visit(*this); + } + + void SimpleType::acceptEnd(Visitor &visitor) const { + visitor.visitEnd(*this); + } + + double SimpleType::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + const SimpleType& node = dynamic_cast(base); + double matchAttrs = 0; + if(node.getKind() == getKind()) ++matchAttrs; + return matchAttrs / (1 / (1 - Common::SimilarityMinimum)) + Common::SimilarityMinimum; + } else { + return 0.0; + } + } + + void SimpleType::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType SimpleType::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "type::SimpleType", strlen("type::SimpleType")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void SimpleType::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Type::save(binIo,false); + + binIo.writeUByte1(m_kind); + + } + + void SimpleType::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Type::load(binIo,false); + + m_kind = (SimpleTypeKind)binIo.readUByte1(); + + } + + +} + + +}}} diff --git a/lib/python/src/type/Type.cpp b/lib/python/src/type/Type.cpp new file mode 100644 index 0000000..53a64a4 --- /dev/null +++ b/lib/python/src/type/Type.cpp @@ -0,0 +1,105 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" +#include "python/inc/Common.h" +#include "common/inc/WriteMessage.h" + +#include "python/inc/messages.h" +#include +#include +#include "common/inc/math/common.h" + + +namespace columbus { namespace python { namespace asg { + +typedef boost::crc_32_type Crc_type; + +namespace type { + Type::Type(NodeId _id, Factory *_factory) : + Base(_id, _factory) + { + } + + Type::~Type() { + } + + void Type::prepareDelete(bool tryOnVirtualParent){ + base::Base::prepareDelete(false); + } + + bool Type::setEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Base::setEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + bool Type::removeEdge(EdgeKind edgeKind, NodeId edgeEnd, bool tryOnVirtualParent) { + if (base::Base::removeEdge(edgeKind, edgeEnd, false)) { + return true; + } + return false; + } + + double Type::getSimilarity(const base::Base& base){ + if(base.getNodeKind() == getNodeKind()) { + return 1.0; + } else { + return 0.0; + } + } + + void Type::swapStringTable(RefDistributorStrTable& newStrTable, std::map& oldAndNewStrKeyMap ){ + std::map::iterator foundKeyId; + + } + + NodeHashType Type::getHash(std::set& travNodes) const { + if (hashOk) return nodeHashCache; + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_BEGIN,this->getId()); + if (travNodes.count(getId())>0) { + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_SKIP); + return 0; + } + travNodes.insert(getId()); + Crc_type resultHash; + resultHash.process_bytes( "type::Type", strlen("type::Type")); + common::WriteMsg::write(CMSG_GET_THE_NODE_HASH_OF_NODE_END,resultHash.checksum()); + nodeHashCache = resultHash.checksum(); + hashOk = true; + return nodeHashCache; + } + + void Type::save(io::BinaryIO &binIo,bool withVirtualBase /*= true*/) const { + Base::save(binIo,false); + + } + + void Type::load(io::BinaryIO &binIo, bool withVirtualBase /*= true*/) { + Base::load(binIo,false); + + } + + +} + + +}}} diff --git a/lib/python/src/visitors/Visitor.cpp b/lib/python/src/visitors/Visitor.cpp new file mode 100644 index 0000000..5efbff6 --- /dev/null +++ b/lib/python/src/visitors/Visitor.cpp @@ -0,0 +1,734 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { +Visitor::Visitor(): depth(0) { +} + +Visitor::~Visitor() { +} + +unsigned Visitor::getDepth() const { + return depth; +} + +void Visitor::incDepth() { + ++depth; +} + +void Visitor::decDepth() { + --depth; +} + +void Visitor::beginVisit() { +} + +void Visitor::finishVisit() { +} + +void Visitor::visit(const base::Comment& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const base::Comment& node , bool callVirtualBase) { } + +void Visitor::visit(const base::Docstring& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const base::Docstring& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::ArgumentList& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ArgumentList& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::AttributeRef& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::AttributeRef& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::BinaryArithmetic& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::BinaryLogical& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::BinaryLogical& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Call& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Call& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::DictComp& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::DictComp& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Dictionary& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Dictionary& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Ellipsis& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Ellipsis& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::ExpressionList& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ExpressionList& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::ExtSlice& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ExtSlice& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::FloatNumber& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::FloatNumber& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Generator& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Generator& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::GeneratorExpression& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Identifier& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Identifier& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::IfExpression& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::IfExpression& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::ImagNumber& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ImagNumber& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Index& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Index& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::IntegerLiteral& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::KeyValue& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::KeyValue& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Keyword& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Keyword& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Lambda& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Lambda& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::List& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::List& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::ListComp& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::ListComp& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::LongInteger& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::LongInteger& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Set& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Set& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::SetComp& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::SetComp& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Slice& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Slice& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::StringConversion& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::StringConversion& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::StringLiteral& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::StringLiteral& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::Subscription& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::Subscription& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::UnaryOperation& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::UnaryOperation& node , bool callVirtualBase) { } + +void Visitor::visit(const expression::YieldExpression& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const expression::YieldExpression& node , bool callVirtualBase) { } + +void Visitor::visit(const module::Module& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const module::Module& node , bool callVirtualBase) { } + +void Visitor::visit(const module::Object& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const module::Object& node , bool callVirtualBase) { } + +void Visitor::visit(const module::Package& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const module::Package& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Alias& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Alias& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Assert& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Assert& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Assign& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Assign& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::AugAssign& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::AugAssign& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::BaseSpecifier& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Break& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Break& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::ClassDef& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::ClassDef& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Continue& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Continue& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Delete& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Delete& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Exec& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Exec& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::For& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::For& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::FunctionDef& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::FunctionDef& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Global& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Global& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Handler& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Handler& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::If& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::If& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::ImportFrom& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::ImportFrom& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::ImportStatement& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::ImportStatement& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Parameter& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Parameter& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Pass& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Pass& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Print& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Print& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Raise& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Raise& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Return& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Return& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::Suite& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::Suite& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::TargetList& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::TargetList& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::TryExcept& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::TryExcept& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::TryFinal& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::TryFinal& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::While& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::While& node , bool callVirtualBase) { } + +void Visitor::visit(const statement::With& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const statement::With& node , bool callVirtualBase) { } + +void Visitor::visit(const type::DictType& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const type::DictType& node , bool callVirtualBase) { } + +void Visitor::visit(const type::ReferenceType& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const type::ReferenceType& node , bool callVirtualBase) { } + +void Visitor::visit(const type::SequenceType& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const type::SequenceType& node , bool callVirtualBase) { } + +void Visitor::visit(const type::SimpleType& node , bool callVirtualBase) {} + +void Visitor::visitEnd(const type::SimpleType& node , bool callVirtualBase) { } + +void Visitor::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { } + +void Visitor::visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { } + +void Visitor::visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { } + +void Visitor::visitEndArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { } + +void Visitor::visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { } + +void Visitor::visitEndArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { } + +void Visitor::visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { } + +void Visitor::visitEndArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { } + +void Visitor::visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { } + +void Visitor::visitEndArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { } + +void Visitor::visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { } + +void Visitor::visitEndBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { } + +void Visitor::visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { } + +void Visitor::visitEndBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { } + +void Visitor::visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { } + +void Visitor::visitEndCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { } + +void Visitor::visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { } + +void Visitor::visitEndCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { } + +void Visitor::visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { } + +void Visitor::visitEndDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { } + +void Visitor::visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { } + +void Visitor::visitEndDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { } + +void Visitor::visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { } + +void Visitor::visitEndDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { } + +void Visitor::visitExpression_HasType(const expression::Expression& begin, const type::Type& end) { } + +void Visitor::visitEndExpression_HasType(const expression::Expression& begin, const type::Type& end) { } + +void Visitor::visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { } + +void Visitor::visitEndExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { } + +void Visitor::visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { } + +void Visitor::visitEndExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { } + +void Visitor::visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { } + +void Visitor::visitEndGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { } + +void Visitor::visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { } + +void Visitor::visitEndGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { } + +void Visitor::visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { } + +void Visitor::visitEndGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { } + +void Visitor::visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { } + +void Visitor::visitEndGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { } + +void Visitor::visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { } + +void Visitor::visitEndGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { } + +void Visitor::visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { } + +void Visitor::visitEndIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { } + +void Visitor::visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { } + +void Visitor::visitEndIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { } + +void Visitor::visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { } + +void Visitor::visitEndIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { } + +void Visitor::visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { } + +void Visitor::visitEndIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { } + +void Visitor::visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { } + +void Visitor::visitEndKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { } + +void Visitor::visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { } + +void Visitor::visitEndKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { } + +void Visitor::visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { } + +void Visitor::visitEndKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { } + +void Visitor::visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { } + +void Visitor::visitEndKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { } + +void Visitor::visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { } + +void Visitor::visitEndLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { } + +void Visitor::visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { } + +void Visitor::visitEndLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { } + +void Visitor::visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { } + +void Visitor::visitEndLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { } + +void Visitor::visitList_HasExpression(const expression::List& begin, const expression::Expression& end) { } + +void Visitor::visitEndList_HasExpression(const expression::List& begin, const expression::Expression& end) { } + +void Visitor::visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { } + +void Visitor::visitEndListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { } + +void Visitor::visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { } + +void Visitor::visitEndListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { } + +void Visitor::visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { } + +void Visitor::visitEndSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { } + +void Visitor::visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { } + +void Visitor::visitEndSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { } + +void Visitor::visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { } + +void Visitor::visitEndSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { } + +void Visitor::visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { } + +void Visitor::visitEndSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { } + +void Visitor::visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { } + +void Visitor::visitEndSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { } + +void Visitor::visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { } + +void Visitor::visitEndSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { } + +void Visitor::visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { } + +void Visitor::visitEndStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { } + +void Visitor::visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { } + +void Visitor::visitEndSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { } + +void Visitor::visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { } + +void Visitor::visitEndUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { } + +void Visitor::visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { } + +void Visitor::visitEndYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { } + +void Visitor::visitModule_HasObject(const module::Module& begin, const module::Object& end) { } + +void Visitor::visitEndModule_HasObject(const module::Module& begin, const module::Object& end) { } + +void Visitor::visitModule_HasStatement(const module::Module& begin, const base::Positioned& end) { } + +void Visitor::visitEndModule_HasStatement(const module::Module& begin, const base::Positioned& end) { } + +void Visitor::visitModule_Docstring(const module::Module& begin, const base::Docstring& end) { } + +void Visitor::visitEndModule_Docstring(const module::Module& begin, const base::Docstring& end) { } + +void Visitor::visitObject_RefersTo(const module::Object& begin, const base::Positioned& end) { } + +void Visitor::visitEndObject_RefersTo(const module::Object& begin, const base::Positioned& end) { } + +void Visitor::visitObject_HasType(const module::Object& begin, const type::Type& end) { } + +void Visitor::visitEndObject_HasType(const module::Object& begin, const type::Type& end) { } + +void Visitor::visitPackage_HasModule(const module::Package& begin, const module::Module& end) { } + +void Visitor::visitEndPackage_HasModule(const module::Package& begin, const module::Module& end) { } + +void Visitor::visitPackage_HasPackage(const module::Package& begin, const module::Package& end) { } + +void Visitor::visitEndPackage_HasPackage(const module::Package& begin, const module::Package& end) { } + +void Visitor::visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { } + +void Visitor::visitEndAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { } + +void Visitor::visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { } + +void Visitor::visitEndAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { } + +void Visitor::visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { } + +void Visitor::visitEndAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { } + +void Visitor::visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { } + +void Visitor::visitEndAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { } + +void Visitor::visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { } + +void Visitor::visitEndAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { } + +void Visitor::visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { } + +void Visitor::visitEndBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { } + +void Visitor::visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { } + +void Visitor::visitEndBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { } + +void Visitor::visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { } + +void Visitor::visitEndClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { } + +void Visitor::visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { } + +void Visitor::visitEndClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { } + +void Visitor::visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { } + +void Visitor::visitEndClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { } + +void Visitor::visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { } + +void Visitor::visitEndClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { } + +void Visitor::visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { } + +void Visitor::visitEndClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { } + +void Visitor::visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { } + +void Visitor::visitEndCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { } + +void Visitor::visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { } + +void Visitor::visitEndDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { } + +void Visitor::visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { } + +void Visitor::visitEndExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { } + +void Visitor::visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { } + +void Visitor::visitEndExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { } + +void Visitor::visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { } + +void Visitor::visitEndExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { } + +void Visitor::visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { } + +void Visitor::visitEndFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { } + +void Visitor::visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { } + +void Visitor::visitEndFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { } + +void Visitor::visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { } + +void Visitor::visitEndFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { } + +void Visitor::visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { } + +void Visitor::visitEndFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { } + +void Visitor::visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { } + +void Visitor::visitEndFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { } + +void Visitor::visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { } + +void Visitor::visitEndFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { } + +void Visitor::visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { } + +void Visitor::visitEndFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { } + +void Visitor::visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { } + +void Visitor::visitEndFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { } + +void Visitor::visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { } + +void Visitor::visitEndGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { } + +void Visitor::visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { } + +void Visitor::visitEndHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { } + +void Visitor::visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { } + +void Visitor::visitEndHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { } + +void Visitor::visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { } + +void Visitor::visitEndHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { } + +void Visitor::visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { } + +void Visitor::visitEndIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { } + +void Visitor::visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { } + +void Visitor::visitEndIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { } + +void Visitor::visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { } + +void Visitor::visitEndImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { } + +void Visitor::visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { } + +void Visitor::visitEndIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { } + +void Visitor::visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { } + +void Visitor::visitEndParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { } + +void Visitor::visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { } + +void Visitor::visitEndParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { } + +void Visitor::visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { } + +void Visitor::visitEndPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { } + +void Visitor::visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { } + +void Visitor::visitEndPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { } + +void Visitor::visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { } + +void Visitor::visitEndRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { } + +void Visitor::visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { } + +void Visitor::visitEndRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { } + +void Visitor::visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { } + +void Visitor::visitEndRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { } + +void Visitor::visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { } + +void Visitor::visitEndReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { } + +void Visitor::visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { } + +void Visitor::visitEndSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { } + +void Visitor::visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { } + +void Visitor::visitEndTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { } + +void Visitor::visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { } + +void Visitor::visitEndTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { } + +void Visitor::visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { } + +void Visitor::visitEndTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { } + +void Visitor::visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { } + +void Visitor::visitEndTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { } + +void Visitor::visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { } + +void Visitor::visitEndTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { } + +void Visitor::visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { } + +void Visitor::visitEndWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { } + +void Visitor::visitWith_HasExpression(const statement::With& begin, const expression::Expression& end) { } + +void Visitor::visitEndWith_HasExpression(const statement::With& begin, const expression::Expression& end) { } + +void Visitor::visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { } + +void Visitor::visitEndWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { } + +void Visitor::visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { } + +void Visitor::visitEndReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { } + + +}}} diff --git a/lib/python/src/visitors/VisitorAbstractNodes.cpp b/lib/python/src/visitors/VisitorAbstractNodes.cpp new file mode 100644 index 0000000..d9fded3 --- /dev/null +++ b/lib/python/src/visitors/VisitorAbstractNodes.cpp @@ -0,0 +1,687 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { +VisitorAbstractNodes::~VisitorAbstractNodes() { } + +void VisitorAbstractNodes::visit (const base::Base& node , bool callVirtualBase) { } +void VisitorAbstractNodes::visitEnd(const base::Base& node , bool callVirtualBase) { } + +void VisitorAbstractNodes::visit(const base::Comment& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const base::Comment& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const base::Docstring& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const base::Docstring& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const base::Named& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const base::Named& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const base::Positioned& node , bool callVirtualBase) { + visit ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const base::Positioned& node , bool callVirtualBase) { + visitEnd ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ArgumentList& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ArgumentList& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::AttributeRef& node , bool callVirtualBase) { + visit ((expression::Binary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::AttributeRef& node , bool callVirtualBase) { + visitEnd ((expression::Binary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Binary& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Binary& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::BinaryArithmetic& node , bool callVirtualBase) { + visit ((expression::Binary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase) { + visitEnd ((expression::Binary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::BinaryLogical& node , bool callVirtualBase) { + visit ((expression::Binary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::BinaryLogical& node , bool callVirtualBase) { + visitEnd ((expression::Binary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Call& node , bool callVirtualBase) { + visit ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Call& node , bool callVirtualBase) { + visitEnd ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::DictComp& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::DictComp& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Dictionary& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Dictionary& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Ellipsis& node , bool callVirtualBase) { + visit ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Ellipsis& node , bool callVirtualBase) { + visitEnd ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Expression& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Expression& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ExpressionList& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ExpressionList& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ExtSlice& node , bool callVirtualBase) { + visit ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ExtSlice& node , bool callVirtualBase) { + visitEnd ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::FloatNumber& node , bool callVirtualBase) { + visit ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::FloatNumber& node , bool callVirtualBase) { + visitEnd ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Generator& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Generator& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::GeneratorExpression& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Identifier& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Identifier& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::IfExpression& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::IfExpression& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ImagNumber& node , bool callVirtualBase) { + visit ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ImagNumber& node , bool callVirtualBase) { + visitEnd ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Index& node , bool callVirtualBase) { + visit ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Index& node , bool callVirtualBase) { + visitEnd ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::IntegerLiteral& node , bool callVirtualBase) { + visit ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase) { + visitEnd ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::KeyValue& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::KeyValue& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Keyword& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Keyword& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Lambda& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Lambda& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::List& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::List& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::ListComp& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::ListComp& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Literal& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Literal& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::LongInteger& node , bool callVirtualBase) { + visit ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::LongInteger& node , bool callVirtualBase) { + visitEnd ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Set& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Set& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::SetComp& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::SetComp& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Slice& node , bool callVirtualBase) { + visit ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Slice& node , bool callVirtualBase) { + visitEnd ((expression::Slicing&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Slicing& node , bool callVirtualBase) { + visit ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Slicing& node , bool callVirtualBase) { + visitEnd ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::StringConversion& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::StringConversion& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::StringLiteral& node , bool callVirtualBase) { + visit ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::StringLiteral& node , bool callVirtualBase) { + visitEnd ((expression::Literal&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Subscription& node , bool callVirtualBase) { + visit ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Subscription& node , bool callVirtualBase) { + visitEnd ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::Unary& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::Unary& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::UnaryOperation& node , bool callVirtualBase) { + visit ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::UnaryOperation& node , bool callVirtualBase) { + visitEnd ((expression::Unary&)node,false); +} + +void VisitorAbstractNodes::visit(const expression::YieldExpression& node , bool callVirtualBase) { + visit ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const expression::YieldExpression& node , bool callVirtualBase) { + visitEnd ((expression::Expression&)node,false); +} + +void VisitorAbstractNodes::visit(const module::Module& node , bool callVirtualBase) { + visit ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const module::Module& node , bool callVirtualBase) { + visitEnd ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visit(const module::Object& node , bool callVirtualBase) { + visit ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const module::Object& node , bool callVirtualBase) { + visitEnd ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visit(const module::Package& node , bool callVirtualBase) { + visit ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const module::Package& node , bool callVirtualBase) { + visitEnd ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Alias& node , bool callVirtualBase) { + visit ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Alias& node , bool callVirtualBase) { + visitEnd ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Assert& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Assert& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Assign& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Assign& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::AugAssign& node , bool callVirtualBase) { + visit ((statement::Assign&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::AugAssign& node , bool callVirtualBase) { + visitEnd ((statement::Assign&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::BaseSpecifier& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Break& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Break& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::ClassDef& node , bool callVirtualBase) { + visit ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::ClassDef& node , bool callVirtualBase) { + visitEnd ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::CompoundStatement& node , bool callVirtualBase) { + visit ((statement::Statement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::CompoundStatement& node , bool callVirtualBase) { + visitEnd ((statement::Statement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Continue& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Continue& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Delete& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Delete& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Exec& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Exec& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::For& node , bool callVirtualBase) { + visit ((statement::Iteration&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::For& node , bool callVirtualBase) { + visitEnd ((statement::Iteration&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::FunctionDef& node , bool callVirtualBase) { + visit ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::FunctionDef& node , bool callVirtualBase) { + visitEnd ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Global& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Global& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Handler& node , bool callVirtualBase) { + visit ((statement::Statement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Handler& node , bool callVirtualBase) { + visitEnd ((statement::Statement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::If& node , bool callVirtualBase) { + visit ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::If& node , bool callVirtualBase) { + visitEnd ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::ImportFrom& node , bool callVirtualBase) { + visit ((statement::ImportStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::ImportFrom& node , bool callVirtualBase) { + visitEnd ((statement::ImportStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::ImportStatement& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::ImportStatement& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Iteration& node , bool callVirtualBase) { + visit ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Iteration& node , bool callVirtualBase) { + visitEnd ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Parameter& node , bool callVirtualBase) { + visit ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Parameter& node , bool callVirtualBase) { + visitEnd ((base::Named&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Pass& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Pass& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Print& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Print& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Raise& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Raise& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Return& node , bool callVirtualBase) { + visit ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Return& node , bool callVirtualBase) { + visitEnd ((statement::SimpleStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::SimpleStatement& node , bool callVirtualBase) { + visit ((statement::Statement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::SimpleStatement& node , bool callVirtualBase) { + visitEnd ((statement::Statement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Statement& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Statement& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Suite& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Suite& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::TargetList& node , bool callVirtualBase) { + visit ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::TargetList& node , bool callVirtualBase) { + visitEnd ((base::Positioned&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::Try& node , bool callVirtualBase) { + visit ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::Try& node , bool callVirtualBase) { + visitEnd ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::TryExcept& node , bool callVirtualBase) { + visit ((statement::Try&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::TryExcept& node , bool callVirtualBase) { + visitEnd ((statement::Try&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::TryFinal& node , bool callVirtualBase) { + visit ((statement::Try&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::TryFinal& node , bool callVirtualBase) { + visitEnd ((statement::Try&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::While& node , bool callVirtualBase) { + visit ((statement::Iteration&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::While& node , bool callVirtualBase) { + visitEnd ((statement::Iteration&)node,false); +} + +void VisitorAbstractNodes::visit(const statement::With& node , bool callVirtualBase) { + visit ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const statement::With& node , bool callVirtualBase) { + visitEnd ((statement::CompoundStatement&)node,false); +} + +void VisitorAbstractNodes::visit(const type::DictType& node , bool callVirtualBase) { + visit ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const type::DictType& node , bool callVirtualBase) { + visitEnd ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visit(const type::ReferenceType& node , bool callVirtualBase) { + visit ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const type::ReferenceType& node , bool callVirtualBase) { + visitEnd ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visit(const type::SequenceType& node , bool callVirtualBase) { + visit ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const type::SequenceType& node , bool callVirtualBase) { + visitEnd ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visit(const type::SimpleType& node , bool callVirtualBase) { + visit ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const type::SimpleType& node , bool callVirtualBase) { + visitEnd ((type::Type&)node,false); +} + +void VisitorAbstractNodes::visit(const type::Type& node , bool callVirtualBase) { + visit ((base::Base&)node,false); +} + +void VisitorAbstractNodes::visitEnd(const type::Type& node , bool callVirtualBase) { + visitEnd ((base::Base&)node,false); +} + + +}}} diff --git a/lib/python/src/visitors/VisitorFilter.cpp b/lib/python/src/visitors/VisitorFilter.cpp new file mode 100644 index 0000000..219050a --- /dev/null +++ b/lib/python/src/visitors/VisitorFilter.cpp @@ -0,0 +1,308 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { +VisitorFilter::VisitorFilter(bool filter) : Visitor() ,selector( filter?&Factory::setFilteredThisNodeOnly : &Factory::setNotFilteredThisNodeOnly) { +} + +VisitorFilter::~VisitorFilter() { +} + +void VisitorFilter::visitEnd(const base::Comment& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const base::Docstring& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::ArgumentList& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::AttributeRef& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::BinaryLogical& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Call& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::DictComp& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Dictionary& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Ellipsis& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::ExpressionList& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::ExtSlice& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::FloatNumber& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Generator& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Identifier& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::IfExpression& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::ImagNumber& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Index& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::KeyValue& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Keyword& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Lambda& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::List& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::ListComp& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::LongInteger& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Set& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::SetComp& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Slice& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::StringConversion& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::StringLiteral& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::Subscription& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::UnaryOperation& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const expression::YieldExpression& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const module::Module& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const module::Object& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const module::Package& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Alias& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Assert& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Assign& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::AugAssign& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Break& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::ClassDef& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Continue& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Delete& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Exec& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::For& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::FunctionDef& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Global& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Handler& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::If& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::ImportFrom& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::ImportStatement& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Parameter& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Pass& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Print& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Raise& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Return& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::Suite& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::TargetList& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::TryExcept& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::TryFinal& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::While& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const statement::With& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const type::DictType& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const type::ReferenceType& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const type::SequenceType& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + +void VisitorFilter::visitEnd(const type::SimpleType& node , bool callVirtualBase /*= true*/) { + (node.getFactory().*selector)(node.getId()); +} + + +}}} diff --git a/lib/python/src/visitors/VisitorPYTHONML.cpp b/lib/python/src/visitors/VisitorPYTHONML.cpp new file mode 100644 index 0000000..f001a46 --- /dev/null +++ b/lib/python/src/visitors/VisitorPYTHONML.cpp @@ -0,0 +1,2801 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + +using namespace std; + + +namespace columbus { namespace python { namespace asg { +VisitorPYTHONML::VisitorPYTHONML(std::ofstream& targetStream, + const std::string& _projectName, + bool _noId, + bool _noLineInfo) : ofs(targetStream), noId(_noId), noLineInfo(_noLineInfo), projectName(_projectName) +{ +} + +VisitorPYTHONML::~VisitorPYTHONML() { +} + +void VisitorPYTHONML::beginVisit() { + ofs << "\n"; + ofs << "\n"; + ofs << "\n"; +} + +void VisitorPYTHONML::finishVisit() { + ofs << "\n"; + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const base::Comment& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const base::Comment& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const base::Docstring& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const base::Docstring& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::ArgumentList& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::ArgumentList& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::AttributeRef& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::AttributeRef& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::BinaryArithmetic& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::BinaryArithmetic& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::BinaryLogical& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::BinaryLogical& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Call& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Call& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::DictComp& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::DictComp& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Dictionary& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Dictionary& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Ellipsis& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Ellipsis& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::ExpressionList& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::ExpressionList& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::ExtSlice& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::ExtSlice& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::FloatNumber& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::FloatNumber& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Generator& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Generator& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::GeneratorExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::GeneratorExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Identifier& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Identifier& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::IfExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::IfExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::ImagNumber& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::ImagNumber& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Index& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Index& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::IntegerLiteral& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::IntegerLiteral& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::KeyValue& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::KeyValue& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Keyword& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Keyword& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Lambda& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Lambda& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::List& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::List& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::ListComp& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::ListComp& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::LongInteger& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::LongInteger& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Set& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Set& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::SetComp& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::SetComp& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Slice& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Slice& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::StringConversion& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::StringConversion& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::StringLiteral& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::StringLiteral& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::Subscription& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::Subscription& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::UnaryOperation& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::UnaryOperation& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const expression::YieldExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const expression::YieldExpression& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const module::Module& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const module::Module& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const module::Object& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const module::Object& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const module::Package& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const module::Package& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Alias& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Alias& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Assert& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Assert& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Assign& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Assign& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::AugAssign& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::AugAssign& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::BaseSpecifier& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::BaseSpecifier& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Break& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Break& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::ClassDef& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::ClassDef& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Continue& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Continue& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Delete& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Delete& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Exec& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Exec& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::For& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::For& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::FunctionDef& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::FunctionDef& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Global& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Global& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Handler& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Handler& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::If& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::If& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::ImportFrom& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::ImportFrom& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::ImportStatement& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::ImportStatement& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Parameter& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Parameter& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Pass& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Pass& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Print& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Print& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Raise& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Raise& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Return& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Return& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::Suite& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::Suite& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::TargetList& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::TargetList& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::TryExcept& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::TryExcept& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::TryFinal& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::TryFinal& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::While& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::While& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const statement::With& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const statement::With& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const type::DictType& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const type::DictType& node , bool callVirtualBase) { +} + +void VisitorPYTHONML::visit(const type::ReferenceType& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const type::ReferenceType& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visit(const type::SequenceType& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const type::SequenceType& node , bool callVirtualBase) { +} + +void VisitorPYTHONML::visit(const type::SimpleType& node , bool callVirtualBase) { + createIndentation(); + ofs << "\n"; + + writeAttributes(node,true,true); +} + +void VisitorPYTHONML::visitEnd(const type::SimpleType& node , bool callVirtualBase) { +} + +void VisitorPYTHONML::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { +} + +void VisitorPYTHONML::visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { +} + +void VisitorPYTHONML::visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitExpression_HasType(const expression::Expression& begin, const type::Type& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndExpression_HasType(const expression::Expression& begin, const type::Type& end) { +} + +void VisitorPYTHONML::visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { +} + +void VisitorPYTHONML::visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitList_HasExpression(const expression::List& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndList_HasExpression(const expression::List& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitModule_HasObject(const module::Module& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndModule_HasObject(const module::Module& begin, const module::Object& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitModule_HasStatement(const module::Module& begin, const base::Positioned& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndModule_HasStatement(const module::Module& begin, const base::Positioned& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitModule_Docstring(const module::Module& begin, const base::Docstring& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndModule_Docstring(const module::Module& begin, const base::Docstring& end) { +} + +void VisitorPYTHONML::visitObject_RefersTo(const module::Object& begin, const base::Positioned& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndObject_RefersTo(const module::Object& begin, const base::Positioned& end) { +} + +void VisitorPYTHONML::visitObject_HasType(const module::Object& begin, const type::Type& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndObject_HasType(const module::Object& begin, const type::Type& end) { +} + +void VisitorPYTHONML::visitPackage_HasModule(const module::Package& begin, const module::Module& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndPackage_HasModule(const module::Package& begin, const module::Module& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitPackage_HasPackage(const module::Package& begin, const module::Package& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndPackage_HasPackage(const module::Package& begin, const module::Package& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { +} + +void VisitorPYTHONML::visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { +} + +void VisitorPYTHONML::visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { +} + +void VisitorPYTHONML::visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { +} + +void VisitorPYTHONML::visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { +} + +void VisitorPYTHONML::visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { +} + +void VisitorPYTHONML::visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { +} + +void VisitorPYTHONML::visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { +} + +void VisitorPYTHONML::visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitWith_HasExpression(const statement::With& begin, const expression::Expression& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndWith_HasExpression(const statement::With& begin, const expression::Expression& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { + createIndentation(); + ofs << "\n"; + incDepth(); +} + +void VisitorPYTHONML::visitEndWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { + decDepth(); + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { + createIndentation(); + ofs << "\n"; +} + +void VisitorPYTHONML::visitEndReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { +} + +void VisitorPYTHONML::createIndentation() { + if (depth) + ofs << std::string(depth, '\t'); +} + +string VisitorPYTHONML::chk(string s) { + string::size_type pos = (string::size_type)-1; + while ((pos = s.find("&", pos + 1)) != string::npos) + s.replace(pos, 1, "&"); + + while ((pos = s.find("<", pos + 1)) != string::npos) + s.replace(pos,1, "<"); + + while ((pos = s.find(">", pos + 1)) != string::npos) + s.replace(pos,1, ">"); + + while ((pos = s.find("'", pos + 1)) != string::npos) + s.replace(pos,1,"'"); + + while ((pos = s.find("\"", pos + 1)) != string::npos) + s.replace(pos,1,"""); + + while ((pos = s.find("\r", pos + 1)) != string::npos) + s.replace(pos,1, " "); + + while ((pos = s.find("\n", pos + 1)) != string::npos) + s.replace(pos,1, " "); + + while ((pos = s.find("\t", pos + 1)) != string::npos) + s.replace(pos,1, " "); + + return s; +} + +void VisitorPYTHONML::writeRange(const char *name, const Range &range) { + if(noLineInfo) return; + incDepth(); + createIndentation(); + ofs << "<" << name << " path='" << chk(range.getPath()) << "'"; + ofs << " line='" << range.getLine() << "'"; + ofs << " col='" << range.getCol() << "'"; + ofs << " endLine='" << range.getEndLine() << "'"; + ofs << " endCol='" << range.getEndCol() << "'"; + ofs << "/>\n"; + decDepth(); +} + +void VisitorPYTHONML::writeAttributes(const base::Base& node,bool composite, bool bWithParent /*= true*/ ) { + if (!composite) { + ofs << " id='"; + if (!noId) + ofs << "id" << node.getId(); + ofs << "'"; + + } + if (!composite) { + ofs << " parent='"; + if (!noId) + ofs << "id" << (node.getParent() ? node.getParent()->getId() : 0); + ofs << "'"; + + } + if (!composite) { + } + if (!composite) { + ofs << " originKind='" << Common::toString(node.getOriginKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const base::Comment& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + + if (!composite) { + ofs << " text='" << chk(node.getText()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const base::Docstring& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + + if (!composite) { + ofs << " text='" << chk(node.getText()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const base::Named& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const base::Positioned& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Base&)node,composite,false); + + if (composite) { + writeRange("Position", node.getPosition()); + } +} + +void VisitorPYTHONML::writeAttributes(const expression::ArgumentList& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::AttributeRef& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Binary&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Binary& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::BinaryArithmetic& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Binary&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::BinaryLogical& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Binary&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::Call& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Unary&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::DictComp& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Dictionary& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Ellipsis& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Slicing&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Expression& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::ExpressionList& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + + if (!composite) { + ofs << " isYieldExpression='" << (node.getIsYieldExpression() ? "true" : "false") << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::ExtSlice& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Slicing&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::FloatNumber& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Literal&)node,composite,false); + + if (!composite) { + ofs << " value='" << node.getValue() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::Generator& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::GeneratorExpression& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Identifier& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::IfExpression& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::ImagNumber& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Literal&)node,composite,false); + + if (!composite) { + ofs << " im='" << node.getIm() << "'"; + } + if (!composite) { + ofs << " real='" << node.getReal() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::Index& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Slicing&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::IntegerLiteral& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Literal&)node,composite,false); + + if (!composite) { + ofs << " value='" << node.getValue() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::KeyValue& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Keyword& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Lambda& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::List& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + + if (!composite) { + ofs << " isTuple='" << (node.getIsTuple() ? "true" : "false") << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::ListComp& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Literal& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::LongInteger& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Literal&)node,composite,false); + + if (!composite) { + ofs << " value='" << node.getValue() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::Set& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::SetComp& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Slice& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Slicing&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Slicing& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Unary&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::StringConversion& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::StringLiteral& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Literal&)node,composite,false); + + if (!composite) { + ofs << " value='" << chk(node.getValue()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::Subscription& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Unary&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::Unary& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const expression::UnaryOperation& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Unary&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const expression::YieldExpression& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((expression::Expression&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const module::Module& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Named&)node,composite,false); + + if (!composite) { + ofs << " lloc='" << node.getLloc() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const module::Object& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Base&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const module::Package& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Base&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } + if (!composite) { + ofs << " path='" << chk(node.getPath()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::Alias& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Named&)node,composite,false); + + if (!composite) { + ofs << " alias='" << chk(node.getAlias()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::Assert& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Assign& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::AugAssign& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Assign&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::BaseSpecifier& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Break& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::ClassDef& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::CompoundStatement&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } + if (!composite) { + ofs << " lloc='" << node.getLloc() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::CompoundStatement& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Statement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Continue& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Delete& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Exec& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::For& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Iteration&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::FunctionDef& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::CompoundStatement&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } + if (!composite) { + ofs << " lloc='" << node.getLloc() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::Global& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Handler& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Statement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::If& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::CompoundStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::ImportFrom& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::ImportStatement&)node,composite,false); + + if (!composite) { + ofs << " modulname='" << chk(node.getModulname()) << "'"; + } + if (!composite) { + ofs << " level='" << node.getLevel() << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::ImportStatement& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Iteration& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::CompoundStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Parameter& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Named&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::Pass& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Print& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + + if (!composite) { + ofs << " nl='" << (node.getNl() ? "true" : "false") << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const statement::Raise& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Return& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::SimpleStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::SimpleStatement& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Statement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Statement& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Suite& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::TargetList& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Positioned&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::Try& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::CompoundStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::TryExcept& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Try&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::TryFinal& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Try&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::While& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::Iteration&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const statement::With& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((statement::CompoundStatement&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const type::DictType& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((type::Type&)node,composite,false); + +} + +void VisitorPYTHONML::writeAttributes(const type::ReferenceType& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((type::Type&)node,composite,false); + + if (!composite) { + ofs << " name='" << chk(node.getName()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const type::SequenceType& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((type::Type&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const type::SimpleType& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((type::Type&)node,composite,false); + + if (!composite) { + ofs << " kind='" << Common::toString(node.getKind()) << "'"; + } +} + +void VisitorPYTHONML::writeAttributes(const type::Type& node,bool composite, bool bWithParent /*= true*/ ) { + writeAttributes((base::Base&)node,composite,false); + +} + + +}}} diff --git a/lib/python/src/visitors/VisitorReverseEdges.cpp b/lib/python/src/visitors/VisitorReverseEdges.cpp new file mode 100644 index 0000000..bdc8dba --- /dev/null +++ b/lib/python/src/visitors/VisitorReverseEdges.cpp @@ -0,0 +1,445 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + +namespace columbus { namespace python { namespace asg { +VisitorReverseEdges::VisitorReverseEdges(ReverseEdges *reverseEdges) : VisitorAbstractNodes(), revEdges(reverseEdges) { +} + +VisitorReverseEdges::~VisitorReverseEdges() { +} + +void VisitorReverseEdges::visit(const base::Base &node, bool callVirtualBase ) { + NodeId id = node.getId(); + if (!revEdges->reContainer[id]) + revEdges->reContainer[id] = new ReverseEdges::NodeEdgesType(); +} + +void VisitorReverseEdges::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { + revEdges->insertEdge(&end, &begin, edkPositioned_Comments); +} + +void VisitorReverseEdges::visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { + revEdges->insertEdge(&end, &begin, edkArgumentList_HasPositionalArguments); +} + +void VisitorReverseEdges::visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkArgumentList_HasDictionary); +} + +void VisitorReverseEdges::visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { + revEdges->insertEdge(&end, &begin, edkArgumentList_HasKeyword); +} + +void VisitorReverseEdges::visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkArgumentList_HasTuple); +} + +void VisitorReverseEdges::visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkBinary_HasLeftExpression); +} + +void VisitorReverseEdges::visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkBinary_HasRightExpression); +} + +void VisitorReverseEdges::visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { + revEdges->insertEdge(&end, &begin, edkCall_HasArgumentList); +} + +void VisitorReverseEdges::visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { + revEdges->insertEdge(&end, &begin, edkCall_RefersTo); +} + +void VisitorReverseEdges::visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { + revEdges->insertEdge(&end, &begin, edkDictComp_HasKeyValue); +} + +void VisitorReverseEdges::visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { + revEdges->insertEdge(&end, &begin, edkDictComp_HasGenerator); +} + +void VisitorReverseEdges::visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { + revEdges->insertEdge(&end, &begin, edkDictionary_HasKeyValue); +} + +void VisitorReverseEdges::visitExpression_HasType(const expression::Expression& begin, const type::Type& end) { + revEdges->insertEdge(&end, &begin, edkExpression_HasType); +} + +void VisitorReverseEdges::visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkExpressionList_HasExpression); +} + +void VisitorReverseEdges::visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { + revEdges->insertEdge(&end, &begin, edkExtSlice_HasItem); +} + +void VisitorReverseEdges::visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkGenerator_HasCondition); +} + +void VisitorReverseEdges::visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkGenerator_HasIter); +} + +void VisitorReverseEdges::visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkGenerator_HasTarget); +} + +void VisitorReverseEdges::visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkGeneratorExpression_HasExpression); +} + +void VisitorReverseEdges::visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { + revEdges->insertEdge(&end, &begin, edkGeneratorExpression_HasGenerator); +} + +void VisitorReverseEdges::visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkIdentifier_RefersTo); +} + +void VisitorReverseEdges::visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkIfExpression_HasBody); +} + +void VisitorReverseEdges::visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkIfExpression_HasElseBody); +} + +void VisitorReverseEdges::visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkIfExpression_HasTest); +} + +void VisitorReverseEdges::visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkKeyValue_HasKey); +} + +void VisitorReverseEdges::visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkKeyValue_HasValue); +} + +void VisitorReverseEdges::visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { + revEdges->insertEdge(&end, &begin, edkKeyword_HasKey); +} + +void VisitorReverseEdges::visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkKeyword_HasValue); +} + +void VisitorReverseEdges::visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkLambda_HasObject); +} + +void VisitorReverseEdges::visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { + revEdges->insertEdge(&end, &begin, edkLambda_HasParameter); +} + +void VisitorReverseEdges::visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkLambda_HasExpression); +} + +void VisitorReverseEdges::visitList_HasExpression(const expression::List& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkList_HasExpression); +} + +void VisitorReverseEdges::visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkListComp_HasExpression); +} + +void VisitorReverseEdges::visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { + revEdges->insertEdge(&end, &begin, edkListComp_HasGenerator); +} + +void VisitorReverseEdges::visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkSet_HasExpression); +} + +void VisitorReverseEdges::visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkSetComp_HasExpression); +} + +void VisitorReverseEdges::visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { + revEdges->insertEdge(&end, &begin, edkSetComp_HasGenerator); +} + +void VisitorReverseEdges::visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkSlice_HasLowerBound); +} + +void VisitorReverseEdges::visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkSlice_HasStride); +} + +void VisitorReverseEdges::visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkSlice_HasUpperBound); +} + +void VisitorReverseEdges::visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { + revEdges->insertEdge(&end, &begin, edkStringConversion_HasExpressionList); +} + +void VisitorReverseEdges::visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { + revEdges->insertEdge(&end, &begin, edkSubscription_HasSlicing); +} + +void VisitorReverseEdges::visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkUnary_HasExpression); +} + +void VisitorReverseEdges::visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { + revEdges->insertEdge(&end, &begin, edkYieldExpression_HasYieldExpression); +} + +void VisitorReverseEdges::visitModule_HasObject(const module::Module& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkModule_HasObject); +} + +void VisitorReverseEdges::visitModule_HasStatement(const module::Module& begin, const base::Positioned& end) { + revEdges->insertEdge(&end, &begin, edkModule_HasStatement); +} + +void VisitorReverseEdges::visitModule_Docstring(const module::Module& begin, const base::Docstring& end) { + revEdges->insertEdge(&end, &begin, edkModule_Docstring); +} + +void VisitorReverseEdges::visitObject_RefersTo(const module::Object& begin, const base::Positioned& end) { + revEdges->insertEdge(&end, &begin, edkObject_RefersTo); +} + +void VisitorReverseEdges::visitObject_HasType(const module::Object& begin, const type::Type& end) { + revEdges->insertEdge(&end, &begin, edkObject_HasType); +} + +void VisitorReverseEdges::visitPackage_HasModule(const module::Package& begin, const module::Module& end) { + revEdges->insertEdge(&end, &begin, edkPackage_HasModule); +} + +void VisitorReverseEdges::visitPackage_HasPackage(const module::Package& begin, const module::Package& end) { + revEdges->insertEdge(&end, &begin, edkPackage_HasPackage); +} + +void VisitorReverseEdges::visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { + revEdges->insertEdge(&end, &begin, edkAlias_RefersTo); +} + +void VisitorReverseEdges::visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkAssert_HasMsgExpression); +} + +void VisitorReverseEdges::visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkAssert_HasTestExpression); +} + +void VisitorReverseEdges::visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkAssign_HasExpression); +} + +void VisitorReverseEdges::visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { + revEdges->insertEdge(&end, &begin, edkAssign_HasTargetList); +} + +void VisitorReverseEdges::visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkBaseSpecifier_HasName); +} + +void VisitorReverseEdges::visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { + revEdges->insertEdge(&end, &begin, edkBaseSpecifier_DerivesFrom); +} + +void VisitorReverseEdges::visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkClassDef_HasObject); +} + +void VisitorReverseEdges::visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { + revEdges->insertEdge(&end, &begin, edkClassDef_HasBaseSpecifier); +} + +void VisitorReverseEdges::visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkClassDef_HasDecorator); +} + +void VisitorReverseEdges::visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkClassDef_RefersTo); +} + +void VisitorReverseEdges::visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { + revEdges->insertEdge(&end, &begin, edkClassDef_Docstring); +} + +void VisitorReverseEdges::visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkCompoundStatement_HasBody); +} + +void VisitorReverseEdges::visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { + revEdges->insertEdge(&end, &begin, edkDelete_HasTargetList); +} + +void VisitorReverseEdges::visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkExec_HasExpression); +} + +void VisitorReverseEdges::visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkExec_HasGlobals); +} + +void VisitorReverseEdges::visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkExec_HasLocals); +} + +void VisitorReverseEdges::visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { + revEdges->insertEdge(&end, &begin, edkFor_HasExpressionList); +} + +void VisitorReverseEdges::visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { + revEdges->insertEdge(&end, &begin, edkFor_HasTargetList); +} + +void VisitorReverseEdges::visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkFunctionDef_HasDecorator); +} + +void VisitorReverseEdges::visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkFunctionDef_HasObject); +} + +void VisitorReverseEdges::visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { + revEdges->insertEdge(&end, &begin, edkFunctionDef_HasParameter); +} + +void VisitorReverseEdges::visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkFunctionDef_RefersTo); +} + +void VisitorReverseEdges::visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { + revEdges->insertEdge(&end, &begin, edkFunctionDef_ReturnType); +} + +void VisitorReverseEdges::visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { + revEdges->insertEdge(&end, &begin, edkFunctionDef_Docstring); +} + +void VisitorReverseEdges::visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { + revEdges->insertEdge(&end, &begin, edkGlobal_HasIdentifier); +} + +void VisitorReverseEdges::visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkHandler_HasName); +} + +void VisitorReverseEdges::visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkHandler_HasExceptBody); +} + +void VisitorReverseEdges::visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkHandler_HasType); +} + +void VisitorReverseEdges::visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkIf_HasElseBody); +} + +void VisitorReverseEdges::visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkIf_HasTestExpression); +} + +void VisitorReverseEdges::visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { + revEdges->insertEdge(&end, &begin, edkImportStatement_HasAlias); +} + +void VisitorReverseEdges::visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkIteration_HasElseBody); +} + +void VisitorReverseEdges::visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkParameter_HasDefaultValue); +} + +void VisitorReverseEdges::visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { + revEdges->insertEdge(&end, &begin, edkParameter_RefersTo); +} + +void VisitorReverseEdges::visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { + revEdges->insertEdge(&end, &begin, edkPrint_HasExpressionList); +} + +void VisitorReverseEdges::visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkPrint_HasDestination); +} + +void VisitorReverseEdges::visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkRaise_HasTracebackExpression); +} + +void VisitorReverseEdges::visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkRaise_HasTypeExpression); +} + +void VisitorReverseEdges::visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkRaise_HasValueExpression); +} + +void VisitorReverseEdges::visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkReturn_HasExpression); +} + +void VisitorReverseEdges::visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { + revEdges->insertEdge(&end, &begin, edkSuite_HasStatement); +} + +void VisitorReverseEdges::visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkTargetList_HasTarget); +} + +void VisitorReverseEdges::visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkTryExcept_HasElseBody); +} + +void VisitorReverseEdges::visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { + revEdges->insertEdge(&end, &begin, edkTryExcept_HasHandler); +} + +void VisitorReverseEdges::visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkTryExcept_HasFinallyBody); +} + +void VisitorReverseEdges::visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { + revEdges->insertEdge(&end, &begin, edkTryFinal_HasFinallyBody); +} + +void VisitorReverseEdges::visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkWhile_HasTestExpression); +} + +void VisitorReverseEdges::visitWith_HasExpression(const statement::With& begin, const expression::Expression& end) { + revEdges->insertEdge(&end, &begin, edkWith_HasExpression); +} + +void VisitorReverseEdges::visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { + revEdges->insertEdge(&end, &begin, edkWith_HasTargetList); +} + +void VisitorReverseEdges::visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { + revEdges->insertEdge(&end, &begin, edkReferenceType_RefersTo); +} + + +}}} diff --git a/lib/python/src/visitors/VisitorSave.cpp b/lib/python/src/visitors/VisitorSave.cpp new file mode 100644 index 0000000..f0a83b9 --- /dev/null +++ b/lib/python/src/visitors/VisitorSave.cpp @@ -0,0 +1,33 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { + VisitorSave::VisitorSave(io::BinaryIO &_io) : VisitorAbstractNodes(), m_io(_io) { + } + + void VisitorSave::visitEnd(const base::Base &node , bool callVirtualBase) { + node.save(m_io); + } + + +}}} diff --git a/lib/python/src/visitors/VisitorSimpleEdge.cpp b/lib/python/src/visitors/VisitorSimpleEdge.cpp new file mode 100644 index 0000000..6c9cb3f --- /dev/null +++ b/lib/python/src/visitors/VisitorSimpleEdge.cpp @@ -0,0 +1,1664 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + +/** +* \file VisitorSimpleEdge.cpp +* \brief Contains declaration of VisitorSimpleEdge class. +*/ + +namespace columbus { namespace python { namespace asg { + VisitorSimpleEdge::~VisitorSimpleEdge(){}; + + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for comments edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPositioned_Comments(const base::Positioned& begin, const base::Comment& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasPositionalArguments edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndArgumentList_HasPositionalArguments(const expression::ArgumentList& begin, const expression::ExpressionList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasDictionary edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndArgumentList_HasDictionary(const expression::ArgumentList& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasKeyword edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndArgumentList_HasKeyword(const expression::ArgumentList& begin, const expression::Keyword& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTuple edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndArgumentList_HasTuple(const expression::ArgumentList& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasLeftExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndBinary_HasLeftExpression(const expression::Binary& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasRightExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndBinary_HasRightExpression(const expression::Binary& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasArgumentList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndCall_HasArgumentList(const expression::Call& begin, const expression::ArgumentList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndCall_RefersTo(const expression::Call& begin, const statement::CompoundStatement& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndDictComp_HasKeyValue(const expression::DictComp& begin, const expression::KeyValue& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndDictComp_HasGenerator(const expression::DictComp& begin, const expression::Generator& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasKeyValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndDictionary_HasKeyValue(const expression::Dictionary& begin, const expression::KeyValue& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExpression_HasType(const expression::Expression& begin, const type::Type& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExpression_HasType(const expression::Expression& begin, const type::Type& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExpressionList_HasExpression(const expression::ExpressionList& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasItem edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExtSlice_HasItem(const expression::ExtSlice& begin, const expression::Slicing& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasCondition edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndGenerator_HasCondition(const expression::Generator& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasIter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndGenerator_HasIter(const expression::Generator& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndGenerator_HasTarget(const expression::Generator& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndGeneratorExpression_HasExpression(const expression::GeneratorExpression& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndGeneratorExpression_HasGenerator(const expression::GeneratorExpression& begin, const expression::Generator& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIdentifier_RefersTo(const expression::Identifier& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIfExpression_HasBody(const expression::IfExpression& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIfExpression_HasElseBody(const expression::IfExpression& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTest edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIfExpression_HasTest(const expression::IfExpression& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndKeyValue_HasKey(const expression::KeyValue& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndKeyValue_HasValue(const expression::KeyValue& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasKey edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndKeyword_HasKey(const expression::Keyword& begin, const expression::Identifier& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndKeyword_HasValue(const expression::Keyword& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndLambda_HasObject(const expression::Lambda& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndLambda_HasParameter(const expression::Lambda& begin, const statement::Parameter& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndLambda_HasExpression(const expression::Lambda& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitList_HasExpression(const expression::List& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndList_HasExpression(const expression::List& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndListComp_HasExpression(const expression::ListComp& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndListComp_HasGenerator(const expression::ListComp& begin, const expression::Generator& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSet_HasExpression(const expression::Set& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSetComp_HasExpression(const expression::SetComp& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasGenerator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSetComp_HasGenerator(const expression::SetComp& begin, const expression::Generator& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasLowerBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSlice_HasLowerBound(const expression::Slice& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasStride edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSlice_HasStride(const expression::Slice& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasUpperBound edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSlice_HasUpperBound(const expression::Slice& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndStringConversion_HasExpressionList(const expression::StringConversion& begin, const expression::ExpressionList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasSlicing edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSubscription_HasSlicing(const expression::Subscription& begin, const expression::Slicing& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndUnary_HasExpression(const expression::Unary& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasYieldExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndYieldExpression_HasYieldExpression(const expression::YieldExpression& begin, const expression::ExpressionList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitModule_HasObject(const module::Module& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndModule_HasObject(const module::Module& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitModule_HasStatement(const module::Module& begin, const base::Positioned& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndModule_HasStatement(const module::Module& begin, const base::Positioned& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitModule_Docstring(const module::Module& begin, const base::Docstring& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndModule_Docstring(const module::Module& begin, const base::Docstring& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitObject_RefersTo(const module::Object& begin, const base::Positioned& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndObject_RefersTo(const module::Object& begin, const base::Positioned& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitObject_HasType(const module::Object& begin, const type::Type& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for hasType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndObject_HasType(const module::Object& begin, const type::Type& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPackage_HasModule(const module::Package& begin, const module::Module& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasModule edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPackage_HasModule(const module::Package& begin, const module::Module& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPackage_HasPackage(const module::Package& begin, const module::Package& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasPackage edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPackage_HasPackage(const module::Package& begin, const module::Package& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndAlias_RefersTo(const statement::Alias& begin, const base::Base& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasMsgExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndAssert_HasMsgExpression(const statement::Assert& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndAssert_HasTestExpression(const statement::Assert& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndAssign_HasExpression(const statement::Assign& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndAssign_HasTargetList(const statement::Assign& begin, const statement::TargetList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndBaseSpecifier_HasName(const statement::BaseSpecifier& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for derivesFrom edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndBaseSpecifier_DerivesFrom(const statement::BaseSpecifier& begin, const statement::ClassDef& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndClassDef_HasObject(const statement::ClassDef& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasBaseSpecifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndClassDef_HasBaseSpecifier(const statement::ClassDef& begin, const statement::BaseSpecifier& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndClassDef_HasDecorator(const statement::ClassDef& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndClassDef_RefersTo(const statement::ClassDef& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndClassDef_Docstring(const statement::ClassDef& begin, const base::Docstring& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndCompoundStatement_HasBody(const statement::CompoundStatement& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndDelete_HasTargetList(const statement::Delete& begin, const statement::TargetList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExec_HasExpression(const statement::Exec& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasGlobals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExec_HasGlobals(const statement::Exec& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasLocals edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndExec_HasLocals(const statement::Exec& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFor_HasExpressionList(const statement::For& begin, const expression::ExpressionList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFor_HasTargetList(const statement::For& begin, const statement::TargetList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasDecorator edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFunctionDef_HasDecorator(const statement::FunctionDef& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasObject edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFunctionDef_HasObject(const statement::FunctionDef& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasParameter edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFunctionDef_HasParameter(const statement::FunctionDef& begin, const statement::Parameter& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFunctionDef_RefersTo(const statement::FunctionDef& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for returnType edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFunctionDef_ReturnType(const statement::FunctionDef& begin, const type::Type& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for docstring edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndFunctionDef_Docstring(const statement::FunctionDef& begin, const base::Docstring& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasIdentifier edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndGlobal_HasIdentifier(const statement::Global& begin, const expression::Identifier& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasName edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndHandler_HasName(const statement::Handler& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExceptBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndHandler_HasExceptBody(const statement::Handler& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasType edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndHandler_HasType(const statement::Handler& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIf_HasElseBody(const statement::If& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIf_HasTestExpression(const statement::If& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasAlias edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndImportStatement_HasAlias(const statement::ImportStatement& begin, const statement::Alias& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndIteration_HasElseBody(const statement::Iteration& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasDefaultValue edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndParameter_HasDefaultValue(const statement::Parameter& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndParameter_RefersTo(const statement::Parameter& begin, const module::Object& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpressionList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPrint_HasExpressionList(const statement::Print& begin, const expression::ExpressionList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasDestination edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndPrint_HasDestination(const statement::Print& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTracebackExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndRaise_HasTracebackExpression(const statement::Raise& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTypeExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndRaise_HasTypeExpression(const statement::Raise& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasValueExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndRaise_HasValueExpression(const statement::Raise& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndReturn_HasExpression(const statement::Return& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasStatement edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndSuite_HasStatement(const statement::Suite& begin, const base::Positioned& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTarget edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndTargetList_HasTarget(const statement::TargetList& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasElseBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndTryExcept_HasElseBody(const statement::TryExcept& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasHandler edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndTryExcept_HasHandler(const statement::TryExcept& begin, const statement::Handler& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndTryExcept_HasFinallyBody(const statement::TryExcept& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasFinallyBody edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndTryFinal_HasFinallyBody(const statement::TryFinal& begin, const statement::Suite& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTestExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndWhile_HasTestExpression(const statement::While& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitWith_HasExpression(const statement::With& begin, const expression::Expression& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasExpression edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndWith_HasExpression(const statement::With& begin, const expression::Expression& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge end visitor for hasTargetList edge which is called when the subtree of this edge is started. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndWith_HasTargetList(const statement::With& begin, const statement::TargetList& end) { + visitAllEdgeEnd (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { + visitAllEdge (begin, end); + } + /** + * \brief Edge visitor for refersTo edge which. + * \param begin [in] The reference of the node the edge starts from. + * \param end [in] The reference of the node the edge points to. + */ + void VisitorSimpleEdge::visitEndReferenceType_RefersTo(const type::ReferenceType& begin, const base::Positioned& end) { + visitAllEdgeEnd (begin, end); + } + +}}} diff --git a/lib/python/src/visitors/VisitorSubtreeCollector.cpp b/lib/python/src/visitors/VisitorSubtreeCollector.cpp new file mode 100644 index 0000000..f0bae4d --- /dev/null +++ b/lib/python/src/visitors/VisitorSubtreeCollector.cpp @@ -0,0 +1,33 @@ +/* + * This file is part of OpenStaticAnalyzer. + * + * Copyright (c) 2004-2017 Department of Software Engineering - University of Szeged + * + * Licensed under Version 1.2 of the EUPL (the "Licence"); + * + * You may not use this work except in compliance with the Licence. + * + * You may obtain a copy of the Licence in the LICENSE file or at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + */ + +#include "python/inc/python.h" + + +namespace columbus { namespace python { namespace asg { + VisitorSubtreeCollector::VisitorSubtreeCollector(std::list< NodeId> &_nodelist) : VisitorAbstractNodes(), nodelist(_nodelist) { + } + + void VisitorSubtreeCollector::visit(const base::Base &node, bool callVirtualBase /*= true*/) { + nodelist.push_back(node.getId()); + } + + +}}} diff --git a/lib/rul/inc/RulHandler.h b/lib/rul/inc/RulHandler.h index ad875f1..24d5f57 100644 --- a/lib/rul/inc/RulHandler.h +++ b/lib/rul/inc/RulHandler.h @@ -80,6 +80,10 @@ class RulHandler { : text(_empty_string) , editable(rulUndefined) {} + bool operator==(const std::string& text) const + { + return this->text == text; + } }; @@ -326,7 +330,7 @@ class RulHandler { const R& getConfSpecData (const std::string& ruleId, T key, const R& wrongValue) const; template - void getConfSpecDataFromMap (const std::string& ruleId, const N& name, T key, R& retvalue, bool& found) const; + void getConfSpecDataFromMap (const std::string& ruleId, const N& name, T key, R& retvalue, const std::string& wrongValue, bool& found) const; template void getMetricGroupMembers(const std::string& ruleId, std::insert_iterator insertIt ) const; diff --git a/lib/rul/src/RulHandler.cpp b/lib/rul/src/RulHandler.cpp index 09af30f..c298a8d 100644 --- a/lib/rul/src/RulHandler.cpp +++ b/lib/rul/src/RulHandler.cpp @@ -551,7 +551,7 @@ string RulHandler::getBaselineValue(const string& ruleId, const string& baseline { map::const_iterator baselineIt; bool found = false; - getConfSpecDataFromMap(ruleId, baselineName, &RulConfiguration::baselines, baselineIt, found); + getConfSpecDataFromMap(ruleId, baselineName, &RulConfiguration::baselines, baselineIt, _empty_string, found); if(found) { return baselineIt->second; } else { @@ -579,7 +579,7 @@ string RulHandler::getSettingValue(const string& ruleId, const string& settingNa { map::const_iterator settingIt; bool found = false; - getConfSpecDataFromMap(ruleId, settingName, &RulConfiguration::settings, settingIt, found); + getConfSpecDataFromMap(ruleId, settingName, &RulConfiguration::settings, settingIt, _empty_string, found); if(found) { return settingIt->second.text; } else { @@ -625,7 +625,7 @@ bool RulHandler::getSettingIsEditable(const string& ruleId, const string& settin { map::const_iterator settingIt; bool found = false; - getConfSpecDataFromMap(ruleId, settingName, &RulConfiguration::settings, settingIt, found); + getConfSpecDataFromMap(ruleId, settingName, &RulConfiguration::settings, settingIt, _empty_string, found); if(found) { return settingIt->second.editable == rulTrue; } else { @@ -1525,7 +1525,7 @@ void RulHandler::setConfSpecData (const string& ruleId, const string& configurat } template -void RulHandler::getConfSpecDataFromMap (const string& ruleId, const N& name, T key, R& retvalue, bool& found ) const +void RulHandler::getConfSpecDataFromMap (const string& ruleId, const N& name, T key, R& retvalue, const string& wrongValue, bool& found ) const { const RulMetric* metric = findMetric(ruleId); found = false; @@ -1533,7 +1533,7 @@ void RulHandler::getConfSpecDataFromMap (const string& ruleId, const N& name, T const RulConfiguration* rulConfig = metric->actualConfig; while(rulConfig != NULL) { retvalue = (rulConfig->*key).find(name); - if(!_strictMode && (retvalue == (rulConfig->*key).end()) ) { + if(!_strictMode && ((retvalue == (rulConfig->*key).end()) || retvalue->second == wrongValue)) { rulConfig = getParentConfig(rulConfig); } else { found = true; @@ -1596,7 +1596,7 @@ class RulXmlHandler : public DefaultHandler char* xmlTranscode(const XMLCh* xmlCh) { XMLSize_t inputSize = XMLString::stringLen(xmlCh); - XMLByte* buffer = new XMLByte[inputSize * 2]; + XMLByte* buffer = new XMLByte[inputSize * 2 + 1]; XMLSize_t charsEaten = 0; XMLSize_t transformedChars = transcoder->transcodeTo(xmlCh, inputSize, buffer, inputSize *2 , charsEaten, XMLTranscoder::UnRep_Throw); buffer[transformedChars] = '\0'; @@ -1863,10 +1863,6 @@ class RulXmlHandler : public DefaultHandler virtual void endElement (const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname) { - if(_actualContent.empty()) { - _actualContent = _RUL_EMPTY_STRING; - } - switch(_readerState) { case rsToolDescriptionItem: if(_actualToolDescription != NULL) {

    dCmS|$G?w%Q28OV?wN>U|z~8?M zGgga_dvV*2<9h`PT3v&Aim#}sKx%AqQFnC3+7)d2MO?o{ryuveXXO2UU$B81rP(Wt zn4}m($<3|~fPLZ44QWr{#T>24TF?JB@sCA#*#G<-k;V(SKbc449F3#z<*<(pg)VK= zv#*u{QcO?cHp^7niN9q%pCZfOueRT)VYimrslmYbqGpMgmDSZ@sE@jHQtIrV_|M1%O)~<2d`p&8-}@T$>i-Hg@@0bol{(X_C2VbBIWCD0=%H|t4JSrW z+A=Y22DBgNuIXbOUve70;*%q{1yRjhZ-OfB(0ZDwN2x~D;;un$SGAR@kh6#_Wj zl*+Nz*2kx@jf_mpSAvBUj9+x12 z^3D3(CZF-Sc3e0%C~A7vKGrrZ?Nxo;b*Q3#02t~%c^Dp7ETl}x3P~)gPGX4z>%cQCWd7i) zp^n&O&&UaCzORKPB1+Kr48Epfe95ed+v`wDh!_V=Z=5^CGeL!QO}x(jhQ&mYVk!xY z<-_5zVl~PfU?=mc(o8AK8B!Oowr=0-cMw^9#u#IuDUSVUj`Jk5vS|}0Cx9S~_4VaT zx0IPZAK0W^KTLDML4<&FA^>_EVNPs(y&aAlUy;pf77cDxbFw)`RA9pt7wxB8o!Ea+ zWph_X7etjU#iNym###RL?z)ZGu;RJP7e1`g<#NUapH1k~<_k)Oyx%RJOJ9iULOA-v zt@#TZC*+I~ zo3spp2UcSKJN8h8oR~0ROsmX)d&A14(sEzF{PG*FF^(7VpbpbeUh;`tze9N^6ycfe zl-%EY<^1xrNJsLUp5cay{#drLV`SDRos-?#MM3eD72%+Aoa(0popKuWceN%fk65pP z0gqlwmE&Y(g?XxH)nF{{Ubk3bbKnAx2I~Gx&hGT1Y-dII8cFSxsvbr}MPBk!Op)lB zE(VZ4oXN2mMD9vzgt$3aL4#?#H>$6wu;5_3aB{F#pgRo%kRn8&tF4Dv-bgv!9Qhng zF-y8fS=ywJY~hm|^pgknu7F{4rmi3@+6SuoMl^qEcs2koPwu3UYiBp}-(3nJcUG%&pdthU`}IAG`$E=_7#o1#2np zzc1lm>2g7uSnh#378B@0E2sLwQWq@ie)8B_6SF!OJenCR$ULEVPg%N)=B!ErJUPdE zis;(*liC_AH4lgkQa})*7xXP0Kuff5p1iM`@F^Pga24-vwMIyfTu~1>z9S9a7Xf;X?(+L;U7r#hT36cBbfS%s~M@G{d=c?w)xHM6Xia+_mV!S%b zbB4HAFMyzmlBVqR^zG`2Y-VkG+ZERq z0%`UGPE26rHiw8G@X*kA4BTnRDfI0EH>=tHeO2O1(0{y7`-qUKY@@VX#{VIjnfN;9S~CT{{;HW6 z@1;jH(2h`e{I2+XKms)wK}F%V(xme z==Zhqz1?2*F?hgkgK0n8%XRxugwS@i-)_m&PwO{W=%~o)j@W0KjtgwGnLOvesa!@y zadGiWcs*+B&f8o(D7Ea|jCvGVd)!HX;0_hU#A);Tnni>SVQVniv8RW&CnH~*7$X_L zJ#*m9UKF3dCF|)CPqf9m<`s`2X0T7X#6h90!`oq{{bt5!zBv+&K0;o>mgk?&`{Y6m zLg$dj2G$rZ4zU+7=<0_%Pa3=zBbkS`AHm4y#grqkzV^1SxfLaimc&OW=-1Ed(efW-8Yi>0Gxmhd8O-o)H8 zArIS50Wn8X(#eU+n##K>f(LRl)%!G9;t<92%sf#*pGir0N7cfPYz^&sW1YL;Yuw-4 zn3XsEb^p7c`O{nBDrWk-)!JRxQplAa;eoQ2&$jKz*|!zlS;AZISN{g}We;_XfhdH^ zYjw(-l0mN$h0S`!M83%aH2B_6EZm>W_$zI9iE*7I{mFaa^d&<_*<;fZDG*MkzW$Of ztBhkvz>J)EZ-pPXzOLr&F#emz`c}wyX&YNA%gBBGbj-6mvUC8uOH4epmOf_t<1gd* zrBY_rZ)!WLq@cVFDwzBCE5o-AN6hSgBw51_cEp}OzmI}JPZ=nei>IXnwKb@KFvx*T zPHAb*Ofg)X+CgEFDEQWq6i_pF08uk-J-yZ!xWKp~BE61@qBBkRhRpu~UqGP0RNT=! zd2W7zdYA6?VwU?w_3tHLnyS#NJT80YB|sKa96G?fbb*+yEELtlc1E%c*{bToC^kS) zf#SKJ1DWI+5**Rvm|xC0Qrmm)Z@_^w1ySm>QL?{bf>-5d^*ofHR97+??%+aY-}85c zh|Qj~tsNff(8q;~HDPk75^|g^A1+v8Lm6Is89vf1h~Smm)~U!|6TmU>ev{(_Ep*|` zwrUWYtX3}U6G0hHc?++-UU+S(KxViQzc4_??-OMnSX2gM{R3|a^#0a$t;up>?m9LA z;}lx#o5gJ5aDdoh39vuPJ7rTFvu&cF+{TZG2>>-}8!`#ccR$tl@cgwUO+!RiA~S1; zNWg;$kc8@>@Y)Cz5irOj97d_fjS=(Kl>5Ck$J!ATzmUws_@|K4&d-s;+REoOm!@mq zEjwE}ESW! zO;KZk40rOc^51Z1!~;fjdiDC~8GKEjSrgddP9>Yki$kwb zVH%7H0Yg{8{WCZ7oK=sUMf9Asj_bUYZsiBOJO8}EL7{*_5@8XM{c*|TUvWI|jj7jW z5gc3)oSc7b@)PUk`?~ZHKQ|$c9_6;>=RUmelq(S+z0+G;vLk<#B@bqi#zZ9C)bhC_4;;z*@cYm zOQS0nMtHoW(P2fKVzIN95lW0fIOkC&EtD5pO2l5h*FSwkVlmr1_YxCOvSaet6 zkRq|-ZKx8R)Uw-X9DuE$M1_XJy}34ax&9+=E@Tkn<3>*1@rQ!cRM2#rog6a~_Gg7% zD|y-5sBhmGqzR?K3)LJ^E0X#t)~nG+6S51~ptX|?WUg5WsSk~jx=DFUzCN{Qwo-*F z@U!BXg0XB$3ETbnQ_Scqj6dRG3Jbo8WqtDns~3+3%2EfniN|$~o0YNyv^PXF389b| z?LroZDDxFUUOJBX?>QiPt^vQ&VFh&LG9)BCoQjeXI?#66wL?nf>fK#LQ0ENp@xqVZ zAT5>k#bzFDjuhj5>z6Kb8J;}@xrFAZb<>1cv*?blvZgC+o((^L4sPdWn4XYNk z9~uhBt(JE#XW#~HjksMd$5z^q#0}Mt>R-zgN~>`7t^*}WLK}V#??pvL0c9$Y&veGZ z$Z3zI6?wf}6OcnbH*d*jlpqztwA`FVY!847xBto4lc%<=H@YoeYBzq$*97W7pv1v_ zu%rtf&>aY>>=?LSO@;>D-|VZ=ts9!t^cGC^oR6wNon6~N6A@WI(kt|x5B||?^5bJ= zt-Y*wufn5px{&~N*4^shKiv~w9xXuG%M-`C*=l!pcSBFI%vRfM!!I>@E^ckQe&IIk zi8sg-XJZC+x_8+0+Gn`!&G7N@7+=g`c+lnW@e{T{;o^S!{*B^7mwm=&KGge0Wp3}X z7r({B?sO6Jgz0CMs!)J*f|^y^_mpcN=4L7p8yfa3hO?XS><<5=I2FnSY#Pj%_ipas zp{v@RpTXLNLHyzsGRj3xs)NJB;Ex}vYglX7c2DDPcHl&EN4rS0SnX)uP;oGlG?)#2 zTJ4DElduRrQo0L!bZ%s4VB55@rtVKBRUe>*-8*baX^VJW{Mg z#n0w(mTxM?N~w@JCBq3@Vqe=0n0r@qq9VU*O=7Re%SKNZDUshj5+j-37T)=VMbLSE z&}4@K^W*NAr_{*cRJls=bo1;rCB{A6RcFokN^o6LlAWjGIMd$IDsKMwQ4!INHmCSW zdD_m47siRVMD<5Y`6)JM_J_eZ(YW11N-wt=o}M{rDF_m%L=kDP+ai?w zTqYhR_0OUVHNn~T^tVZkDjV4uTp0D%G-c%s>qq1PwZR}|i-F`p)g4Ni;>jn49rGc& zoUqR>h#p^%Z*Nuv9`FAkZEbC-@~*UPnL>UjQl+CN0@yOC@5 z^XT<2v_U}z64{?35f}Xdqn_+Vv2SBlKV>77J1>KYi$lG2*de;Te^{OHoxpFsJz#kA zl9AUk=;8Yqy-k{(l=L>)hn0+Eu>lH1Ea(Vt;Cqu{*B0D{zv_D~_?4JMQBg6VZ)BE| z_SWo@kQX(ZNh`3mm4EIP-0e<>^ZLP31d9Chw}dvv^p?eZ9eO+$tMwS%Sdukhj&(_I zf!VUyFL=oMyCMf6TusXWKC}f3Iw%Ox9<<`AmY+04CBtLOB*EdRkkWc%bJKpgGxogb z0bLm2YuMczb|VKuU?vk4c;C+hA$@^@p>=cx$>RF&o0S>H*ZyCmXn+0u{`MD{sc8OC z&rOG&=uD4|=|_QHv<}-D+drzp?)eX&=As?fG~bB29|!Yt;W@r6b^Xeo-Jfy4_``U^ zE#z$ve}8>~1Zs5ICfxC_SGA`bN(n;?YbkX*`X1XMX{fiCJ?NE+Vit$A*n?_lyO-T; zLLgv_NYqXUM9GvY39re>$P()nWMss^U|1k*2Ry}r&s|}K@#UqXI3F{O2X{0%trE2c z7njS)0#1*lputH#l4{=RCn<>iQ1oQ=jU-Z=%q)50b9_YhLV!IWWrGUnf_ca_Fm#U) zcPnFO+n~akTKkL|aD5(?S0E-%T4`7l7!e^gGKZZ8a=1TwTQ*-KV?S?QD@a$D32Y^6 zZIpS9gY!G@oLxO{w8J(bGLn4n<=*AG(ea<2)~upomoT6ud8zKjQ~$sv-6x%*2ZXDs zwiV|+a4|kYoW#LN0pigl!N{!5cBEpEY;u5(<19e=Q+URVw6G8OdxuF45Br;_ZL`zU zqt4D8fFK0W;F-HXD1i*lutI7g5IH*H+WuQ{Ycevawzf3W_f*AGM9Rfn(CDzj4|C$B zGvzFMllQfFCJs!zxVw2Kxr#f&3{?_-B1XXk9-jg4LG#Jw?*s>{y1PY9>7CI151G2J z$@+c@gew7>XvMcW!+3Tdg10{V4JVz`EwrxAwHOwhhWF#c%R$>XEz9w@!HT2Bewug! zrN`G*NjOf@F=$E!Tep}EGBJ`$TXx3hw6~0;MA1P3y|4s!D~;NPA!1@%CkHV`Fb_HY zitd^^+G}%@R2Ij-;mfrfK5kEa8aQk=*YLkQDj{M2Gq>-|P2`EmiF@}+Xi&sB{c|J& z0BWNd|Hv$5Fl5OhH(BjVRQ7zrhG=7Zm5hgt-TCX+kMBNe2TRJ?9BS(I(7R0fU7g>( z#17_Ru?z^~)G}Ts79|+yvZUWj7BV@%Y`^7>h?a~{IfF)U%|Ks_ z`)Y3nDkU!t3bd4Yw02?|zUA^3pbkHsx{HiK+ zQn@87)0guG%uh+>ongmD%^}@KTr>x^f5u7DPF!VR;$^?+y8Us3CQ6c}cE!n8d2K%T z+Sbs-49e2vr;~Du)Ei7>U}f~ZP3RUL?w~*b+DtYV7tD;=B@_>eZ&H&wI64}22NrSC zkfcJS(Se46!QkJ31Jt;R)hhRMt%wDCUoeLtUsdHZ^Y`TGhr|7QTcbg*B9br69%sMz zCMrBQLrfBOT`HsDQyJcQIGoqye;=PIxlbyjJIk3M1)SsNkow3EyA4orDSm((`Jf*R zyn{~|Zihg3Y3?QCSwWp&EfXD{4QZbn95^Y*#WxoXIQM4C zAJ%0;%3pG|zH~CEM-4RL%5u0B-*a@37>36ak@dA@$ zZ)^k7@{yxgDx^W@eu5c-tXE(GOd<*x4Bn~To%q0Tdw?+b`8iY~F}%RrsZ5h7YW_7I z#bYOn&9ey_X5vezXj(9W7Fy|*rjwJZW}D~tlc&*QESFmOUj2^91gzDrh4L1M2RlmD z1Kq8yB6NRxs1BRCxOFV^wSKv0JK^m=USDiL0T|;QASh<3!$N=sa&tL#Z&mkb5x_en zBT>S9K(O?K*S)~m`fd$nA7d(aYfT3dEyR<6_H znsPE3HBcxt*!vmhu*$TLm(z=pCP|vb``V_J*O>ylq*dG1=I8Z-mKLx3@h~3|VSr!Y z^7-!rMfF}2Aoxpwf^oL{>jlB8P<|x5Io`qsy>CpX{u5&)6i$(MH$DZ)mR;_crvK;SD;Q`0wY;m0A_4OsNSgv9QW6h{fc$GJLM1Yi!?OA=ZX`!)8hAm1_Bd#a8QFH73=V@@QgUNvwuGJUFyfEiIym zX>x1F*n3ai<#>h!g3_T=R8~nyi=qvb8s+dH%{+9wI8h*=D*Gy#>RKAA;9;w$NcNbJ!cf3M^T!xm-G7$NuPz^O0Ty0Ni+V;NkN<=*Zt z`@e7ii=t5=$x|DcsIi455)9U=Sw#O2xY<^CYmG~nM9QCPg60*gruZU|BX!yEN8f965jX4hVcIx zBrQQSGhA~X=J96JQKBJ1>J9$+Qc^)N&jFfQR=$WQzg`M5m=|rx4 zGNbx6sMfqAAWP4B;GFH>Qx&SO&CJY1$kBz%)nO)nYJW-p93+Fs3Hgo&g1<7Lg@=^J7Ht>_i0qrWbjY^@eZ zX3z@aao%CSy?1bSAJAc25sA``>je{Fo=}s&Q~D+&yj3zS^<@YEV0a;XdF~=Lx`Kj& zP8quL6xT15DPra7R4hvHYH>*K-YpO)>l3og?3uR~C?mo`OBJr1T_mTQg;fLacohBE zqAou+{O@594i9y8TnFrVN+zbbq;t)UuCZl3u5ZFox~NUSpGS!OH@0wb-fMYA5qE@# z9q8G>1Wf68Com>(i&7>CZ|rH(kWNC(rlzKbJY^)|f%aTk=?MXO>w}uuf9s+{)6+Oz zU0s^hoY+n2LGUUkd9WeXErim;!=t~v4cP6vHa8(>8~+~v;a(JL=pGv*5#`%7k>}=? z8us}?#Yqj1Mutlk&p@$WZ88=jUEY65aEc$Bkd_u%&~nPpvADUzpW?Q)4$Hr*I$^$ky6E{0yy}= z&h;EC#S+T>(HYu{)Q zfkVPY7;wcHa829+w`Ti&Tj*Jn3NKZ)g+ZqoHZ(MJ+E1R~L0-SZj|BAI;tU-THi+=) zM9}Z&>^DH{B8tJ`VNnTfx;K;=!vl&|=$?9UN%R`&KiXuedp^IFfo!ZXh5ZV(ad+SW zPPJx?pznk6`T&_&{^VMVeaiIV#m?@o$@s}K;=ykO-}~#nE*OMQ85uhC@mF(``TQb8 z_(ViRy~~Y(PY>4u)y{Mp@<0BjL(G5HAecixs-}|)=GDfh3msjYB&-$b159`ff zdX49qX}yM@nZR75)jFP{FetkARtnj?T#kd3nEB&Z8*DdU=_+VyYOeJu<)1yduTlyL ztrm=@UOch8$O}AY>Q+C}055_mRMxU05_4ZD7~J--U(toVK8Uo_<2AXAW;Q;}5-6is#ZX=>r@F5t8BYpShw%PT>)Mu6YOH-aNGDL>~`$uD!f;@i}|; zPUU>EB^GeR6bnP?dG>v%ayd6%u6MUv?JrHFS-0!fE7R&A9gzPDj?WS}Uns3y>k3Bj zIv>U&#f49h3VDWs&wB}gLMQMn%cFcyEmlqCHsY@j4KrTxKHa=b>p1f#^NSF2Kkn{* zwdopslBT_5x7>2LEaAt49;$jC4?d%V3eoydRHCo!sG1tXb4-jC_&)<&ERY$}|b|u>`I^OQF zczAdjUXQwCT<>N#A9LC-MYx-f1|%in)Z3u+^^N$O9M&IK)zozVC|0R9cL%5K`lt=- zCJ2T>yi=+}j+M*)MxSKI?ahQvyWg?)ped_th9F6xh%b44gJi?W^7+hVLjq-r$#ObJ z(n5A!-8Dhm(UDCIDI0DkpL=q042m|qC0(cu8Qlq1I;0j{d8?O_||4>pmE7fr}4H#k8$a{k?q(&+faOWkon z7luj%kAQ%HOu~s=DVG+M!DVkevLlDXR7)X_XKvrlgK~X+ZL#p<9WKKoB4sr`jr`ZO z54vdBxVU+ao7DJ1>t>Ian`nwcUaeiJ2lsx-=9~Q}QnFvx%Nxvdv}!*(I5~B<-mHX| zmowJeE|)CYy*&Fu1nQ0#lK6wmXlQL6jmxNG+|?Zq0?{WkSDv-YF*>Vt*n`1SRXDNY zEY>IdfYU8Q2f(6;)yc`pftn77Z*31?f%SStRn&O<6$c2J`wZy;3I`XkHg{lGjW@8Pg!xGlJe&? z*ot3!I=uLSI@fZ=u9DI4-z(~bOU9`-j+(u-WYTTS(V1x#f34ey9XoA3dtq83`K|RF zzNWUe+U)l?)`rr^)9)1FsHCtUmxCp(hSA@@v5sq16aI4+AjQPE+HnMTxyF@ zL*^-OXSs|3w04rohqK~tHmsX=N+du)K|$eRd$1VM%480N4T+zNMcr~qBw`7AhRLlu zDJw_L7p598l)J1m54v-8i@QnvsTU@PUI}iI4_^@bCV3|nViHB@r`0ug@%S%-`EIR z#=yY8dwiX=uv@Ov@B>e2c^m`%KC^qj=3ch^< zSRVlSpn#K?s3O@k`aix@lqHsQa)K9zeI4Jh1SkOS-bf`ArrooO0hkV5@gTdi_$C@a z!rHdQPorlv`ZhNuzT87ST9Aq6D%v+yN52;%<@X3kq>&fSpUg?@Fett<&&&IioD7eL zmx6R!Yw@WKfOPyNcPnY>&=H$KBK!7Nrys|v{Fb%9@_J&@D17b2%k~eW5DQ=bJuXzK z=&N|lWqDz0vs6WDtzOw3zNt=n$j2P2d|~+^haCB>f5=1h}}kv?Op^NZdO)Bea<`eA^h^1EO6?(Od-r=dYu6m8hJud}B1^>g>& zMtc2PCf3S8SutA>(1WSvZN&uNI3gj^mMC%Dt`?C^)1)5F*; z1B{iGg@i|D{YFrzD3t#Ts>i2I^R*yjz(SwuZD7Vtv-(*ssps zb9WkxcVxdEFD~)$+;{`1!(W*Xv;EJ=sbHeppOFY-;hAGe%NHvwc9O|DUP$NX=cS}& zd&}HcLlae~mUBuZ<4HyA>?*pP+v~4C0Fgsdc88D`yg;nxd@#HLo^c?@V{2xWfQxl8 zpZ@mFDGuPmb)MI21z#ue+ z=xiBHSnRV|sJ*e2@hJxsI>DRBEZ@5i4^)+m50+qJVpv&OS!ifj{N(~y5z^AKGG|v- zHIuBD(G~AdPUkvb&#a`Ev&501L6777X@yp5yoVj~$l zjU+-@u_wNd2sgj8VsF&j0@1~DPuHL>))^8vHWh`thZk*aXCHj_5;eeM&D_L3b`Tph z{p;iX#N7--$>Q#J>;(#`0gFxw*L?Z(cI@;;!dU)0)sR z!l8wqzXTN((GEAeGE+y9gns#gQL0xBTa8ai`265Iy7qjBX0W;<7}k1)EpUD+j*H6% zwiLPr$tJade0_Zd9#&tB_tE*lD26dg;>xyL! z)d!nnw=^vw!wm^-jeU=+>0NIxFD-%cuhHpRf-Z`Rir;wLe=I*-o}PAWP{~%g4NkaZ z1QsOq$KVI+dR{LuHJ?1+)paH1?bM7GPZk*N*O+rp38gm|Xz|Bv#|*8mwoi-Y10srr zMLQ%pnaNT$-Dc>l_J*UFLI~;o&d|`1`1ZJOc3eb9kuxTEB3C*{0N$Xhv*zs*K9M*C z8Ih?-JL~=8j!6~_P~=3+&5Oke(XQ-BnNO}Xl8t9{UB9Oo9ww0h$^*n|v?ZN9M?)3_ z7K1079Wr1w=$pDdNb8J#d;Prs;ne7ZGE1|iQkQ>2OS+g?TtY_lOY1G<2sUPi0qffC zI0aC7xk)j@D|d?vb&azA9wbPoLZ7=dw5itkw26mLiEr1^t zyg>eLix(~m1!vGTw|KgJP?7uN2O@O>Lay=m_|$lRx&&$?yB?8)pL4i`ybido!{7YV zDJa0gyr_G7<~&ZPq{k_|P|AUDhCm3&Z!XQ7y)*bdv15fE!BVIM5$nq0l?KmG(KBQ* z(H1;$#AG(-m_72D8|M#{uh(U7$|sKUGxFEjZ#dgJ^QWaHozjohuxw9%2AJtX)olw% z^+Ma9Z=rH>a&XyWEu7n z*sf&&Owwu4akEObQDWN`yflg?K#cYwG4b|tGq%dY8PWp|cB6!)y<>=_Ei7BeyOQ1z z#pC8Ux}xn7(zd-8a`ovn*IJ*2SvP|JxCx2G`<%{#3H$MS(bmoRj-9e>RfJ~ry%HMS zYgoZz11S6{Ng+qY?Gy#=Ez66QQ!}C^+!O)=-yjzT8L^St9*u~I-7kefelLt($ojr_ zR2CK%T3)&n_b3g%&rql5*RaV$l0X%DUG6H|RlQ10Mzs$g46m0O;niq6HqSts2ND8z zmy_@ZvuFT#(F7_%$;`T4FM=10U0q#PLkbxJ=Jgc;0bax3c;6f!AA{Z9*8E|RXy?~V zibA3OVNh_u&&Tk{gXp)~npU0F3Nj0eZB)x2Y*5GPIt6LMP^I~%)RIp>(QGXfkm71z zlNX86@ZUC!^P!{1*ZIn}w3N2Y`rg?=%YqY%Mwj~_9z~pPSF6PyE>^L<&&H12}Fc=g&;}gbjHqui@@y-Cil?3Xp zZGB8(p;_*1V{`N3^KYZ7G~Jo8MTS+$3cc3TKR5@hhKJT}hvV;*)YK$s#=`$E@E$4K z9t_C4I5S(0M@LxWs^(Xwd0Fa4-5Mo?=eI7$Oa2`0?zioQ>6yINJ26KonB0wnJDI-Q zctJrS8&9>C>zkWU{vsey126mc?%2uYWunMT55(6OvTBfwHC2+(3*i^8M;V;dgzO;T z=HjR`Zg2F5Go86XYX?0NJv}`tN@3!W;o+i8k&!n-cOe1xC{=NmH=5*IoLcX4xob7; zSjY#Euw{vy`nLOB34UYKa>63IaVwc4pI#?!bT)F(;pTk+d=9UA%Mx;)R}>I?UZZY#c6&RCt*O}TD{&oH7SI7*6Q+9dbT^_T2*ypvvmVo58n`2ZXU}8;S zk}u!c9DMh(@4|L+v8bm#eVTR&A8lHytr}d@S@WJEezVmB|MTo z5HD$gZx@*pK>2v^k^*cs4Ck6i4*Yk6IBcT1c9Kt@KBc%n9LWoj2s_gYJ%46GJzR}d z&V9%2(Pq1vema}wyD`#yEavXcdwo0~c(hp81(0%gDF1L4H=1fe-)0Q|aS%arzsVA?mjmwkuZI3i6BJ%IVcr{_App`%S7eE8Qoldt&fmup@(s7V9^s zXICpfq`Odh-W=wQ7w2996 z9+bT0sVuzGCn=P}4KB**PV@HhRw-UK&K-xZmHCvVqy%lS_hsiODZ`jqq@w=XW3Jhl zK@QeC@^3U=u#+YSPjaAjP)#r(xNMff_9hEeMff_KMuoa5VxQr3nCtgOiBREQ+^xuF zystkdAcWSdm-nPsw1<2+DGw4M?MPYdGy45NV(@ftvc#5aJUSoA(i&8+-Vz@4q2%>l z2@JbKH_Ker`Al@oMq65a`=5~JCX48Vn) zUSD@MoNb=^jtU^zl8_wyj@OGd6t|I5QUU|UfS{#yL*B&H#IJwTuxB9N?ddmGoHXSC zj|b+>XfvP2t)I_~c`YijPyk8W3o4!OQ!r9*uR)dO?i<3WM#q!h()sGWEsR2pHHsiH zdJE^)Gq!Fp(V`OzWp1aRolbysU9?0M1dvjR8Y_Nu z^h|QtlKtrL`oJKQNbQQBqg?p%g+n;VRMtAOl`rgK!+u^#T2fkGK0ipD=5Bo_OIvs6 z_+zzIH&gkMD39Hm$m5rmwsA{rp=W5|C6Tab`2)vDJ4sSPYGWtQgwOn|9cd7FLq#ugS0*li08A&pi}q!a)%chzH62 zu#R@Zb}!zqKgY1D9XzL;8|ShHdcNsWF(DL;xN3hwb#--Jya$rQZLb%naw`}I9Unh} z6QSg6NKsgn{H*K1wk`a1oz+(Gw8^UPS?GrJ-C+o3Xf|KvT~~jW$fr+KNv)3M`w+FPE{`nmQsZ%lR_$!g7R<9R#uF39EK@U z`$Nmf43TidGFOS(T2wV9R>CcARx0{2zpD2hqlXhASS%IZOS4U(9LPO(BV|$noB!=I!m96buqH5bz=P@sZwFZXjFK8{T*>|dis^3>W2?lrlYBm zWa6cZ-dp1@YspzYU2UyQXgPB&<`kf{v;Hi>bVq&*X^A1bivl+J!C+&3WB2CeL zL;m$}Xc%N@Mr1fPga?OP=ue(x^z?|{fsmvL_j9cUZLVUTo>V+gRhm}vDYR+&g%#hq z@98~^x5lJf+V5|tS$-07c?sN|o^6SfVa;QJ@mmpahD!FnAM88Q#di$#eeX+ zi~09P;uw!vyG|gG_CQq8K?Btaf1%Y9$BB=qKt9V*o6EaT4mVoraIR|EW|<-s4GQ!< zH}@z>F`X@U+{M*u5f&7d&faTtcgxW3c0AwOJZ_0^Q?F5>2LjbbdECC zehh|OySbcUEWLC<_Q;3#$K{9vFu|uHh4d1nRXTE_fN`TBr(k2h=GtP#5)_JoWQGHd z8j4yVUNSuqEa}0xzb*n#)-zHNT?|k_7!l|GezdO~vX{4a)vJuK-_fo6Lq#=HHSMGE z1>)-d3dy!+x!P_wiGi1Z zth|P%V`i389(Tv&Ko%44J{`z~I#pCheO3@&C_)V?Sy^l93@{22%@!Lcdk<5qg|e48 zYM6$wdp|Y%od?ixEB^jWsGj6`6m)syCZ7oXC3?i&+<2%60ky#s1El)l%Y$voZ__10 zyz$*TaX7T^H8oRQ(_eBH7CwEn`;C$i`fgJn=gPzK(>>tb(w>bxx;mWCnm5*ad&qg5V(&OrzG4`A?Z=X4enA+Wlfjc zCBhA>^mzhf;7f56XZW#zNh#lAlI7&M3>7NkNAD#_iRUwS3xDLD`*{GW!AF7g4yI+E zZdMzApDF=DQ|IKOq*@otudN&IR_^EwUu22CKdMs2_9 ze3quf5G|P|-<-48whkL%rxGGo-Pp`gDXuhraPfMYPM-Ve{$|b!TfM?POX2O_TZ-@G ztkxT!C4#gU(I(qtWoPy6($ejVW0~$w4=Q~9=!Qd=hKPPeSR~5|)V!0FgmF2Z^Jhxu zUOyFn$u1~>1;lh999ltSXdKr<+&5@6HF0KikzzI_5!zQkZfOyys-T0xV*t!Sot>Sp zk&`FjUcf;0@$upDeHKuY$=AhMu|$%B6p{W+`;(m`r^O4e)BC~Yw|t0Pi2KcQXi5rh zk77*s>cjQ;dupPPZc|Y*tQ@6}!BuSCY@XYBQqH)9pIqP_KG^#5rgV9M{Fa86liYX; zO9S%jc7`3Yr!A^1cTj;?!N5&U8giv~Zk~bP5JaB6p*DC73XkI~iWP-7|H#(e5e;+N zNQfu}rS|p2@`HO!?f?AF@b zCqRG}D==eAlf5^f`=arpx%GWpb^CSoDSx)rb#uIUl=lboXuP9phqeAfdOLc}WRWow7wm zv|+Kd-jc_V@Q2Wyow>bq*Gj+au+DhjVQmk$CVxQ*`bYPBJb>0z*3bx@o7;YaT9qr6 zQ(lgm&ZSkD+4Ayyw`Ru!aChy%;E0s7Gv^Eq&H81rYP6o`iT90RM~DCI;iO`v<&FZt zf+kr!{y53ZoqvXs?JpAdSSmD>lt?TmC@7%#GEn2=1C^BZV(K+YJAnVsF8R@AmgQq4 zxN?U!7EaC0Sd&b1f0Hz4ns#cpqpI{RN|Ui~>$cb>9F7~609{lsPFBbFc4$S=bM5FT zP($Ar3J#UH%d_MSD*#pU_@c#Fd9xx>7iHc|&*Mg}vQbuK3=9k~`qs2DhE$N!-;|hq zFE0;~{#(jPPOkc337-gxo10r3EkraBZnHa9D5PVV=w>7}x*_}xVB-Tv+ixfC--UQz zjUs1__TLCU2R&?$_Iom{c829ByPf*qohHhhofT#oZXeaxA2jHD{K100JdO?}(eb+- zw0FC#>OcK;{zpl#Evi_xV6ARE*Y0*qShMc&gFxG7^o-9A-Gi`=$^4*>N!6&2j@zVs zTuG3dTj8M%bZ2W9Ws`{^_mR3nd#r#z`!V7Agkwy4n6E1IXO86S@O`?EQzmQuVJ^6&fdhyO=Lw|9d^W08KeP$mqq`F28r{M;UVN)_jiCr)OE zhLEaFNBaPQs;s9TLd0KZJhc6LuHKc!CPTC$S znnR$-df0@J9-%zCXJ=>0VnRdI{&o>+;x!p_NH0ODc<*wQ^@HXlBT4pu{IFYXbvzr< zW{69ThlrL6OiRQ6T&qPW?1Egf;*E2$JtF$)(=5*DR^>-9QscnTP%ctDPofzPi>PD< z9Byq)z&Pk{F$Yf27+@HYtzHZQc^F5_w)Kw+Jz(CMjjW~aWQy-^Gx4N3BZKTHIgr|) z?r>gB!w5F!+GgyG%UxACv`rZDxs;d~q;6DD0|;M5^!0!aL{YGoIG*%`ducl^4@pdQ z{a)pk&s_D!i(I987e2Xk(Sia3tbh+eCgcG>!6A42xLN6a(ep@UMi!H9R{qz~h~xTE zT-LUcx3&Sdh?(_J}zo>** zEVn&zlH9*Z_A;D`J^Nl!Hn9HYN*)EDh#;~7&z0=yE!8GSgc;r7V8;5AcRa9Y>JMg+ z-lL89MyQ!Vv2^PW1xXp@uH>gF3_wNf6gCk*l*~d7UZwbZka6d z65^u!kBzYwdXfNg(xx&y#ZXI^+hL5frNIf|r{cFt?ef_J`~9i+Ue|jxx2s69Y%WVY zO(Hga?e*ZopD&W8eaeVZXxWTRu3^Pay<*JFx-EVa6Dohp5LuAZ*UL*ME15f}c+r)N zrmV05>DTuk^%5ch*|F2W>HAj2V4x|)jP4k36S*2WJgOB6`23$ds%<*%junV_eDo4{ z+9GfM(;c!D)ojyFWGQ?LdVYquZ8yuxN7{rfs+sX%=|v7K9Y#hBE6Fs=$3RvM(pRnH z?>UozbvIW1MIx=J=o+?}^F97w)AxN2eAg2aaZhIr6i;e`v8=$>&JG1N7q+r^sB+vl z2`4K?WGN^kBO^~avN5*$<&b)f@}6*5LBa+dW)pTiNJtOk!(00l&l7<#334D1BJWd) z*{eY0{sh;@D=5UVvA|6tMj;udkmo(#(a1?r$cMg1_=lnx3hYQWULX4J#_#4a(5Q3K zLoA?R`u%ZHV1Zm2*g7|z#pCu7i;W!0a9xh(KWSRLzFqy6;8f)l@EEBjaeW3G`n&5I z$k&g>y=CKUn7BBv4eBH9iV+Lrx7xI{@_(CQU@>V1H7zJeEJSEnI($J_>kTraF;c`7 zC`vp;M8r5>YBZR;J8)#L+g4RDX3BvHduqq#87-Jw1n`j8cMjSU>jql*fblatyggH* z4WJcKkS>`vIyu&L=@q$PvB;TH`k9J>`ZttE*;BZr*GJPEC}Q3lIaF|y6LDF-u!xdi zOi{!j9z%Pvck-;5I2;BMxU6#V)^*__-0;A;;So^s4IpsGDvoBCi(5E!J*=o5nQ&`S z6$N+-35Twf45dP_@7`2i>I{5+4t7Cd=COPs3O zc=;3lFgB|Nk?C;Cc)`_`hv517IVt*i$9g3pS7y=zAK=X3PtnBydD;{b9dJQ~i|g}7 z*GfSoU(Lwd0YgqI*E&_jxTA3>5vcLXe*a^GCvrHHuGAI*KwZ``F__{u(_ae+kthm1 z=_9HK-VT`jH1$Q;KD%{^wM9gbRLUX^3JR&^cYnk78GIheym{+S!HhS#?ZKqUh+Q;I zPsry6Pw*w-?7I0xZ`P$2ALW$F+eE=jgC#xaGiW6CERJ5cj>iuP3tC z=rouZbzZQY!=8um_U@|d$aTqIsI&8RbEWclsG?}yr81;FZ08%Z$jBa~mGrznx-xnS zpZ!}k9G2|0Ut=Y4m8|<$Q}UP7u!JMO`c^J;2Y7WsjS`^1d9iTV|ConID3}}`fZ}&_ zq>hD88pUdL_e~)m#w%LiW6M&`Si`|MTT*!?s+h}W*G%!hLLQaK%DddHR%Y6YU6eX` z(k@&9jE^5N9EFT1fusCmsM5UO$7-R9L|pud)UHGvAnfbod6Z(gkXH|gTV!_+otvvn zmq=@hyS0-g%GSNs`HrOfEWyljzt?{=F1rT+h>=IyoZc&$Q zeFJ?QK)sr!Ngg7{9GaYrlgExniNTWGsPNRfoHK>X=e1NnZsp$?6Kx>bfnwcnRJAsd zFMGRPQt>$?!bYWFT9kZCl(KT=$MmdsF;0<^lc&n~M=TEHh)6tI7Jb-mRu@h@&|2@T zMo#I(?$k-V@&T*kx#s1;Z0vvOPecXOIQ$HRtjC(-?s}$;=1xsrm@@UnqvdoG-G;Fw zgR#%_*=_8|od$13obyAWvwXc1Pqbz6-%6H@*Bm&b1P6uq_iu_bqKlKCIoy?RK0&pv zZFUBZXil2cAJUMdMJu-Hu9jOfaKcJ^BCvTLx0aPJ&U~b&?v*b~y2FTd4qazh9VMGhXzFm3!CnG`VuIfIV^NGp%P3$$FLDL!N(AEd7CZn}S2 zw}Bk+hgb;*hjb^1Fr5I~G5BQ^y&`_Fee;;&b|!vq=G9oVZfv+EwL22GU^`+D^xUtV_W>^BHe;Z%w- zbNiw?H>hNreO~@H`nUf4;T>kFS?)Ec%g&RF{leZ_+X~+p2k#DUc7#Z&T-*D!TLLd) zrv$pE^;mpna>6n2o?tPk(pIfTtQ#?YBe5-(*ILaGiBQEa1^1mS{s$g_X$-49OV%Fa$RN@NrP$TG)xhg z21adb%I?!xm{8IkFoD{O)Z06zrY2G{-DSY~cD^}+P8m`M-QgTDTP0b%xGin&jU8{? zd+4!Ud9};<|Bw{qbb_MrY5vmyRRBTT9uC6t+5VT{-ICqqf-9^D(jNJ6xN=OmqY*J@ zymzrib9QOvap z@K~HN*E|UB-w|Jti%w1Yf_*gz`RC72o!HM=c3fm!ejl#{gyGk)Wip7(#0QqOodmv% z@mD@bTM3`9Hq%r{7lz?y_e znL&bZEiDY+Y8w=ni6?d*PQG-6ouP5Aft3g2MI|Db0gKHJ-wT0KjbI6mS4#vLc2A0?O*!@Q9R;k5BGi zT9_kxBv7_dy2sYLb=&TR$a;k4fpqLzu0A%u{3hj%E-vn69b2-$qzrW+zg){9Cm|t4 zPR@?ecCL4n+4`MsD7iJ@3lh#k&2jjfmyMoq-$g(`l;<0criGn?FO_e_w+{l_B0v(C zXy)gfo|CZ)Ur??VcSj6G1<#v9<055&id6F!)YjGp{MtwksW6GB>&egGC-UF2wDP-F z1e@bi?J>uza#>l)0|F*~*Jv@-ST_s3E}Z_)hV=6gji z(Cqepi2F-2%jN@#Z`YV%cgMP2ny#%#J8LM3iYT8RfGmpdDKpTKrC7Glm7Av$NID+1v~qYN6Jf@bf>%*fTf2r9310tzhNAGZ zAKHwMiT3j}j{aH+OS@mMQRkHTeI3T3T z1IGjhFPSdckmk_ZK4d|^OJr2 zkBk6$H|LYjiVL!X?em+o#nlwxLmP?sLj~6_i>hEpxqqoOWpXTL{a$E_9&3h%#_;-E z<5wrr9+(7_Sq_5UD~!lqA}-I~O+^8JEZY_cmXi_=46D^TEQAt`dEyF1g|3Z!*}a}? z5k7BDu9Kx$Pg4bp&3o9=d&=?hF$%IePc%db^AW&=TMfb{y#=>4z>5C1Rkp4)%sN-?i33x>U}NxA=5V?C!Q!Xkd7y#& zc*RP2#2Z2co5PH{yzUvMbi=nwWK3o`|9r&p@oA6q720Ljn9|2W8iI0pz9_<_iseOG zqlnYKh8k`amQ+9 zCzlDs&VW0&^PKr34?!fq!qCv8vk@YGB@KSQ#=GP=* zgi1ZxqH))#qB%c*+@-U(5qJr>;c|IN)K8n>fw7Srr*@k30R?Dqw1B3ptnA400!q2Vh0bU5GNOVDE5hX_XV5huCan%oZVM1_~M9-Pi(4g&AwPT|JYoY~&~dSc@$I1n1;&M$Z! zwc7e-tN+vZxW&DwsHh`W*b6OTFo>-_`gNdgF0=h^n+#Xb^zCsfN2tQj$OKvMN`q_U zC_;}~Rxf~{F=h)%cbxpMJQf>CRB2*Dq-iUu3Dmu%24Tez;3kA5cOpymLt0IynsW+Q z;Lo59+y|93a$en|1PYOq=$^ryh6g$XNLvc)#FM^GKhFAxT$wsjRf>?K?bnJ5mPZd5 z(u(Z30MVu?npH|DP>9s^!DXFJmep;2<#0J%$p0*Z$U&B{6&GN&F@cv_!l>`-R_1hX zc+fFm#V}1rqpF!EH3;HTE^)5&h-$Sp3M-_HCiDR@&MPfj(Mlq?j9BzV<&TJpd<_}qZ|i(jk6>p%6wZEEC^R<=E>Vs6 zlQkHqb3A+a10|FjtJ!^>@1WtMZJ(v{Y3;5K-!>Z?o823?jd-)|M-<%j;MML8*e5CNty5oI0&oF6aq>`pJL_t(G0|Y zU7LC`AIb|Owyub9sPMe+GTc4Y1``u2Ai!<7?KituH>lBm(JVZsAR0AztMi^~fEKrW z$)}DAa=WfJ$J_I|#=ZGK^612QOV3iwEgGZxDwR3QYxgrcB8v`>BO%P@P{AM*l)n=s_F@-g%Gay_`C=56!xIpXg`lfVPlPdI;7WM5Y>QkBgzUsDmEAHX#qIj9Zq z^TstQrY9V{lD`IYfBY&z`r1oz;$)6B5|M^W74+nSgo0`oo>$V1URu&QTxlhkwjyr3 zXutwKQLF7tyeHqn*DAyA+oun^wP6}j8&{d=q@gGo4C*e2dS}OTP_xXQ%L|wF+=4~W zrZxTfNxrz4C*Cp5gDcJ@mCGLUI2F$<-Ca!Ix}$*Tp~`&6hyGFeUwee7xuZiQ6z?6c z$pE;gr-zh{4ZXLwR~k#gD6BXoM57@L;;BnZcSmg{RY5rB9kB;k-#2}Cs%n_m9&&#J z5_(85u3Js#<{%LtitG3V$Ga>d_`f6u_H2E1k!Imu@Hi1rbgW)%SZIk1>a(Li4I*=ZDBxMAFg~N&>CN|!bJ5>;QtJ^=nyq>kV!sL zrNtx%Y_wKuDl<=wb(*YL6Gpn&>s?>ANgjb%5HGqf!hW7bXl24t5zr zLPA34%@&rCl|9=bY2S=Vt~)ZXoWB#V;DL=`6)V4J=2*qiQ7U;%G=oXU%E z!sOeRWHt6m58nc)Y+DrnQrBN6l@a1hg&R{Z+fq0+rRLRoY}|8MxM!M9kuV6x;;b1T zrhT|R?kyW1zrDG&Z^^2Jl}&2%s}X-$`;BF5cmzkXHr5%qcIH;}qqOH8iBH&#dYRNh zj_>QnTFWwNm7M@ToL_BW?~9&KZ{1^WzAT&J2IV1tT!{Arnn733dpGC1pTy{nvercB z5kpnp2iUKhBe`wx#PxR-Yd}6?2tA;OUVNQRw2G63J{9@bg|>N4<&f5FMSRmA-TU~k zZRqWQK~GO#?xvJmTIb&={Yr^dW@qahR?(_t>6o$g+^ROwqyzi$&q`VvI8B1?1`bz=Cj* zVIOZ&&Bj;+2>+WdEmX*~a?XN*xl7@7q+VKHCObdvfI`A1HGc{re&d+m=l2+?W!28^ zDOo*;Aj_oZc~b52TMF=FYkfce_4SX&gf%ZZLmMn-UN^G)N`{gQ<*bl1wJxFSY~~>; zS47mky<~>do<%=?1cZjdIq?zwRD6t#6?(?CtK^?f0Bwb?hT02FJtQL&{1(YDz8 z^ zlby!)f3v1AMQ1Y5O^Q2H(Tz`wiHSjgd<*k8JD#8BQqm%bLg?&QRsJj7Q!|HvH zjEpakB81%35$I^!KTre@>X=JepG)_dx?TdlaI-s>TO30G&Bgr;ENG37jbOpzsU#$;Qn8Ae4XuL$SRjr2cWui*^wf8 zRp6pWg4V^!7ixUW&FN5y1>gbMn%FmH<(1J3Ty6@N{nw+jfJP4cElt#bK*;}3nW;{QP!f zIF-YRoDes%7c#OJHhuZ}i!HKhP_=tu&fg~jjut9LGy@3>Am0l!+f3eD)Z!Nx7b{6i zj_t}TWZ1#0L$3{n?#wY=fSZhaBNfS6J4Wl|K5E4%w#yf!()>r~Volw@y}gx;izOA5 zB@5*kb`S3__X5+!#40_eJ#qPMzF80SKp_$T9S^Nv`4}!52q#`LzP6L))3rBQcy@=Q zUt_-Lby1|_09XMFJwbX;q$4Eg2I-@F0 zJ61uW;$phFMq{{3J|Y1@L3D0+_5%G>nR=>TN#t`!#TBKloWd{fy-)YQ^b;@^Lm3eL zRLgoL)=HsI{J#Z6|F?f|r0>9EB?0YzRg@<#D@g(IfRAQxpKvz5fOhuyg{tn;YkqNz z3dVA;x)BBMjC3w96OFU6Y1VnUr^l|BxvCqDZ^q^p^hE(o3j*nR?NPPVZpc%XYQb=G zb0ZT75!$v^PZ(|%DM5=KE+WbN4kxx>{wC~846<7+()^l~6fnB8SyyGu=G}+9#O3l$ z7X@wN4B!#QkCz~U{R8$Xh=u|oncxD9QATY^XZ-(#oOW;Qs@&Df+gm=^Qa*zVMYT}g z@H#ggAq66|Tl572iWNAe z+&9eGb!P!-B=W zsEOdsBU7}cz8CZ@V24OZu6F{}@at{y>m>73m!N73Q-X>b=Cq$mtwx?JWRF6ptUr|k)2B^pL@{nl3#o`C+UY+^$w|2p7Cc}Y@qfAY zc5fnIR$5xx?uYS=`aWqg{9%%_+JrxN;!eVg8~VYWl#C2wRQRREvh7{Y11E>d9Dk}O z_OA){Zw&OE?gh}natK(FlnRmmTA=1CpFU9mYmjl=aHpe?`{}C_>8yCkbeE;{GMai&uq0Ixn|fzaNu{>F zS&@I3HXKwsjI4ErYSv;HX@&aiIG%-4QE5{-kL8uA8s0E%1-mlT_kVjP-@==l`2qcz zaXy#({X6ZR$O6?)4?#Dj?F;2K&&>}=<|P0&njf`G|lfg{H%^o@b0onRnL|Dl#lJj3>PoD!s9I(_){jgTOY|A3qtdJ z3vwV&sP5B2f{eBz&%hsCZXdDgQEn`=S{az!arp4K(9X`4%T&O{i1A@3|L*z{k60=+ z+%Xlc`x{#lW^J>RzU2qeoW_p$t|r>#{cs__Z8j@8QH2${RBgq3(lg zZ*?p&BS=4AnLehR*AMlLX!#nF-P3z4GTH7?H5nK(3B+5d};AZjXq#rRKcs2)uLa`+uiDL&<(1udFdP7AZV*7tB}>82AyM+rzcqdRJE$P6M~_4TJ+!ki*UVZOT7$Cfjp+ z`iu^5&p;qF2pkBZuFQv_Pg?-B<8;NlvV;gD@P60%DPWqJkON5l3ysCJgRyqvP5ggeSI}xeXnG1 zg#2k!IppiU!N&RE3$XPh8MOmi$r02t3$lQc>vdb zu9Tr_Baj8`q!_j3Q1pR5RQ}hc#8kIG4->ZE`_7d)_Z2=VOEW_}>gzMuhcptsepvVQ z8v(2o8H%VRJ`=t2u2s2U-IEY|jTv6ug3#hR)H|$cXcm^EBtGp{qpp^d;Jrl3{CRmHt)!?tnrw%uQ>pTDVP*x z(Ku~uZ6#|!fe`7D$I>iV57X?e*2;PSsy<}sW zSHz&trdzHbOUZ{RXFE*oh?O7VxM)x%53*T~5Srj9i}q|w zAmazEkLS`!p$3JhfeW!_X9?0r7ZfY1TPu<4LuKr@RPwD;!-o8G`h4`ZWfGnqTf9&S z7;Kx1$Av7)_f#wknCpNfZGK(&jiSMjjSVC1pQ6QVN(R!gS5uQOy{(R>#^akvM@f#2 zI$jOex$62A(-z8lKSDGIg4JzpX4(Gj|7`TM2`|(Lb+c+#o1%~hw#4hItsFn`LA8k( zq$32qm1o56en+2+tK8)uN5G*;9nc;Y`VRJv`|j~KJ9tA{- z>kSwX4LtQ76ol~ScMgP zuCA(zc2eaf{N>g`*bPR2P{X`EMT>dI zH&;9*OeotP?+KdV;mH675>)jiAro*TBy20PKEE3tN=)%cK)Zi{w{Mb*twGWnMo!!a z{We6)k%GR?(8ct8-D`Etj@3Y;6OyG!Z?9+R*GxcQjH$PK)Y;#(NoCDfj%bX6ndzl7 zky<3nlT$Y%p?whMB4u56@Iga^f`w(2E_Qi#c2*tv%j@v)>#f0?Pj9se&AGP`{$4hl zf|#>!BTRU>*J(tU02Os7D7UTyT<}qzvrW(*on?8U|2j=I-y;wE>qh1?`#`Wj3S;d6 z)1Zw8t-GTXJ~IO&FqRM-NTrph+i=fNrZXU!+S!&OH}i+yM7P|+ zC0%~G;jNAf5TQ?SBenPVVjd3K&Ex+LFO{Y$d?E3Uia?VQ8>SY{zV708k@M;0Rri5x z=4a<+h^MZF+E`V0Gmpco?D2Hcl8ZjT!c6gKg^i13rGwFV!ve;mClndZt{!X+wv_sL z(7wJtSbVKSH}dtMs$CN*As^d^oY*vYsIs{zAV3_xmUAMYvXb>x0~E*H*=-}VT+cKE zZiFb!3iwFN>x!Z8YmXf(P#4D>LoD(^OG=cKORE(R_7sqHi{Aa&(;FrVT$n28xV0l> z#+27b(`A!z9CGL*+Zir%xK|RdXJ=u1AU}prSWny)0@yoFyP&@yKm}7xiCasos0>|W zR=Jxt$`r}sH}&V=)U0yo0N4=A8T7gTj?383-|P$sV*UR#pnz@^%ICLOJSj<1+>=bS ze;fQ?j9wpPYl<1siOf>aD-Z#TSw~-r5Phi5shJ3C^Ko9Q{3v~Qp*XC6O4?(@1~b=N z^mn6&z_bp`=gkR|M_|XpC>m&bb~xHCW;v+G+GhzF{M=K=ln$sbNaOzKP&wwpHGaGhx~^*` z?d)j_>)DaUp~Sbk7W{OWqJYi6W&2}`2ulY2-}LGR`NZU8mGy(dZN#0D1@hRwe1^kj z(G+er#}w(5K5~2qN-r{0V7!e|20}OHx{?Q91YTd=ut6PZy(UyfRUh4I0zid+pSp4a z_Zm3)LKN7^1l1(saJcdx{qe=AjEtIIs{Q^=;r37gwrgXe7wHt!j=#mMyVj`>pOA$S zDt9KQbRw)GfqPRL8>PYydy&hwii&`-*4bc+&jkA`pY=}&5TzI~H0$fgQ^uM?c3i|- z?~ksB5)EZm0P?{c{Z&GHIEYf*zSufVZV>tT`G6al`rGRv%gZQ_`7lem;{>s#LbAl+ zh#@5RT@*+`XIz z@J0(wI}X_0jHv(3AITL~^kvrM4hTA9bUL7YuGKR6WJ=1w0VNX~@ta#D11EcQ%%?tAD-!YbXR0|3UQR!Id_{<7; zQ-7I!NL4ixjoYdm-xt9cU!);A0|luPZlHc(&|E)_7hE|yI#!wf#_zdIrf4oA)M}mo zWZaDdZ^hvsR}kK7bSwP{lj1+i+8_kv%UArsGQa#-8WJN{p#Bg`KpxDpCX9#q{#5At zY)HXF+oArDvyM_HlP{JnCJF&#@HRE>d?!m@sE}hyB$qp<^p`X@;quzwAvd{qa=yF( zp8*N=f37(3rwqj}`e+acH612A46ceFXRq*PGuHY60_0GP7Jvm&_cDcp_f5zh(yx{~ zNQXI8lQ9GkKSoux3J_VNuD^2d=<_k8a?!QQu(irye+?xYzQrf|H|h$?t}KH7G2wv8 zPF44Ee{a`eSe-qdnq9^vZdU3qW%fM>1BmZ`%^{=WvT9k8Db*iC*=ot_cIsT9*Q9Ce zSvcr4dCSEgWB{y@5^X@5mqN+3780Ev-FHnz>I8ol@Y1R0xJB)l#aobpMrjqDuvapC zt<3bs^{}(mA>X%1N4fWt50iEVtlGQej1uo4Ju zARr*!UD8NNH%NEKw~zWf?>pY{8{->_|HwIe@3rQ<=XI~xOCg`)She)tiovpzP4b4D zzj4}jk%%;ScTOX7SjbxY3o}cwjBR<*xbk-~^J1~sLcDn^=U@hD;sO&Og#N9}{yfyv z)06wDx7RzzXG8gT$e^ynppHv3DWKcz7Z$oeFfwHQC|4C~s48rz>eOD_UJ~BBwOn{I zTfXHL-ou`B`)8Z0TSb3%K-__hF6KzJjf5vcb2L^Zf_chmy+^Y?TU-J8g(rwXBN22+ zIcRstp@J5-#UqSc3x-f_-0eQXCuqx_+(fUAQO%I$%@=X z&E0?ijRQ+|OUJV)*%A%kaP8iCqTL-G@6Ss?GbIa^^L)eO^td&1r`489G*W1eYUG_9>fbGL21xG%&CGgVrJU?xokqA-y^<3~WJVp8dj(TPB(rpUMc^<$Jh1kc5@*s!+ngCPbcrmiIOS)hPMTulvEnAj$i zhC{Aa&}(tlEW|VdcrmI(wh%muWF4XpWlUxS5)u+46iI^^goK*a%wLnw127ti@JNdB zLdB6lmAICKVffYAKVTdRL6Y*qqaS7N5BHqVuBoZ0#%}NN=A_`V*0y!iOVmo)t!J1w zEr#}6O(G(+&{5D-Wj%^yu~C0VDcNp*mR~NOxB2dWPDY5^E2A%abTn4z{Et<}i&2c-G#jPN##VtWav{xQ3p6!_Gjf=PG6T@mlSX z`ihy?L~%|h9MfjlWuDw{;c^GD4l{JQ-{B5gW(X)WMt9^ zlv5MaI@=joT(R)!8zQb(yi*MM26k1K{g}1ysJkt;{N}2y5uBWzH618sxwwA+m~Y%J ze>SGj>-liXpCQfSnt{|9c>x(S+dAhn%)|sxed#wAn44&`{B@gL-Ldod4W`x6z z?(ybqyh=7YBvNs0)!PWbE$x4r8qVp0CI{|`GPnf!7o2G-yRlTkm59?OBANe#BaI7s zsQ8PsT^k%^xOHr7PmaR?Ez-D%T>`UBaUVjcX=$qD^*~E>qr<)Td>@m7t%BRO&!VU` zPu@$5VdRG?AgZ%FG*i8QpEx0YhE|+d_nb=JJ|G z*>VI4v&ezMN+|^eJ>^+J;!^g_n}Bx|U9WQdM%V`ScVo;#R1pl{i0eaA6b~Vt!XV&_1cQJgeUC<($E!sE?@8J^0gc@gp&(~MzyipksAsLnm$CFEtBSly z6Y)H?{qLoY7P8=70#D)>@6zVI`UCaizfWSt>sNiwTY)=#SK!#1fl$W zP5b626Ub6a>O9U=!&)^?3@ZHpd^vZ9c!`7oF|G^z`8#jxUT{S zdL5FHn+!we(@pO#yo4^iSYv;mJtHd8=PA;IK!#SVFV|Tw?wDl9@bH{0<<#jgWdYXv zK@l;))Z5n!MI}<^b&c{*o?ZxiOoFlPe7m``)2*X9D7yGjgDOy~TuQUIRRAUS zGYSW-F56%wzLj;FY|D#Qy?CK!w>1ktGT_Q0l@hV4T3S)n=JH~c*p7wBX9CKJ7;TmL ziltllC=z;dq|E)xOPY#5dL!cE>@H`!Wf_Z=YUZJt6?CI&OV!sD<V8QEV9?o$z~DFF+GDnqD9s{Lz1T>Ne0jW7`cDJFc9tAqJKKnsDuAXyVd zozE^2Gn48|er1Au6Y`bvfB-I{=L8AW{Ec0gnkqxA zoeTy6GL$hyjn`>$ry7icDcE4wo5_r;I=c~H^^5t;8e_nQfk1KFJH|izQ1#M6b8^T7 zm?Xn9Ts=e8v>giPC_adOL~ybhoJ3sP zu2$On-E;_pm@EQ&ht=z1G8M2Hr;(AV?YruJihFr#;jis$R-19P3E)xCHopS#$YWc4 z`$-#vpvx$@{()ncAN=Wz3g`x7?=SFGLSAzz6E+ML4AOby^|3=H2?+@x5O4WzrR4_v zeI{ytPqQZE!RtRIWyO}2G53TaP!;7qgw3;QmH~H^@ZrN`@nftMHBcS%K1NdFoCWbv zsRQx6E09LGa8NG^LsvPsN(*bmAOSXZ$&jN=t8++wg^O!G~alwKRuAQDatN!TdtdWQWPqp1WBNMN>rfN zURTW4-_Rp~BI4tveSCaMTaQ;)4T@D6@5gwJKX+&AHe1_8&|pY8+TlP7@|hqrpCZeA zP!JP&TtgtZ2L-A5D&R5!9^}9!g5K&?|1eky2&0QjjqKL=2gz`mB&7bh?b%JzU*QFR z^@{rR1M*i|k(U+QVRD@lsCqIKDs$@P14AR1d(2vUXOL}z_qK)_G$Jk%@>saIp?bb| zj&4q8G6DsJU#!^Sd+6A}R4+g2Du%H$Y#i!m*YZFhtW{6_ymObJldUCHAv`^4b$#8a zVl1CF3e78P)Gq^D5{q8}C}dvOtyuuCjQV#IvapHy{8URj;{i(ikJ3kW-x-^*HHw0` z#Ck)Z0D%jV{qbv#$E#+xx|sPAhUgnzf*3FyBX~R8f`aOSQc*d^uCzui^|dTTWxiGL zLkQ$FT0~!1#Q}+d%QK}QL`;h>VE%MwN0$#VUw+zCB`0AVC%Y;a{|!;|B493CKCr zAgd@;PFH_E*IHztM~WUF@em21F&l9pC1J1A2+;Y)r1cLokHm$FjBEQ$O(kQ5q@=NM zD0rgIK;pJM5B?U8X+U_`{?JEcL-OnSc9(KS-7ty|-b z^@L<+a7LZUcTOOXfa0?GLiqlG^I)aDy>~u`%M$CuhYz62Inm8;GP1IcSHleSCRBbu z-|Fob;aX4dhz2bC-cj+e9(@tMjtu&#aeJ@k2Cc-TJRrg6y^SLy`>LTw2A7!+BT?I8 z&6ED-QCIZkPS1p{H z=HiaDFZbH@d@5BQqr$JH3-pXE-R9BCLU%OsjBJnug;~eGF)XDkK-n3iqVNSdsz2BZ3GlK`=;Ng9r1IUw1$z_0*K3G5l ztxyi!Saalmv~pj6hk{nMCrZDy4xclmL@Xikr^bTr^K$?+VSR{c3m zejpOk?iF~t??ZM`hzVf-9FLg1nye8)`5OStj@#;~ z1q9}4_0a!;k_1{Rvzn?HVy!^Sr94e7oX2ykd*Zmzlqu(jfd@>id9R9>oYXM;lTSO} z2|cO*3td2%1Ki%b5ic_Ozo-k~E*Iv%=N2StE0<0~He>+sXu$TK{eKZyBW;>o*zT^y zZY-XL?KC($LVm-?EPc=3ir66rj_0^hg*kipyqy9mb`R>G3uEClQ`oVs=T^5G} zb2OVjbaGNTWuQBS9LdT3loSU8#g~muE)o@PtNcnp{Gn%d=~~oAJ98@IWbH_tV3?=) z!H1n)0QSjQ zHp^mE^NW#@gO!>5gh&e9)G8sBV5n21hfr+=Dg4nK2$BHCp+y)yP&A-T$atdOocZbU z!FaC8mv_>CC1@l~vr-U$J-M{Tnl8tR7 z*q~|K=*QKKZWF174~qKAVx=8DkDm@<*q8+oDLF8IynC*OM(2JW;Wj0#$q5Efd|Bf~rCZ9)b6NdKrh!gm3-s$0GJuIm5{s3;ep`+gU(Jdsk_PQfkENjX}ECnot99gZY*}1Jn~Hr z5m0~zv-o5#)Ego$5I!r>>Ae{$(55lE_fCqshrd#w0oP@Bcy)!G$(`z0vlya+Khn?| z3{6<%QhW8Aa4){Osig8|RTGDBBm(u*#v0k-+CFt9KJj|c)|=mWF~{gx-BoAEAxxh= zD88}$kb6JCR2ooAbaH;#sk@}A@xd3b5El=8OcD~QM0w*e#xOkRfkRF!x%x}w%v$LB zX??%_S8>h!oa1J4zm{`6C&-n|T5xpt`^}99C}6_Er9rwMr7Z4_^J7qJqjV%0xISASNQs6m(Cgiu+pQm zPg2bF!x8exmgV=z7s*!(Qqib>ZSP)%93iTRmnRrqo}M3wo;4ZA_7h@a@@rdKG5|V~ zhxX|;BbL{N_xsXr2!w?@8+tU~^hm_WrLBG^Y&{>GC2$;Dad=+Q@2Ma9=}=eP)5el7 z%a`qa;1|D-9p^w%&;4C?pAfa?aQ{jAX zOX+m)x`e0A-6IagSgtNF{7_L6knz>#racCmt+vB;#jj1cfldIn=w3~W9IvFMnO2ukLAz zI|YRm;RAbhuiOM@Y;DM|5Cqhbq`2xPNGX9-ODi8=Uv~Pom&>W=Wshyr$2l6MbGhvf zm?A~bap5`sNYqEZILE$qbLUR0(t(R3#jLiKPbP$W&4SHD9mjM-Y+q%GNrdfNYFzZW zv-hSkfi~s)QrZCsHJiC8-M#S>GdIRT$3^S*RNkQ?;Zq#36+)vW}9nX0)l{gd~YLCUXKoi zj*>ueUPDG$^vy?>m=SxerR3^v)_Y91XW1El-}W5PJkn+Nn-d zia}=XO8O@tiwkl0)$ZjmThxV~>S@U8LbLHn}! zsNq=l!+bdTzk}xTw^5WCPkOyy>Z{u{s987=`<#vrAu2Np3jCWliHIOchzdCg#SPVB z>2^p^GVPVb!S}qDh(urEB@>f@v*98B^jHUvE_kWX6Mu_hM=XE|bJT*aLjH`<_UuUu z{5NzmR4R{Yrb>=To;N)n>kX`>r6p@3!hi8Kgud_uU)8{KPZ?rhKXet$HLRgmj2b%l z=z}`Eb6EPU&+!fPuMBm#2n?%#8L+8Q+&hphKkYKLw688`-Fq|s=SCwkbA6i?K^@O( z-`pEkwhl>O9v+uy{5>%ZXr~~n3{(&W4l?PH`g>Q)_qc%_1?L8xe@H%J@xz3LgqDIM z&y)X}47%~(FINYDIXl+Pofcw22i=TK^jzR=dOg|<*QF|`J($F;YnJ52?R4RlE zDHJ&jpgF59^@8={57UT>gSS{S62+&{svI55uZU{qp-F~>4j@KFPgzW2wmLNp3UC_* z6A@iqUGUc`C90QbysiM1CuC$S7!dz8{v%c}p#1!Nk_Q-_=%}bDvsxuBt*FV#u-Pbd z6qI1O7uHog08R=N*c1JurG>dR#|xchnIa}>Gb#9~PA3alF!(cCD4f;7tzR_+*YQEY5@>*iKU(GF!vL-iSTrrc8S>n%x z9DkZxY45}BIq~94ettp*1_qWHc+hYLZ$&2$6*V=x^-LLreNph3i`})YtQgPE&eEsD zqzc5myu5;KAuB?FL}r=k8#(wd2``rW6EE-rPkOT&jD8~n|Wh?;B zV$uk5UqlOGoOfUHcrqt=k7n9q4>S5==0O3gs|GZ5bQ|ZrC2ZO@6jrulLT>(9y?R~8U z;3G2n>el}8aBTCX{cB(6{9P)6@H^hS+EP`>0grslPnb(`#vhJApxu{5CtJKjRj&PH znZnwzDusl~kpzbeVXJXaz9(}q*P@uK@y*9_km)076IC3@q)?MlHlk;VRW;HyE%&U# z*XcFzXSm|-icPCm$q0rfxwk*&0GK0*fQT=wRP`P866KyDC4r2dw{g9Jb7$HRD$z# zA=4=gvigmO>A98iR22;FLD6(}U$B>!km5+d%T=VuAi;8CIMxM+47{D3oUC-{q>F6> z2SyZEeWs%HF_g?x8)73dQPp(B?3I+%%X+=`JH2uId;I3B#pBhy^hk4s9Oon2x~jE6 zjmC9+3ofFRfnYdG*)61;yeW*Gb`x+fLu@61BaORVQre9SwR~CMDSsJY|Zb~*BcrH6pg-; zv5Jq8j#tAaQsqR>oIp;^5(+SvY=;$MeTva1jKD9MuZL==aT2%w#(9VenR>%ebRJZm zUPdiueQ5+aNlC))=ssui^mbjfg=7D%oc}{bMC=iKS`H3$AjnS{DZk0JF9}_~FXPz@ zZRPo6T+ZZ7=a_=lzKB8>Kgq5DWnSLyuV&t>!(YLBMl8&))WxR!!NI2&Mz7uAZRo6K zpyMKAw;oV=JB!)f*Ndi9JCu>mb4hACFS8BtUUDIQ*D6KK!`U zKQy&{F)0T4@mYF|Q%iQ_C0P@7B@$pB^owmglt2S6!;XV)_Nx(j<~8@MCtP@l!N9m7 zcZl4-+UjtuHPu~oqfR2zO9VUobyAJ$((=T!$LJWp)dAi#t;I$)xyrlcM z{h4ffdKw%Rv6!9r9hraLX*iv`RO#NjRtwNKbjLNZ1X&^PlR62;P%YAMpU z8LJp(o8lgC;rJg4c`VOx$~0Sv`s21?nv67f3dJ$M}t-yXTj!DrEeEmV%&+%$ogl8~5+!b&0+H7z7Giw@O?2VyOj zK_G@$gv|T;Knkb=j7&_{+pZ0J61Y@I3K5HW8~B5h285~WCw zJ1{)ZQPS0wKFxIIwxEs*1)_h=*B@L;Zf=I1>wI*k#-#pDVx`UZ^x~%i3@9o(y2^A2 zuf}>7&A$DS2L~Ch?eR*xOsDY!q$K96eQ9?{qy+Be-E^rtc~4J|(b&-vWZzaO${iCi zOLA=+1Kl+SMy{xh4vE+G?{3Hhb2(bLmkb|dS4K{XI_LLYt0tpL`6FNXEP+toWe*s} zWMok8goUE6ZY+b!7m9;Pjy`mu3yd%FSwAWxB6K<$KAL>~9MhY+Y2vaw9vFxLP*^Nw zq6}tEY6M_fcQ3sxP>^$He-p%HDA6Y?hKIk-Tis&&#>m48snEq-X^N^kAzjdT7mKk| z3Q_NfdH5*eND zkz=8Y-wXH*#{EW{#S@5NunAvJ5R6iRycRC^N*uP*P@^C}P71xN!YCtOjqL)SYzk}d zREbJrR#xm%vpe;R7w}?YVjwFiQJ=ftMZ0rV1+(Va2?-#5OAuMw6NgBE#HMO89uxDl z@NSu%M~`^l73si~MM7c~YP#*h$q(6=YnP4A>=q{mG(|DJvKG}34vx3yk2w$M@JNg;{29F zw4>|(%z&!jhDSgU@v1+jGt0OS1d1aYkv_|EH&R!_d(vnpb7~}^mWmVqF^97#OhG1| zSE*DXRx!JwD9`g3Kv>fz3|wKu&}6M@XLG0VRyB^+)JAq!xAoJPq~bd_gtq4lA*?zO zy5u}2#OHg*#bY}Uo2MA@HtB`o$!h1-p^*2Lgo_K8va&J(9%iFZs9Z?H35DR(&4xy$ zL7;R?k=+s%2&B!yHCN}#H2HI~(rv`*;cn;|C>ufS?n|MYn>ZH@mulgMyDnQmj63`a z3TC2b9;bR9pfv0G!-U*nZ)m!P(>U3kw}%Dl+aEYyl2cGQAsAH=bbt83#>{{OC={Ue zfv(oG>pNRRrz7jVH=Mljl%9!E$k?#L!U-}xWRJp{e-YQJW4ilu2FK#96uERPHVH`# zkfuIue7I)O_j1`x7>E=YHy!=`;aR(eB&0ije#$P$*71%7;f6Q4P#(5V&^CjMTN9oT z3X|AemwSP&R;Cd+JS>;_${o$r)KsI@iyO3B5HBn)CkGBgCm+o%)}#}8jeT$Y#zm^iqJJ{OjE z+^zVBPZ)@bih`u#h(b;D@OE$+8Rhsg-ATgF@$z#|z`{Nol7c)N&k40JGyVW?)2)jD zB=Gd}O>gD0P5*caP5MBg$Nih^J1>-~ajq0Vq&#+IIWN}L`i|DL6uf}a+yTRJAB zy}e!CoQstffMR3z7yN{z0xl;%z+K(*P#~lHX8zixxf4;y;P+QK{Dg#rjz1AMtxzzr z8j7#ikt-Iww@5}x8jG**g9$vCnZ^{2Q5E8GtH6SuP3m(muf~P(;nw0PUdsBymZe7h z+u&aE*0@TvLyTf@N9GQBx5~>FG!WuR%IoU0SD+4v8TxI{30WK{csl#Gf%YpCEHu=W zDS6*LN?UK@!-i|yC!RnVK|WIw_}**D@H)x>(SZC9$`;?R3@75-*M}R|y;j1Tj9&=~ zx(cq}Ur7MIIh6%(lk`<2t~Kxa&c&sx9<&p6d}CQt6A@^|G zCHncYH~#rfYq+rQJ(cN!MhpozQD9&oSyrMbMS${JJYe$;W>&~+R(9lM(g@7QGQ}+| zOJrNj|M+8_RQaOUIl{gqM?VW?@l!|4!X)2uxJ@b6pp@`K%~$Poxb}vXW-+n$E_&)4 zjGo6ECcQw(s5`8&=X|d=Z+|~zLhxY@{kZ)K+9y=}{xR~=JI`FlUCztp1v2v3l+~+m z-ZaAgJG8KjFjh+|3}r9^p{^ZE?l0DE{o7IB&9v<+9Nb;@gxfz<&oCcTCBF3PbCn)z zI3nPu!BlwK;JzPRi51?qN;X4*r@QDysA!+ty?(P?C_DSDfr+1RaFAh_0IyGUFQLj8 z0Z2y^6PsYO1)i3(Nm&oyBONf2Ai*FIR4#LDZ)mXUeeBio35hpEM=|4%tmUI+0EOrZ z3JR(;A0rFDH!(G(>Euwtnk9;ny9kYah_UpJ_<6CAb zQ!>=e?0Nj!VSJnT3T6`f>Dq5T-#RmwAf4^-_D55ravqq6t(%ire9U5Sz=&D5cMgk` z(HTsG?}h4c);0gvuU}W`l2@0WGeTE+#A@SF3!#r&1YrPs(T9wk{j@{8%V~sllzqjF zM)Cs=1m1OKB5Uh;SMYCny7pLs^=oKZjJinnc!;Fav~i$dW5aNdBMhEh z@xUhLu@}4Bo37Mgo=Z*+{XHfW-2+v>k@K0R;{k5vk4Q?CQ&Unx z*|%QewLRTgLsm2yuz`v-8}lnGF+?6tV3s{LV!d8AQhZgo9$>v%7`+R7xAwBX=^fGM zrzZGhGft=Y?2d<*pXTaU@Q8J-pS}CzATbZ>a2F{we!FKsuHS%Y9EvogUe>)nwQ_JM zPsF>I-X9mFti;KYN&XaW^K$gkTmC6{%M!iH^ECcX(r2yWS2H6u?4Aaei0G1|7=j(2vX1i(NUA(N{+kIogmh1t1#8yml!` z_#8lx2lu;KL%4q&92~q_P*PHAIBvTqz~g?KplsN#tNg`TtGWH#Q^Cww^S5;0R$U8+ za$BH?EZA3QwQn`m&Dc)ONlVgP>_?8_vDDf(Q$PJEl*-_&wh}tJ85F-D^E-AuTpBP= zzb7lP1Sh{AnD}J;+r65o_BoMSn$7>o2T)!~H!;EsDcREYaP54%7L7A=JH6Hg8fAv5 zJ%<#Jcos=!JYx-ItT0;IP75xhjWCf)yF;yq79ajL&6YVsVG!W@#$WJ#e$TnC!}4b| zu`xCv0OWHvNOuG1e5LEYnnkUas;X+o*cf`2fNK{ZqilAId=U~T8 zEYk|C6Zh|>Yp#Q#h7e#wmFz8=*iJdQN+MBo9DZL z0TQ*SL=G()6DZVGF+D_*BQ3w7NEtk+XOc@sTWGqH(0g%SddlH&T0t^g{fW!hR%G3@7{@$un>EIHkg4)(FUY<(^+wHoV4LvOimKy;r8n zh&x}mAFx}U2l#ZU`$=Lh~Sl@S0 z^64~4YXMn4OU%ZF7bIF#c@>-PaVSOhdP?WZSp*t_K}zG!uSA0@Q?C5PLA?Tm2*DEE!IxWg+#$XeUgHpqc_k6kENN!xyp z_r`a_gf|x(3Lub`E8q6R{z|Gqq2>9RYPuXfD{Gke3#Y+k#weE;U^Quj-OA7K*N2m} zOh+>EQcg}X1yOvlg|qugYFg|6T?(R;`pc$|I$jXEQD>BG;5X2poxx)d#E??87k9{J zW8e=ao@-xzlpS)pG5ck&@!>8*CHuKc5+?g`R{Q25D+S}T>T0h!S!eW^pz=NcSjt8k zzr8MRd-tz(<%j)|_>&_hPDmXLp4D&p_BdSTd$XQlI^qRh(s7D>DNuje-{N`B=DaOe z?}L8$$|XR)sPvM>w_@2>QCZpMx$$*>Ttn_G?_o$=1ENUb7s!gT^lnMJr7@;S^}09B ze>X>LU=mjS)f`s9AJQpgO90g0or{;~%ZJW@E*Q%G*4;o+T%)UnOHX&V1zV&zG8lT$gs>xZ~)nLvbbB>bw&}mDShzvi@2zY8;&qY@5Qnl<$ETB7CNRPd7ohC1Cv$`E4_608qisyj< z5Nm8~w7VxeA`>AyZapU-_I`%BFRtn65LH#v(_GrTC{bai!T!tbP1%6CY`H&bh77uR zT^&T`=2GaXiOHMS&L`B_aZb+Iw&nHfH>XRg)aSgMHC*12Wjj8nedl-dumP8P-iN^Q zluGOyk17(6r2 z09j)!rF}m4BNE}e3l%V_0JyD9aOtb8q$Hg1?JjkhW-D@GVd3s%Ayc;3HX)dt9U8=T z7nanl@;<}1awCYo627{Y-w_2DN2rp!aR021)aVtIoD)udN;W8Il{3& ze#nprKhS0SUlATGXjju50>XPTzo=eicSz)SW0$*HX+DdVlID?2%lmIKgocXJ2Tl#g z3LwzZpT8Znb!-aeFF(tU=4uH4XDt8<@H@k}@HqI~EhJk_wbtyGXE=h7!<>rn@J7#V zzNzQy(Klv;Mi&RuDD8zs8@1~Cl6#Yd1pHQ9A^~}uTWmjaqiBxi+mZ&3{((#f(7NOg&U8yKgE`)yf}y1*#6J7 zl+%YhDVC2Z$&@ce&{vqXVt5#F^)fk&-X1b02NGc91Z-KhH~UKc%j5Shzo(ngWn`ib zMcjAiF!3+$Ueppp7E4ba&6WKcLC=pi_&cDX^GYVL054)7V>cGh0u6s{bzA@c0ZGwA zZS@_w6c_umum;?m7wa3qk zjm|f_KNZ+rcG+(3&OS~hRk=q3Uzs^*(iMfvl#rGd>AW+VS5^iFYB)T|=VC%SA~Mo) zW)VG`ik246_LW;7^-uln@URH2cfO^nfNl8r5y#kj+l^V_U2n$oZTzg+=J9cSXK*+l zGtZn24`3VL6e{}_r&BcNf}cJ13~73!uZuWzL zaB^kQszEd#%kHhQ{CRS_lS9qIQa*E~uJ4O$RZBFK^3q&GV)JSfOCL}bqvaM)vPWTR zDymBJ>!TM!Uy2(Lhg4F4Dl@PlffjeRI$|+fkv>5Ag_ND$H|aK!jFGVXd@7&ImFF%s-NV{P zot5Iyv+o?6TRUqRlF<`VgAvC{j)eV!jTumuRg2`P$q!fui;dX&zPI|jKZXw5 zf0m$4PZzThr3GgIfw9Z@A_1$GVO7l z^=z<~-wXaicD>{;a+JmuDaMs3pb^*FT%G$d8k3ZCBnT$4bQ}-IU}>IveBY(^2wkO= z-RdGskv+F`0%hjTzqL6QHZ}U`&r=BCh7vhzLZIx%QO}4o24D{ytQ3FzKgF zhn2ojXDBXPO}VcOd8J%Rj zIT}d<0|OsU8XKq*fZVpP@T`pG#@jPU}53f38|t zjwj*%Va@5pH75D?Eqk50UH{pXYRhfT^GQ5}d5%U*IPw}Aibut}x2QryDFW(p1L(vh zMjXCYRxaBLj*`4`T!;00x-};ea6tqxn2i98h=?ef!DH*NUtVvt-V>SWQAQXd3|$<& zwL31Qw*Lf$gmft^rSF7?Kbm7*d8j93A1blEQpRI6?-EMYpu0pD*%wXEAP77iXjRp& z`*m}#GCzE{bd3dZFWfC#1{k$&qxkRKcAwI}HK`qr>=9Pmj)-VzeI0;-w!RWcztAX= zh>9~b(ye zG3B^jOutqRWLdcX(|Jy%hLyj!rk-Bh*_ji`D>tz9Oj+lvL{8pxi&&sEg>zB=-5JWk)ydFGzR4Ph{q$37Is+EVj;LonJ{-+Lskb9`-DJr4?i z3?kZ4({N3#x&9ipFy4SSEC@4xwfA?f+;Ix>yjgek-@juahhoJ)K3e+JSrED%jkM(% zE8EvVc3mLwK2J8Zztm#+#G(zkjZ8jw%&;F{)t*}?m7UQ-Lc)wDKbACH+gG=)Upq@k zz+N3JFMaO+pLO<6fq)(ia2I!XliIcWIN^|BbyY@a?eaC3K_>p2`cm}$A^|9t%iuw+ zUveYHL56#Hcu-VQ3jF?^<6xzoe8uM+72>4PMIOcrs_9u+fPjirq3hhk+OvPj<8p`> znD_RrB0Wy*opgBtc1zz=cSEDCjxdxZtGZ=DUgWl&8u7PD-lO^U>YVhjEhfMI@3{L~ z57$9|*Zq9tU=I<8dbaQgDBWqSe6P+4+2^vT-(Sg=$;b=@X2a3K>`*Fi@gXfeJ3YW57kkZazu^>Htbn!m7a= zUt(B;>5giHeTY96B(dUlaT0?vAP~Fp=Dm?5XUk}RFq$b7jGlg7=IvvNDy(r!n zas}4)1XLA-Q7|$_0W_@s84Z2MbrZO>PM`Cb5JGTgKqv~n(OOri>(R!>MzA!QCoE4! z`OG6^kY+&c#k=&7ni?)uRn;j*fnrt0n&WXy$mS!Ge6=q>lc_nWyN!|2=CNR)Rc%lA z4(NV0qHz%Y1r~wAe>EYeb6Hg6;>f#Mg-*i`ZFCJXU)9B`)8L>>xuykNs?%5St%e4H z*=Qz`NP9XGc@}pO3}&tH|Jpq}kNwsbYT5r-7a-xw-D}J0Uk+CXnm%m)!aYWgNn{ym ziGi+`&*wKWi%5T#djZi~s>Xdwt~08vp%LMEzTGH+CRI>1GX~%fr}=0P;J2+}T~3nW zPhM|)VI9-bU#VT%Bz<`F0a_AZCDg&eLAysyJ4W@J16fINjWQlU%UKgA08H>u{135e zSmP3da`W?{0c*>e@lIDVT<;4;!|9LcZpeSbvAb} zfPaf}dEur<%`E$_7hB<}b=mZNX=&+c_w@?zKELq&CbrMRL^x`;Npsg*53hOTfh{Lc z$B&vC_!QaJJ8ohy{J~N+LPg7kyfOcR5V|G`KJh=4x*!l-E?idd&DjC4 zeSgudpnxjV@B1-zfCl2l9^PcWBm&;jAJ>$x#`f2L`9Sg}Sw#(+v#d&`Pax-V4DD9y^z4!7?=_wQ`-v zoBd+xQ<{_^_LI0*CzAjS4)&Axhm*I&+qd0klh;V?O_U2A5pW?& z*X}rQnWMv4N(y;jOLY!HUqEZQeunXcmnV7)Sw?g0G_iIj@d5J?7xBFeVGIlazwA|2 zH&4ySdrLd_$8C}>*GIFl0pt6Z9_N>{30x*@cCoRYtAQ}5{x91@zMt4x@Y;r+nBr9$TNAD44rhx^{4P?+2jd#Cx7! z8*5F~3HeScqyT6s`-dHofx*E}Yz1LB4PrkpEoGgUw5lqMXi1IwQ*9vJTOKB(HO{7z zDm9oJ?z6p5=G&iR?f*Z<-U6tqFZ}yGgp_o5hteUPQc_aV-5}i{-G}b(5CLfrq&r2r zyQRDP?xVl|d*^-cy)*aBIKwb__TFnf@%cXMS$lEYb_9UQ`no=lN+>B|=soUSxSs|4 z<~KCpJM9cxsR?Y<+Xk!9_YR~gp(DV?dbk^S>JaxuexAqlEV_ z(LBrtQ+oa_J5AD%q)$$+=U3qSKy~61OtR6XmlYRx=(??<09bn>fO61w2M4mh5xkk1 zf4*9%jP@Fd$d!NoxDTYkMMZQ? z&U*oPdR~aiXlTR&?p2!AtZ8z$4kx6MkzxKS^uf)|{E{)GQ7{iT1z#H)Bpd`CT0D3< zfVt76Aj*rEMd!#pKp70Fi8pE%&~H?MMf??qPj)gjOCzBjI6d=ZS=d)>f;j~v2> za(dFX7_{@NN6*E3LUIzJ9Z}!j5lR9xa)cUTrd92Ekqk}+ zETCMwcAt71C@3hNq|AW2gBd8$($aVSLsEX%-)gkQR_XwOW4=6`51I8Et||!U0jA~K zc(5?p(M-FHQac~n>Us0-03RT8V6HJL+pp=DmY2`ACKcQcg94O;OD2n`cx!W4OvI${ z2#y;zqlvC{+fv~UruA4B>upLWnFLr^&>%lu=!=SqX3Y+L6)k=e*ngzMm}#A@SoQT* zKEF4f+dO3q8><`P<*Ki28_kWEO^^J9f>y$hEBp=zMvT96TB1XreTtG8vbJXej*pK& z?Zwky12nL`i;F~#koW1B7#amNbx`MLvk3|S&*&7g%bo)@4?`X)Ibc4;c+x3!R)&QE zq3)x*#meJ;h@K8Ha&T~}iw^B^3nfqYLaz(a8 zg-gS1PZfyili??UJfsf;D3r5SB?+K)qwr;hhj z9`Ma-2^u{Fe>Bn@<(Qz$qNC%7a+K^)U^a;y?fCn3h=4lI=LqT@J+e?AZl0!g&6nCw z=yqM2BsW#G>5?#YRge%2>JGxFO&xh#ym1=7wsx_&(L(Znu@FEe?tjwE0X#QcbiF+_ z%oO;7N#=D5)#P%}N6xuE#M1tQhR7K%LH8Z*;q;ut=IK5Ii}4fps==|?MFncL#%mT9 zmPk^LKOyIZg@qu$PMG^y&la85w!xdr>ucMY#-xnW1aZz*{QZklsu&TcMH`LUds*W9 zZM;XvQ*u4uBh^SEVW=0MBTjb@53YOC;Nalf?X~wBjJS)i$#qZZsi7?`EgmW0?Fk>I z&3#G{ja(MVD1yl~{1*o-TCQ7*Z*|Fk@V+6y=TP zmO?L2ue1H-=&es{-_gl4k;tfV6m{Rb94wezg=gr({V2H&{vZw#bvtx_z*6J+Z&37o zpE$j|z0Z2E6oBLct*WXjB`@CxCi4lME>+)5Qr9z#O_$=LrlnnoN7+-4M3$ifoQ2J& z3)buBXDlCHcXT~Hz1yeX1adJ^!Qzg_>W*k=X!uc*#Qa~7luIs?vom5US^n)bSs$0$ zfV>nRU)T`((nIk2cs_7c_(Aw^shWhD8M>wRaanTJ_@*KY(j3s{gxB;6es&&mDzqFv zKU}lxaYxxa+Ns&+!ViCzVg~$MDUx|ckl2mFV3U}v*_Y*%^9n29vZ)%_Z;|+VFj~f= zdY3_GN{u!ap3tEqkYghm)@cERuHjFNy#q<2H5}5?(i$};h#{yXND2xH119X^5)y`c z6NNm(h1aRp4X=)~lm$%;cA`n zB`QXL$~12uef2>g)aOU1gv$APPSoe;XKrdD5Cj*Y{QV&wWEZdYT{EgHE*|BlmaXma z$M*V~Ur74G+c`cXoYLSAxXcza;_)bVf=4?YA$E&)cS*78CMGT5sf<qLv5( zMg8H*6wdMAtW%4#sDLNU3>;qd1}mtScdd1btsNXh{9L(Z0dmc84i^dt9b=rR+3l#y zSI-j#@LE-O5BH7D7&T~+neeGWLH{Z#9(?I^`0j297An9vhTZp9kXa`6*~0L7Une5t z$S&G6z-qAu0zV;Z+0bsi5w)5~f%v?`i5|q}+ew5X!^4pfV4*MfCU?HY>;W$ClT9k} zFub=(;nMG#d~;`hdU@G%@!|#b>6^UGOgL9h5Tw4& zn+r(3uZ4y4)4Z*xU9S~Or>|&ttiP@5xp9<*H&KVXCK@TqFy%k=yLp|s72kyVUroX;n)iHInjz{+fsedHUMKG%~K>9Ts{$DoBd)Sk@A_f z-jwIyxik(UK_8tZwT6ZUa(4Rfo$LT+t^N5EVzaoBYH#8H8jsmvv?2>118Z`NI(lTl z;@w6O*^SZcNS2hGlwYrrKX6Mb&hLyQqeOofk4IIsO_&(#Z-h`G!m}~%U%NhKk{)9g zdkKtnZ=e`|zWYd0(9%MD(DqE2Q*jTgs>VR7-Ga|yJ{+RKXeQBwxUht|BxnoUj#{7HA`^3oX_ z4^PbQO=}F3*FE@66xT z)%7oK+((fLHuXOEJf8J)34+JQ6d84!rkFS4($mAYhf-$eUA=1zkCz&6kK8fsNGbWr zF~bb%wBoXof+NyWFutC-?T#APsN_Re09pQHvS5|3u*!FNcjs|Rxz?9w+8xZ#%&qcZ zz`7`OHf``^pDgRr=4!3zCMxmsI8s3%qZ0Glkm94cHWIQjce0e)S`2<;I9#E7d?4#+ zd&|Ea9E6+>-o?2hHOOcpVFD@VhZb+|%W|Q|J+WmByWeFgoSsj7AZFhq$B;FsuD8y9 zT6bIW?+Jo!Ij>BqIuFDFEG95DRVg$w+;Un+fVLJ6-^40SX-U*0v}!PW3q(q}U;T_4yzhX~YcB zIs;8jMxX=~@$1U3KalMzZn2eGn~fGO_fYHJeN!$JEy*?QCKq}-yx0$;ygBR~$>Oit zemJTAyeZkx+)Twzj|AY2Vb4I^>BU9!-o^K_A6@;kmCGCF<9I|>!fjXGvp}$6K*0LD zsqi{*5RUR8rF3@ouCYS{$>tiT>}j9jx6c|BScY#2+0M>R?%yFF{|?Vy4$R_rUE6_y zuR1BpS=-nMSn<9$c=WH6Bjx#Dd`!+I4S7jjV~Aw9fUjDQVVIAV4jv}_q+?l8^;GS>am!YeDxEVxy6eLCwWtUNgj|;_ zQSrS_#erV_97t6mcl>)S7yFs3pzKM>}sneKYu#_!gzj{MUSBh^0q{7j2pf zLRc8kEEYMWMV-}S|OZTn^k9cll9-AtbT%d-@pHzAO=kcA7$`l5+^ zCwH9RdlKL++%CK-5wN?})mgQ~M(Hhn!{uT@@jtx)!tj6zA^^mC-umm;uhZdKtFz6O zR-T+V|M+-JsX}GgS1y1u#}{BVM@<=MK~xe{x%HX`4>TTB!1?O4uZvvLP3}2XeclZ5 zxH0`)H`ip!VK$mJB!W>_limANRk%{|o%70i|8h=kccEt zb%Isjk8&30JbHRHk}nn$gmh9`XIXN-#=EFc9S{7GQQo@Ljm#2EW_m0c=g``cd z9ZIG!z8yq@510<<`f%wLsD9fW7W#eGlSeCQ7~&Za1I^+b*?L$u_(^^@w&z^KhR z5BuuK&rAHh67$%&nM)Hp9My``t55a&_?^q1`Nco-pZg>$NIzh1YP&?%H*rO~dM|D) zymO75(aA`hLjL;IlziJ7&a1U&fW^{_IVgUDy`||9OOAL3-fh_huLlz`pc|f?YP&(q zw-Os0do8W~W%=6K=QNhW{oYO%i0WuiAj>+q(U*%?zeBTZZ*mID)e0I`Jcm-KxLMFf zg>HyLP}*UjprB% z(Egx>-*Q|*p;~#>MYd(;CTPx$cXMqwc-E^AvROxf>3wXw&c9}_Z+~(KeCVEDiS>Nf z%KX@Fd&V~9L#p_|+1j&;N91F1`q|7W#({kOP20k~(-Vqa2|5O0&i`R84eDg_XZ|^ISEB3TH&pX|b zkq|KWLqv3`n$_v$gt`4ofVu5_W9b$q@!U@|x@fZI!crydtsSa-w-d>s%cDiKSFi4v z_-sv_-%h?G-X-$b)lS*EZ5Sn={ML&ui_Kp37Hbo(~)@T5?tL6 zf!tFUmyne-y_+!mhbuL-_{@VA9bv!Rs?1z`iWoDG;okKVNR6S#mRahhAoRUM{@1|v z$|+`#w?Fzib9^PWwCI_2TSE1*unrDipJ13h-293;I(gf&V$qeCFA*9|8Zx5WB*KW>ZB$K8M+Xna!m2*+MnlILHcXb|LFe^9!=g1hN}ooNwY^=f_n1F6JsCXFveb+)FJAq%*|XVjQjn5Xxpm0TKgnNny({?Q4Ff~q-}jF8Rjqfk**!zw-ruup zKpqi3={pt>!eMO8XfHhkdyFs=>2Uy@L`DVDJ+B{-pbK6)I_H`mK!NKffFa;dRjOy1 zz$iY!UbYP;td;IZ#U`!+R3nQFC7g2B421Hg>ayGS_EF&98DrbuUPM{PXk9!^?T;qy?RX#P4pT1@UXL!D zEY}$e)q1qy)gbc<((5!|m~J9gsn^QN{_X7S7{(J!!8nFTk=2UN1OI2A(oc?FTuUom zH!G!j3K~m1)Vg09`HGLEZMlkcozSki#kEiQwMqC0Bx%+fk7V-}m_{9KnGj3!So~z$ z51s4&`|gKB`6H9=21Kk3MwWy@R^u5)dFs90S>25ggeWw~TDNMc8t;~QgK8_boEcWl z53PYhN^twg85niFy|O(-HibDaKR2?Ch8UXQTa5M@u)hj`Nn`8h16R92wqXj$l{g1Y)F+|bn_>4Ks07GvtaUcTnBF-vTw-f0Ft)Do5Osw!4| zSteH}`O5ZtJL{))c)d(X_lMhDb$9oI!I1O=+2|-l$YVGnefjd`c2kDSL^)5FQ>ge$ zdM%-Z>~xu4wQIN83f5)O-S*o1-c)+%n|jUIwB zH3J^-UzHdf6a;I%+C+dsNCwy4`NM=WJUN_jj>x;2p0^05E?j&UiCcwIw$!Gktg(ey z;pNB<0RdrGaS$$S4Chac5df?Ad+||LS=5Hj|66@!}oI*emSFMu`slI~0_bvyw<-kUIsu$KLxg7hD4kBO+csOTz-(4Y7!10vMrqE%QF`GyV{vWe0+qm zb?<-D4xN{HZwftI(2#mtW5BF;q*_w_?bB>lv@HqX`Uwm0fqLz)l;mVeCMFd267&jY z=;mAGw6wH0%(f5N?*J-LVDW}SH0PIRx9RmfsVnvZ(o3Iw`b3_Q$;p525qcOfsElZ1 zi%9!1eX8tSs~mSIh2=v~AN*k2E7xkm!Rmw}K;^Fe>HDT8W~r8G5$*qUFG`JDU>=k0 zzPFu%F;&L^vn%r7mu2?F?(*jiGZ~T>F9QH!K%T$IN=vk$`1$i&q}NEXsi}Ux0yl1O zJ)Kpwke8Ok>7Jh-!8R^s_>+T`)zm`J)XO?5viM_DQot3u&4%NfF~*mvY#={gwBLOV z4x4OF*N3P?1%F0#$7?;`06_+Pe(rd<(1^t%@Pf8tfEx1OoN-$Uqd6;0WntI+rkAAA zK_{N6mB5mO_G@m&f9je-&&waVc5GPBZ;fe7Z-?u(uc_M&-P}ie4L@&ODilcXUQW4G_(% zinv%O{<}(!-PP5_YA|+0+w%?gKhi5I_=|2otFGc`?-!9nscAP8(H zO~meTr~(hjO_V9}J&LRB*G0ik$T#xYk!~vn9pv=-lUqRa#Z$t2RkP(^A*;Cpp<7?S z@-0S5Qpsltgngn@Fw)i`R`adH)zi~!87IN_{O|F`3FM^Oje4GYu$X*~{DTTK?%Gl0 zxSY|Ef}s;=KSE**t!yE1MPEHnoD^ogGPj(J3?flc(bF0JA#@H)6>zI9neQXU#AsIc zC)s3j+kSasK?h8b{njm_*UxQuMz1ZU%+Y}kFj?8!$Ky31N)+QJ3Mk0jbe*njr&fPkA?vaK1K_RR2h0EIfv{-k0 zYs;YbR}wxiJDjbpwe7U|$?>wg`CT(Ur-yUaQFeCr?sO@h$JKr?si5b^(a)70;p`VW zm_C4UHYd%@j7E=jSqYI{>cK%lM!#>*08NC9InMOm+~1P3FDeI=rZYl5{xKpV0`R~^ z^l7o+pjtk-9%*7J9wbnMryTW^<;TFm5QtebdSk#y9*s;+V!5sG<`0^5R~LL>vmeVv zB`9D}uYgq4qmsi&xsXShpNQ;=agk=-jUQ%)i&=5zdnZzfmEXgP6b-#!LesXjfQ1tA zxaYNAsLFm%*%W-mC|lY)!<0clP5FKHETO3Cb9aabU3^(9VXuTPTcE_xpoLMGl>nob zhmpmP$xl}UN}=NUv_r$$yxn_7iQdQ9TowAWCYo_lL6=TZEKX_YWN2h$`YT>c)G6Vo z{Ylna+uQTKcU3@!_7miH>$K+Twyc8&!9qiUIxOo%$SXC zw_g38u`m#%%7+6OV!HIB4tE^2dI7m7w(lfIf{ z;Y#8sEAGeh=BKONtD?Zq^+$z;g}~oZLe9Q^(XK;EIBo-TCk7e=00r`B9hm`rUq--0 zfUWO~%fLAV+^meyNnc6Ro3IWCZh^2BGa zs*NX9yn-(mc;rB4k74mB8@UG3l+iE28v`Kk<;mjt3fx^zw&W2Ld-5oP)tmi4O%~+U zr{_3bdB8;!qwH&XTkdNfeTBtP@|K1Nq0?sj0kY)Ri;aO|rkrUZ4uHeR`*A#b>oA*U{A_Vx0Y#o@Ng>zbDc|^a4x!(e2RZ6^EUy z+fgDr@{*aFRM9+inL^CxXDECO4$Nu}v#!5^2<2p%2*@2eS=?1ktw4}CebIn2zwbbESh4UP(+iM$;#<2uVG1Iengl{G zhcBo9UuCN3EP-AF&iwD+k+!$Db>2op?JubMm8&3A_@nngvbCrksyCTKgp6wnprKNo zM_cDwt?0rdUFforP!T)l&am*Q^VQ-9w^RAN`K}L_Of!m;t|AA{q=PEZ5p~HinnW3$ zgY$m0bRPdE#pD*Z@JbgjqbnrChSDWk%E_9!O)zZy;UO)`B0;xUFT23-<}Fk06Y+!u zT#`OTbK=vO(L{73z*2W zuN_YUM)vnj-n(nqyDY2UitO#YE*K9T71mWPYSCb9Gt8zglnIVwD&Hvu;$|Q zXfvvYy^+h-IT7-<6{@#c4(NImaF?mLDm%TxTveRW`}2yt-(ju8r=@)ZW=Y7|BJ1e* z_!v@{vA0JM6%#v+X&0U~G@eqd4DJem&Xg4fbLx8`>IXxQ3cd)~y#Y8m6D$r0;(~P^ z$9(O`t4Q16;^H?A(k-kndnx#l+JIq%RAjZJGtM@fO9c)>r^$ufp|J!3P(I!GE>X&Y zxiE(%1epN3pc7Ou4gx?U*F)m_0a%?mlOGGOmRT%E8>FizH1ak3=h4MYQrEPEA230t ze`Hb_lUkHA6X%r?Bc@-yw|oJ(=>I6s$m3DP^}xs^?SG3|KiUlJ3ggzYylg)Wh4{SRQm^c>mxdcct2FR2IG!P^-*Ky5{sdZ6N5-t@@tFdfnB$f2W zLSf*u=h|ulqt9%j*B2KQ_=Y=a>a%@PD!p~L3=ehpmtADqTbE=bt;0y#A$n{iYC4+b zvF^P3sVS9#?Q`6$!14bDS&lxKS)D=r(-cwH@|M>(@uduX(L^ygC+&co`&^gCljAyL zYdnSVZ>?vl^VU6_JSChw0qFqwEdt73cwB+em@0|l$pNYMqkC;UQnY;e%+%e>RiaOu z;{Dx*krrl6Z3U-gk2*MQ3VE1So8Iuv+x}O&Z1kmNEobTPX>lk;Hv=Ipy3^lPQSS&O z`+5upKPhaCOGKcP2qI@SJNs)ehV&Y}mzPIHrK2_429uG~H<@D55FrOkMaG=)M13yB zF)b`)@{m^hhPzi{o@#IKchx5J`H(uW>l3m*%NYuTIB44Gt@HFPcd9jLj3OR|N$KK; zcID*zqDczb3`Co6xDpbQ+R&og2Vo3-;e1$X@lM*0Jqc2BQXL1CZ3_kjfCJEFdxdve z_WYi&1%!w-TvzA60omH37FEAQzHFoDL`N?U`NM?*4KrO%=(armR+avZD*YlWO2IgS zjTvptkF?mqEq4#;cgz;GXHJhw#JpeNnwGra%A*UXNi& z!63#Ah#dpm4bjlv76b5&)6h`93vp*v_*^S%(4W4Qz}E}bhjX3?{R&0o0}27cNWXG9 zQt=xya@9(!o%fV4+nj22vr>wR=ty;cAjB|h^+br15dK?sleZ9`BA09SL{9XXR#1xS zV{J~WsxCPAj@ps`Wzu2e)`58L21~RF!Nzzb&3zaD`}gmPdU~jc;J0xJ#((cNQ&dNX z7yzq~Vp4kQ%xRb6QD%%LN~!Izh$f@RCJxM-RY6=*2XAlT{Yv18*9P~bLE zevLo|l%38P4psZWZxC;B_Oe)p?)A+NCuID(68k9bdb{OFq)!<6`S}Y^UOMj5e}^We zG6ml|z-#S*rcaOx-oW-ykeixlKnU_mw$83#e10G3mX_~WqDFZP9wGkJF|H?n`I1}@) z=})XsJ_Y9lymt`cyb%0KO}Dx8^kBf1Fu?$s9yN%YH2&{$#CZX3)BOJM z_*cCkE~(z2^joNG!r0$dUFN}Y`sP_gnJmR>+a=yJlIs8A&&LzRoYo#4e{36yWM6FU z1<20U5IZ8*7zu`OXQ|i0Vn15JwB7o;2(ZxZGE4Z0 zu3tG)6`|jL>m9L}^`w+7ty`StafZW6+((a$B$&2^>@ZP^O*znDNdDo1EW@9^ibm{T8fC?$f6+pd}mgb4KkNsbQmzO-EH-NGL15{-`D}UH_|1OhQThfD1=%HP~ zW)M!eutv<=M_nCiOBrKgV#1vRofqoAd5G0u?0cFtwn3TTc>DJDaZ;5hA--#kr?}_V z-Fmr(VB3rXl)LH&g@A}?YCuSlB!fXnh$JS>OV7YtOB>hv-&*^7AZ*HIkXmI7j99!g zx)~vn6W}S19oyduNJ&BdRHR@xTYVZWTCQfiH&G}xj_YXjk&?e>-u&+kq-s!h{+J_> zl9rb=@)8ISkF4(zbDY?7&Dx6Af)w(PJ?W@eS<#Kcf}kiU!TqHFDkqqjm{r~fWI!oH56{=^N%e1;cS+32EhEOojjk0A_RR9C#T^hu#EcFxtaQrmdpAD77(;= z2L}hFgyA=*rG;RoEeA~4;rjgnFmuoUTc~^}>SrfM>5~;UzB4!b0tjAr0|0 zr}>{w70UcS3~cHmj8{R*g_b{b+{MKU9wsLztAS|)RJ5YiI|O7ED#da$zeV!S*urVi z(%~Sr(z=fz%?vJ%+Q9>{YYBj7GjcHj9UeF?75QsO2J%)wk^og`Sf zBuImCoh%Wx$KqX=1*=HqWT%d;nFz6;9PLhmtRuqS&d9t^&aAEYE8v>+s)|-qir@Lp zd~E%(`eW8R+Ptrh4{(VCAX|d$2Vfx-p(0$)g=HR}5SN{;XV;fa94N&YqE#;W;tvCH zV03;tc4A?VAM!Wal==0zI3y@ZGQpRZPJlVvELvfr(?yfPfPVYf%O|wH<%4dOhc6f( zv%sWfJ=GFj9g+=M8$-8v_p{Ctb6{ZCV&IW)bNi?8`p3o2!R-}%LV{qs&1-gi6ojeb zai&UmA9A*(#NU!LL{ft7%mDs3EtY&HPc&e~ zaDkz=yoEBa02%LI##QPRR2Z{99`bT$Z*#@ZQ1j{VbsF)VP6iS+WuABQ| z2-6px({c9oNUCzuaCU^mC7ZqJ7TiI@ip{)2kI-`GJRYaA$8N}55SYi_m^;w#~i3!7$DC0K35W@aVbL(FBG`N+A`q3Ta0mg6y)ITpCnbd`wp};uPCciWeMtxYdUQPU>o4h_V6({mo0m7a513?P!9i zjOI%_HL=iuS^3b@G0%p#Sws z)HI*$r;{QurQyAy=OcuHQymRcv}Fb}(-o~aIySlm_7|tgDL@*QQaIi9qA+BsGe?1- ziU@ztLHHiXSjEqPDcR3q(-LJ0?vclf@KEAzFABe6G$WpCj~Q}(LPR}WHO~nB4Lm3< zQK;7EiLcVT*yurb3hg}xJh2C09$0YDk6V1sggp!l7w5sWSMILk0^$;=^$`~i>oj=> zB*LzT3s|$ep1jd5f#{IK+*V)bdf-F^!B!;NGY~{cW=cz!JX4|~?XV(IQhrwlGI=yL zv3NsYMyJJxg(XaEEy1(P33GfP3uB`%+=S$*UDCZoX*8>^qg6-LkKz~Gimol_<9HGWrVq{ej!p4bGreD*lphgwQ_CvV90Yt!SUB2ct-)}Qx z*Sd+p)10b7sS|Yo(Upz-r--CS6I1oh_ogTyaY0T~>j{FHHe|*BZWrl?4p%_s%cj%% z+~`3P=heRM*KQ7=$X%$ZtpS0cOENomJ7Bx^ zr{7wtDduX6zcEApTT1^7Q8nD?p^e0U%D+yk-VkF9Bq75o5y^b~*c)d2A@};ifHgF< zSS(&T7_vrqetv$q;RU#BK2a5gmsQ%Z&Qsv7nv|?;_gMirOK3fpJAG|?5pf-(^~-qJ zGc|o9Z1$V(pF}ep_)-6*HXkF_1*M=q_{E>LlA@vkKtlbG+r-UT-~X-rBftgjDp2A! zb$wI}V=PbZw4j#UHl-Om;DN{2{RcsiPaW?+3JE<_aX(qX$L1vlObl5P9&-98Iz9rx z8G+-VG#yks{a3~&AO2e*t(k>Ol!Mb3HU(>*SNEv+Z~ca5)U5gXuZG5?4Vh~I+T}@z zAiD{wIb!pfOnNOu+{Ix-#8(IZ7ZQgKFsrC(8Zy?AGcuNGZp+Hb#w91iHLAb@lmsJX zVxIaxZ~V{a>i-Yg&d{4Xb<}>Rt%ZdS9RDXIMFLc^2Zn#GY2Ap6o80{SPetfBIKco( zI&t|@Qtns%Xr$Q{wrBm{`fy(XYLWRFio}e|_j{@NjpB~AfCYzx&=KR54{6K5k(3>4 z-rRn4$z%~^%m-M=@u`d@+3=6w7JG4OF~pSJ8Zf4O-pPN@_To$=*u zLg$f)xF{YV!_e{Y`VIaUUlxCag$J*JnY8zpZ#Gv16-)T?YHH3yytTP}V?0l?gPy%T zj34LN=4$RdK_aW6_9mvEAq$0&@-)cr{M->aCcNj&xS!SMx5Xvm$*bIF3LHpyyxzD^@-4BbPGw6T!#y)KEaSfWCue zA2)MYK*h(>hU{roW>+bGwVZ@Gn7JS>XD=zaHE0`kv1<* zqe2l%1^sI~VrRE^DPs7X9>~vE6A>-3sI-iX$fauKqFtIKJ9ZTRRRl8QfHAFF?_Ot4 zGCDvLo|^yZHfpP)rn(W$f6}t1|h9ROkZzz3Rvh)l4Um>0C zBlU}5REdeb$*4AklNE2m<(%a7a8f}}t_I&*61TNs?v)O=46gNGNenIa0Ir)TQ#?1s zN42yF{0-?4_j~)buyFl$yjwoUevIhj>G@I6Y3PdU7auHId2v%!oQ-<58^^g?Pww!D z2sXow9*-f&a=GJx!Q~;T<-7?mD?9;X=!Pn>11y^n5ti44e&IV=hC$Hb+f_N zRwZTSi8UWLH#dQLcQ)6f`G{q}I*PLO0?c3PgShdheTAhZVsnYZ&d!h}so2>6JozVX zQNsoPCk?cXe@&IVp{MV95qd!W(%9Hww?73pbbY)`)E`4)b>Rfrf*_wIFke;!kYgtW z1?06`ETkApME{x4LZUcj=OH{<&o4CLjzFhBqKvrQ8rPk?PG<}4`kisBK7oTK0nBvp zCrtX$A4q-hL1QJK=l}s)P*zqZv2!{L#xuIBaf{8$LP;15`bflWw4XRw|Ah8CGpusf zCpdn?D0SG(TBDt`_2II*StI1;IO=^|cU-1s2T^IkEJHOcl)pb~Vj>4VO6=hF>9s1W zBp^=fQ1T)`qiEA2Ta*^F7w%>4FDQ#EWHckKB^yuZ3?OFCZIMLOy&jbXTFq#M(H!_g$@O|9{CJ6D{jZ zU%q^qtG6KnLU1gCZWbSxOcK(hkvX}9_5e#N93Te`q%N}}<47Eg5eDKU?uW=7T{^2o zc&|x2Aj)O8JT3Gp888bn2%w!h^70 z&hg|PhxGRaZ7-_~Z|}zPXk(OC>mmCcA#bgjW4$wbg45&S|DTghe_o6%2SqE9;As!B#x{DiC6WzzyJ{l# zC^N5&@7=3#rPa>9aF#M?dmF*{QD}+E6i6R&=DgX++I8Osl!Dw%HPpT0oL}95OL7yD z910tVS0A$jhkB=V>yl%TLoy;j43fcXe)Z_9MXICUnb1KQ%2%l*D~Mz{4af{E1TLpd zGm3&RV_CrTLrC8`vj%? znYZgnfVI*Mub~ma8YKZi7)=i8x_j2#(Y~z;nJ^6&P25@3zXW;*>DSuvpMZ8)hAO^0 zw5=pfR=xrF8yEGBz|DD(AI$?tm5~ZU_U+qN+igb-5p9#clP`s-W5am-BRd!QO5k#< zkJGg>41|9h9)V9Z*oh}r3=@QpwG~LlqNAF8twKI@QhKGlD^++f1W(Wi9t^vUIB^eL? zaP`DBu6RZ=6i$wyB5C1Yn|Wyf)qYH=O5y1GQeXv-@?E1ZHHH6XviP#2XG%B zx^{c2sOS=**p^r>51bmw($r@T^}?)Yot_O2wfIe~?`t{jYg!!;9uU06Mshww+hwi2 z`_%uh1ok>jWx%tUWDkY*_RS+J_q8otK^*?o$s#l3nfCasyVqt4Ex&?b#$E2; z2#)oN1>LnaPc^q!PQVmh($x1w45)&fw(BH+UnvNG#8GwUeWsL4QvG?^GK!O!*IbEh z9OzZGV+2L_vj9~U5=TO9;z2n&%Vb-0BX7V}N`<*5|MY4xziE^F3x3qj;9My+IE=dv$EYvOgKDfJ$ zj8&K0tD3VAZy5eBhSuu(+Eh~dTG8Z9`7|vJwKxJD*yG5{6D9$4Ui2ErbEdP)<>2)f@_@*Vl2mXED7zj@EbP}d9TL| z@GcJ+hBuM4P1!wM=WG$jxb-1s2mAfTegN<*kcd}3h8y@cuNI6zsSb5tD&XLWrxNS;+eF6f}^eYRN${qAyX0?FW{5IXW;Kce=oP(9_i)=23E)X?0x){=*;Pp#W| zA!b+G`sb!axyN*C{h3sz_$y_ix*7#%JND`~uJ*+ZZgXe%hDu=_UB4YPJ&PaK{*BQ5 zqdSH^Im|7&Q-=G1yj1k+I~;)sD?V+BCLxV3|3Q@~$aofZ#yO z_^OQ8CF&|NG_-;)Nd^NKw-1ps><}BQ65DO>=JcMd&^*h=U(X2EBaCRtRUwp2a`jK3 zfgPeiF!SjRHbs3A(gXYJ@eg}ny5l{sY?^%#B*hj*y_YfsR`2UE<}>~*UCgcy-2~kl zda3Ip?{B?Qhq87#QcTY4y{fOipG)_U9bsW%LG#ra43VQZfp|QS<1O1rZE;d{T@imi z3|XTjO6V54|ETSlQAE7N+^iO%ApI19zDv`WGN_JDow648{Ost!C23Jr`S)3Q$HuYaV!bBCN-8r$e_6#WpA>KVv@kxWDTtw{5+0 z>&+*3TdZGvGEFTl?%7zg8Vp+G|DrNGu65;FEE5jKPSPO$<6XW2H{_5*0fRO$+>%Qo zCn^dJS^q(ZiuvR_g6Z^195co>3o*O6APzxyJw(RjbKPG^`nwwz2p0c)ODVDPd(_RK z!B_7WH(6a~Om1Bd!ueH?8%}Q%iqFwH3ebM{s44IsC#$Y?Ee=r>7kA|2J^M3#F4(Q;YG($9p3N6`sQF$q zXW@p|51(qsMqyGpouELui)aVcEI(mkng`gdHm3G%^vk<^Y8hxR$3!OFU_+eGM7K*> zHt`hnm$<#qm!@0UzDD5DXX^$O(4%~FJ%GD~-#9g;Vqu(5T9U!D=Jm#Kqsi(kds_%k0?EWjtu1Q7rT>@?sUG%XMf-BWOQ;r zL?GF@0=?K+oI=W69l+xxb1Q_HLL&(kAvH?8eI)vStKm70r>euUS{mzEE` zQPb`$R4ZRY5LLz05$(d1mh!Xr@l{l&gu+CK4LaFr@=zT)-{QSVAa=CPE<7aj?VlHd zvEM8&xmAtx`_bt*#o~_5JANjW!6b8b&oc`eWxY(qE0(s2+eW5=UNrq2 z$;|1{R|*1Q6PB+x+i8P7_bH?f7@)f(6x$<; zN^s6K7z&c=|44=UOe4wnk?q<<+kUi6n2o$A2**M`lG=jl~(loK8SC6=`q{(-!wdqkKR(>F((e)cX*lLeS>QFVNInrl8RQ~ zi@x9XjKp!$g0meblUY&xf0g#uQB_4<`{+Rs5NVX|mJ$$U>FO^xw>4xm(D znnl9WE?4}|Y8l83ReA!|M*_vfnqc248>mjPmyFgY>T!)e0*!KsnHNJ9vHh5(T;$lD zxnE&-?$bkDDzfNO8+!g%-e`jt?pP1LU4)imxY=q$8XTgm)eQUCtNwzabRK7u)tigu zzfv8~_z$M{TDB34LtUXJOy#U*;dY3r`sMj4y5k-td1RO#Hf9$S!B#sQpZ6fHfduw0 z8s7Ffq2^t)MEs&u=}lO=I%ZoQD$@HC!6h8x8!&$VQAcgwn`PKh?O?PYiWXq0$mkC{ z=@Iji{QM*e3*45O30`}^^dg|&kMrbV$*r@2S`y}d0r+D)4e@46J{GU^hM-%PwW~N1 zOA(g`jTkUT9w(l)p|>5mq2{hjj14P2l#PYHgzVZ87uE&0NJf4ssZ}t(j zULzwFt9dviJvrZgWVLoVVX&BZ>(FT7zSo4??~k)JGY6b9RDG^m z{Bn;!^e}NVIsUP@I*Rr_*9i|dZkRY3FK*^26WxcwPy(s&sgkTMXMV|xb9T-@GJGs} zUb(BpcNhL>nK%sMp@u-gWz9M`lgc?ft{h>Gh0zwUP+Eh~q#_S~t7Tge+V?_;XVPBR ztCrlS{ii#k@(FTQEU9J9W)64tPpN0F#?f}o9fseH5lyM{fpVrb?1$E(umlUCNe9Ph zJ0?^tyW@+v$JXU`4)4!T>s!TO0__`OKKsVE+&lCwYKr;j@6>7eHnB?5l|5{|sQ8$2 z*ezOj{xXH=w0mLU?mjd6`fbe3{w{jj(pD=3;j$~H{B8{f zrLy++9O_ZHNgA(>N-9qN_{{GM-CB}Rxacod+*SU^rHVK<&(eZ4JLX<#)YYM`#;B_A$5aM zd;Ns4mh#L18Gi#xvRSlbt18dKw*d=@Rhd#ntQO+lCp3fVw<~Z%xq9zm%8+qktbZqJ z508J&>8;xI8UOosYEaUhA!hQZvLWZht4lXG{*c=`bNHAha8yRKEj`lzQ5JDm$r>wMDE|_Fh1)*hlr?jUjf<)2nMenH* zP|zYLlLF}#LnbC8WPfv;W*@O`VDM;^@u35!IW%2N3vdYUv^95ZNbR)k3YsS0m~I-V zE?y08wI_}(y`6ya+*6VM6^DM`!;ZUO2p{lR^S0$mV9Kxp9#QahotO@%?K+Q2#I3XD zbfzc}v+NBMcY1;+s@E7L#nv#=d*gshoi&no?#y>E6f;FB zwo4}ir#_>ihW51YJjB0xd<7pme^GJQ?t`EFhW2e_R3E#$94?THn}S<+Z!rDdv+WJf ztNx;;#XUJkU#AyWS;_x8#YjE$K~0%x4_U?gs_^!pFzed~Jp z?xW!)+`roURB+phhZGnMH|`8{Zf@3oCTgB5p+_LsOdPf`c}Z}vad}JO5mijR)15)0 zOc;#${d-P&8l(`kZaRfR(|4cYtZ!p%l>v+UEOxEOCOI) zwcK%hDIS2*f)T3|YndDcMaoxitbsK&l>T{_RFr&V`4dC$jVOhcmDQD39MczKa+19J z{)_nbnv;&cz^B7=coAASGR)P?>}zr|jmM=w%GF7B)k0(3Vzpg~ti)U4+?xyqk4Km} z1ntOJ@F)ude{5K!m|Dj5q7D(=<&Y>SKqY(lv3oI^@Bwvkhg|->t_<7TTd((-P(vXH z?Ix|XM$KXkpkYmB9ez(t-AD;QWEXB9E4?gOWLE+U5W`zCGVaNd zcp;BWbL$TpjJ%gMyyP=dJ3bm6pE)e26(4bo8iLfBukvsZ8IN+XjvBUcxr;V3IyppQ zY=^6A_Ax9g5Bp~dd-|6b5KP~IJ@Yha%aYK&L7j~BD>t;St9%GKJDVh?M2?^5bdMty z6IcE?Y=-E#8#`iuoB-FA)OP0cUA4kH1WbFST}uMMDJwP1EsMUy9_EQ(&N5DqEY97} zx9h%l*AKUdG*EjK7Ak+XJ8Kv>k^G$}L;o%TG7KISC7JZ8bex`!&HO=MUmpx+ro+xw zMQC|nKe*F4NV6zRk+B`QVnw{DG*DS9=q%Vc=~sW&s2265I#+lhE$-YlT6Qia>Qi>$ zvL&3ux2oK*02X?>#<_^JD>4%BkYbsB6DJZT_;T(%wPBkfc+ ze7^0_0(XX7Zj?l!46;Oikg82Mvs~M|KayB0Wc8!YFaANH|c)y^5qTSlA)m}sBqz^xA|6+9)m{T!n+MZ{7O07eM3e1r7g;G!viIr4ZF^6OlBFL;rUr z$7T~ezP;Xz@tF^(7+?0`^7s?3Vf&$FeZmY23u9(uGkxA;Q|KlGVGb^)(>pQA4y2t! z0vaBE+zWqNSj!tFM459tHo`ew!HfR=k{=94_>{Mg=h0@9rmp;L*pcOEpL;)iBRh~; z6$8efEsB#^hzhe6xsxMFapMvDP!abSA0xZ<8h;iY9+cMLc%qQIDN%4?$#;g@QIR6$ z@R)xIz%PGhgu>nSK-UDL_J~Dsd+bndUeZd2ou}MmqG_&hRa(n$C)aU zpl@{ZuuZ5)G~OYlVRp^m%yZF$+~w_E&7zhpTxn@VepRhBVLKK+y9wCHGu6yys-SHC z<=UEpAp}nA#1ZGnm|=3k?-B|T(qk{L*xtr=1g_`0E#sl@InmaRItr%BBdOP@Zaz&g z*dHoR+`<5I#8w?J`Gc)VWSCs3=#AvjM*UiX^(tFx=d=SxIUb$01Q!JatvueHRlsMe zOR@%>_Y_!kX0&w2=SHMsm40jCLc=wpr2c^zGbT=^P$ne&yI4EvWQu;157PRiu(k>x zc0LI)#msW5)|zm+bnw!MItY(g!Mim%QfvB{G4TY}0|jD#iZ@rRzUS8qmuK|p^rA>W zr9Ms$$O79IDlo%SxW=F98}tU5R7S#uGpVG+xN}UgP z$zygJb8Xco;xx@bfty&+mKgRftFpi;J%IgkYPq5pH4&-GXAI$ur}Tz9`7y@lX9@}! zd9z$0iAQ(|2#wd)Mufqfi~?b;mUJ>kekaBgJ9wBfIDG=Sol>uViM>vX7m4#MJ8}I*wwYff71XcFYyv!93%iltdGaJyKBD3{7AJ?2 zzbjKPUqbg=tMhmDz>_p}Up5aO)kfhl@ceL#653elwZ_w9 zI$v#ORh%E+;(daSOL;TE3{%?pmh?AA>QK9-;misQc2x%nDK~~t?kc+@l&`5H^;Tyn z2e#DLI_ZrV=FEe26%f|iGG^+Xj-3~YR>Qx&C&VdP(r;@s1x)TI@{0)YS7#X>U75w9 z{h7`g!lLK{=Gg4#`NTug#Pnbr+4!x!c?IuF+>f{FhV2m|UD>M70x|~z3T-8$e-o1O zo5sN#5+$=*{`~sBd+`Qqv&2>sc-{*%GIFZ;*4Smh zg^$$b#5i9v7S)F62!d6~xM1fp7a6X#oC^ZPY01MDm;UuGnBgp@%ZHr`=R~&rw0nZi zb>x7Ic&-h^lVE~D=^-jm=kir$SPSoHFR+m{8L7%9!MtDNa$1f3R?DXR-G>j~azjJ< zbb{)nB;VPXs8z5s2|q1*?8u$z@*CRjcY4KZN3dQdCMKk(Z;X`pzhXCO5qu8*n)vL- zs#ap}vxfliPORvLeOP#hMp=n(Op}D$iaNYox>`3}$0Ah6V&fAxtdi_Dtblv0x-O~U zff+3Jae0+_D$9*|8i}_o?G$#4cAM*Q)mEjL9+gTS)%WqL?6eh8n$FE1tPP|jy!`gN zzn1&D8Nm1P2?$8gadv8sFQYGz-&1S}IUi92Mn6)>&5=Gnhj8Gl(e2ty>^Awc|Iqyz z32bK`ZM#xe#@LsQkfWjgsTr)LyWh~>ZFa1*xuf&;ijYRQ&{P*tCPT{*s@Ey=0;LxtNR>f5uUoIpR?_zSiwkrzq?ta z=5&*X*03cMdEc6}YU-y;hcVatBn8xXxNw~Eo!}WFy~q60_mZ`7bucU&FHdsSpdDv| z8ZySl#`!+)d6bODznj5!Qn{yxi$Sm34>sRa?}!$Ydbgffy5~HB`#Mo0Et5IVUkOd=@dKuZtIQF@%x?I z`X)l(T*7-2xX~WtJPs2?4TrBjym|8`w2xPjFAA8uNR^E6!Uod*BkPwp5VUg_};Cj8!HExqzO&>N(8)seTwBl z%!`GLX8~*Fg4$oqEk~?-a)Lm-VAc=@e1F2k4PX$^n8JKAjd)ik+?c9OE8#1Sg)AYx zG+$|^V>?|&*=|Bh5~I14$sg1%aQYuPdfm|LrGM$AWZ-A`tXlq#W*3tB~yz@=WZJnMAox%=QkWbcQ?Mj=rz2Fd20!0<3jN?hrO z57Ke+QRI`-sOgZYMoFRo0+KiX4XJ2i(pB%5g`q{#%CIaS7#(M%-P4fi z-+qj(`^6m2@RG8yyEoWSL{!tv%uM9u#A1}_D10Ayq9;kAdQ?Y;G-{ht`35t1xce#% z=r$uua^KIxdSydweXqLy($1l~cu&^Zsx)EZ>a+f3BVz~JZ4yQI52uModApcJMVn;T zos{*bie`(v818!Rm0vzm*xRRkLWNxjJY^5hx{8#l#Ng*Qf%$nnsN!LWtn>&f5L#kH z>onNgXs;E=kPi>>eSdEcOr*F>n3&`=+qSm0aThFL6rVA{76X1T0`7}@2YzGdXGAgNnk`(;9&P@n|@5X!(xd$XW zaN#{I%9uv$tjbctZaE)%86Udm;tVh6XlgyLj8L^-#CAo+?)R(^)kjgs=KIuFuXKj& zD2M3B8SGb$N}F9xOqCs?)~NC6N}k0RYq!~qjhU~!X_r7{-3)1cekg9}+6uD?nH%2a zdSlJG?NB=3+r9kU(m4Gwmzwk=qqER4Ev3(&FpD*#b)q{DD(VKKDyFQP2nSth%U5IKk77!adyCH4+1=jHa^<7)9{LDlD-?Ct}$$GsJ;Oo_p^fH`pQP08S#uGis>b|oM*g7u+``{_mrCM_}4Y*mq3_?%H0suK>a!)lr5rJ^mUmWV~aUk2muih zO+ZA*Ec&mH_f1O{Yc95r7VR9-t}q3v7aH%3?ft~0#Pe#@He+s+3Z4?-SV^jW+z-b{ zsZ5>b_6p%C)H6hDbIuwP*P=9i*y*!(n{KuhNm*xsD`c=-+G`|lvr%s~LrL$DT zT3;ChSWm;tDCHU@U9;M3yL9%Dzfk;MnZMlQ!4KcxO6j70Q-vnFi*el5wv)ldx;0Y_ zWP}`g=zz22K2DL$9u}v^pU=2gc+_urv7k;;?B%MA3U~+k7ArGz%O|sb&{deJxp}p2 zmz#Wh*+s=8eH|H(>TN*Au87H0UNImfe4EJ$FJAnMh6zHZrlu{X-20v+_>nn}K1t-N zA;G{iEguU)@92ig38f3T=p-e)e7P`!oGqDU>6Qr$jzC3txR4vhuMw`!vbo3oxxz1P zsvpk+as33lIV0H{$`5Hw z6wWR#Nbeqflensh3pFMiY$`>-NYOLSb&XqpyhT1$c+|VbNwY~z&$R;c zNQf3pv$br?K|bdG+csB03is`)umt(+bWtXS!j9mZw?X@8iE3FVzjjQHvigSU6w4?n zVFkV_66Kj4rxz5QGI`}iKmM;BOF7HEsPCM5yBE9T7ms!qVSzR!bzQ%fLV8Wxb{D&| z#@Fr4tawOaJHK+;SxXy?PY}LcE9xH6bHD3myCA>(5H$A~HL%VDi}4l}WLWcfnW z@5I%*ApHKZ(X42S@#Bmjk^hXn6wZ*_FY=1c7=Y=3NB7A8ULJ6%^}7~1HWB^$baLq!WSKv3%3#W-_IiB z<0G_bji|k^_xbutOGqGP_^(lMyv>eLTPQ#NO#-H4&+<@ghnnf@AIU4c8HtW$!0(X8 zF{K8*L);;{n}tN1;w^v~6&t3`Vz$$O`QO_=D>uFgXdCK#qQB>YA@GR1=0gw+l98={ z6M#6`<+|bZlS-S;@BynKM!)};j;R)^r=H3&{$F%#jn63rO^SB;Q|f;$aKsL(U&WmJ zGHCVY)jH80o_8bVJz^`HXX<3`VN4KqY6O{}i73J|r4( zMHu@3*_iZughpdNTGB*yR7W1kx$L|G6*@j@7}?H zm9;NM6AJk$dwQZUs$_ft(G2uzvDQhI`3`1iicwo@5Oi$(*SFkiv~R1cmh=n^lLrqk zJ$&B8*@c}Rgu&B@KBVQ0qzlCp4v=UQ1GetU~>q*8U#C^v(kVt9sM>i2pjWXyF$!C=>O9^D~^Y|%Wd zrSNHfndLAo7-x9HH{Je}zZOBRHXIb8Ve$FrgULCv%^p)^Jb~=SAEW zSNc%7beM9_e|i1D78hD+MF->88ZlaZAvtIo;!sJKh$X%BF(-%qONI!-JrkNbmkR@K1QsJ$!X&^->URw!0tu$8ZqMU>uj{0bD}!18xG3Q195rqr(%eP z(VH4{eWE>!0H-MKf8PH?Qqmo8e=?Zr)2AUIlDm8J*~#{zUKr5O(mK?bbYlahf*O1a z&H1O18?Zny8QR~1z?iKS<{*RbOD`2wJ0QY8d{Fp%QB_&l3quS)=3gzK!~5#rvV;<` z2rEcBA3d_=hvrL%wyDF`l@O(!2Qcwqa_i$x(XM#+@phfCAKrQZ`G zRNe}PEiIX%+`L)k9V0}g$)udVs&?K}k%+Cxhx^2Xk%Hd>z`#CXB9n>?@H^zzP^oUJ z3y+P7;YFO;c##8QsGg_W`q=)OjD3{X_kfFwi`DT`Dz&FicjqIh_MXmB|Js?dDV?9R z$TS1(`OI+DVZ41tAREFI8BM5D9an4fGrTc^sa@qK?>GK=ssBw97bT+9?d-@2)-vNU zJF~_m@~nAlOg(;TN@ruHo`{BqCRNCT!@zG}!ymt-MH(5;P3v3h+g{Wvomd>LQs-ak zJ3Hu59nDw>o|Wzrv~RB}^7CL|Vs_kbJ_}Y#<8zbGt+Ah38*wtPnAFVNTCzR&j%sce z!zUov{o%8X6u5Z_K&w$c0ubMt1E>HrzsqvWLOUaS66k0WdvPf#+I!TCfLQLDqF4RpfV#p++a> zccfk(%8Vy6^d07_%;N1&x!+ydd=X`l=|@=e!W(~q zc%fMgrnmkc5{o}N^8EAbJDNk&F=K}@mu88cm5}}SJf#;3xt@nJ9)Qfl%C%!ajBofo zC06Ad%C6((%uc_x=FB1}M*8jA)ztpZu$7!MC)|a%0IIXR% zo{O;$1@AQHN%wzO5yN_|hzbH0^!%)>Ea=>UnEpsfo&jIU+=R$pZjO|rqhmZ18JO9R z+U3Eql8`xnce6q08@v%#5!WKT0E0+Tq*>hNv)vfMl;Qb)bPe}SXQWAxy8?xi_0sK$w3Qmuo_MhfcwuwwrIMUn3owx5UfO)9XMp4Y+U&gM z3FH$1c+@yw#$PXhj2YwBV7W`_?OF18C6(PAOjfxBAW`tf2Q#Hh(*pU;57h3<^Mg3e zrdNv#CQ6Xf|7cz_MO47=ga<~=$e7nj!~|pJ;MjV3@>b9d1NODlu-QF+00J-mmTi17o5fPes)qjwx;i@&A3nHj^UiVCiP3ty-t z=tPsB5GpqL>Nj3Cg9c(1k^MVB*j?4EJ^Ayib}>#!@Q;?w+S?`PI(^z$xS%XcGA#!O z_UAok)DU<9+Ey#YXub*+>I>hOa*n^fW0e9PIj|h;{p^QFN4Gb4{oYxKzF$3o!*h{4 zZC%v{{tRs&KB2_I!rD1Ji~!)Zw!W_Ghb3!fP&YHo6%-UyP+ID+`&sK`t*G<`fPje! z?S_k!bvb3_a6OI)ZMN$3iZEfwMZm32Jz|9t>Oy6Lq#jeR} z5A!g1#^+^LUaa|vDjTh|?y9jwS`iV7U%!6UdhXITovg7o>~@h&lo=tPot;4y!haLU zNRJE{x(}rbgp}<#LNkyipR0B-P5(LA(4(OT3^<@PK~M>CFqZ5G56ueS+((-{TPf)? z<~73`$`qSjc2aWTnFfyMj=-T19GM^ADzs@*`_4j47~NStFzgunIEAC?nR2uLIj6%9 zVW?m>YzKt1-S3aUldnlgU*~KXm!}Qjo>x5o97lMf$UBI0er`c(6G9Cf(W9363!&`> z0+`N6+nvnIGc=gv>1GW=JI%8e1|uwn_5#>Bkao@Wo!yM%QF1*xKb%E~>_m4O*DnRD z6{0+!&2F`>TG$^qtT~_d?TL7>@3Q}eJ zJTdm(9SoRbs`j<0Vc}p2?%bIAlp11eQm6Bp$l6T~=-+C$?QJ-#mc5+3yu{_jxzoYM zB;jek^4qAtRj-273Ojb@+aZ8z`19>??b?STPP-|d`b86Cy!*@?!T~l-6 z@?!gvnlKvZwP-+>jeqtf*Z#^&!@YB7N&Q@}(cGeRXp)Z$gl_LY%o%syWQ_`exVXqes?4ZG7w`1it&K(Mh8FSj6`J4os zv5yjfF-I6Uj(+GWNskxalZ*E2?ChLq^r>k-2jo*hRb#JD`CGQKHif|BrInHqb2Ee9i z1^onEfBxji?4CUY(OrK56(?Mp&FNS;S)p@Q%b+Ws=K4VP`>jtvbW5LC<5M5={Y^O; zl*+mv*ryC8z!~6V!l}?|NPJ#YHjkXEegD*Os(jYes|XIB|hu81|p2!SQa)2-@Mk-ZX~}f_emH#`-q_^JqvZU{V4y zU+L%59HE?VLfwG*cZKyTuEbrhnBlhI{>^)M{QpR`1du<(#s~`r4Y9*6EGR6LFfyXa zhEiQOc}QdXSD->=5_8)=U=~Da@#Yp@M6H)JBY~E)YIwd5JZP$A)Bl|G1X6BBfX1q( zBthL9vHRyVp0P3^SGHl$HU9#`U4!QD;rIg};Hy3l8R0|-xGX;hsvQvV7|`W}6u|c; zYMrv9SCYi_)q(*-2}Yu)eQysjx|AWPiVFx-S%932JtVq6KD#5Lp6(z9va!i|F4FCJ5anBwPRp zi}tm)tpiHfZ9Xkje*xFmC49i55c%;V8>|IDI9#HS&sSf#D`-{UH$nbDfsABJAy$52`2Y6~qA4WF;3Y6s9Xfa*pqk??}29D1LZ zs&k}zCoA}0q_vxdTxZOBZu?yvuP}dKPe^|m_2EO`Y$Dn`9)JQ0jvB?Huu0?a=XNc- zCbGK|Ch@!d7GucZj zv}aEu9+!YN*?XPe^1o*9_Y&b9JNB|HO}exIJ)9C5z}gUowmy< z0>JvX@7=qXnw$_6`;1IAZ}jt@(_e<`WA8ud4b7?;gcm;o^Pl^Mi9#VjcfBF|4da}k z(;0E|7vKjeRvE6G#F)yL{y-#38ynLiubN%g)a!q($ar*mx|p7K2T(1J%%RC9FfjFZ z@7$@Z_r4h*<|W2RK24#TfDUUZ1Ni4rq0Pp@L~&#m2ZwvB=@w~`3p&CqhR*sx1HNqf zF+QSAczTKFc(h|Q4Y;+Oq9PzP#6S?BVv&ZPZZ}hTd3j+%^}MCo2p5eDyK)66tgWr7 z6ML_3D1F)F_r!#|I`z8*`5kb5eM)m?s-vSKZYbZS%jo0#jZ04>ql$HFXn{$b9&UH* zIyBxa){Or4P3^4t^6;|E4#79=*p9{Tx~iJe*i_n?2#1sEyNzlntI*%W#%RMDkL?1= z_4w*pim}6%4--s(--Mx{5V zHQR=lCq!G#m;OL|lOSpwwqJUCKNgOJ_qc7czqaB^14^@&^d^9;m^_9D?PlCSGazTn z#2TymipTr+gGdL3tUDMtIrKk+n*rGd5J?<})@!wF>+=o=3+pBf3jOy3j&DOl_U;`u zCOJQDz{T%O0K&FE)wQ&wfCQ$YL6XVFg9P-Fvj7-faD#=##V6|Op;q7XXoQ8y6>{-G zoG2(LC@UI*sDOMTqePY}H8nLXAt51^)96OE{mfLBjTj^so^MQ)vmXqAwnD{DAttfv zDkw*f4}p`;7+_X7kt%gwfkeby0K<0UDa+k==KSp_oOkJyHYj0mNx4nIT+V6129SD|lcN%JHaUhce+ntpd6FHriMkbpYJ@|RKHVRA<@Y2vamlce~?s%dfeuw(=n>Dk9 zFm&$MigHRycb#2a!hpUv`qAKZ12&%^OIhAH7Il{u1=f~y?`ddo@QqemzT1HC;oCRv zYa#_g<#%g+&m$uv!POm+1e=sXHe+nybD&16CQ>pp@56An>bFIqI(gs zq@*PDL`Efi7&>r&yQ;V8v1a=EZ`q;BaRk`p{LhIhxJ3HS=5*W)uVs>X(1^+z1avOrvqC%*IeLt>Y{ML(N>9sn&V%+L75x();Z5op6JHazehQc_YdJgTZM99Q0YVC?Vjv-j!M z*uS+y0AYI**47e)Y=^LKIyRSJNyY$7&b`!aZR8$OAgApFXG&?n=2TU+bk7HkB9umh z*|qY?NuZnO0q?Xc-|l6~yaPiQJKG7tB_w2o;bNkO*ab*P1c4{AOgs0p7gr}%l-v6M zu*mcqqczuJG$il*mMn;mm*A5+U_S3@APS`>q(_QB+hRw!duvRb>uG64EG?M=F1UfH z!7=HM>(tQF4+CtEj+(lqWIE5KJBB1A1Py0lB{QI!Z1y*x)Fyyk5A>+W4@m?epi<);2a2V-@VW)wWl;jBMHX zwxJ;$;JR%&@`;W^B8Qd4k_oA)=m2YgBZ$)`Oc;nUGNJ-s>gn&7$`tie1u<>A=@k2E zzOvhgw;s%#XUAFY@bfp*Z1&1D64PkT7o;PpT`oxc@ASip?_^swC3f^v3XI8Z}c z1J_IHv4K}-`kxeT(u^g5TOq+vaVTwTM1Z@)9D!jGu3%D$P8&V*J3Xj6N6gO79+XY% zDJx@hb93)Rh@ByU_5dy|17?=p=o_AumDLfLcc+s-Rt<+gd?1w#@%$K4UJOV!`W_$d zTdoYgjqdAH@IC&SQf*i7zS(yCdnMuZ>sv7G2G8>1>B6V^3qa9@$z)sAP*OzZW~T}e z^v8_>LMv#ox76#oRks2q*a0(Hd{U&Y_*U>PK*et0KmduW`TDWY(Jd41SSqs-w%hX6 zJY%w`3D_Uil2cKU1ro#{;M|R#i3!1&VXF|uLxGso5Cqhp%VSILqhT}U>({T3=0b2_ zFu}Lj$Y|Ko*48YaDk_j*pd3LH#R4ej=jUO8v1AX8kN1A|3=D)(qwoCwE#>Vk zs9CIY^R?pg4r%>^S0y6}*Hkpsan-eL9-v7l;M;)Et3pf1x;6Hlb~Q6&)^%X)3O;_6 zc5~yEl#~=y2W^cf7r+Oy%#w>f`~CYHP`2Kt4ari^kB*xg|NLaXJ?u7-Ey7~pO&H)s z=>jfY)d6E4pB)`7#_J|I?Jhj>1zm-bR$$@;&VH!`v;iC4`rl1zNRj;*p>bV50h2=T z4jK+66q~spJb0p^F}fxI5bfqy{uFU7RyH;i*ngFH)*d7gbMo@u=j7xJECM&183F@_ zivlH4kIsG%J$d>x1kCji_R!{dDb?~oTEtr+j~lS2(=DNRxS8y_-1Q2JB7d#zd|McQ zz=g18iC*N_uc{4~7pG7;!M3p5cHKN!`j%@a0f#dl$bmEIs4xiYBy!b^F3yhai!y=u z{yLGJ6*+3%3G}Z0X=N$lrg3|ziymq)Von*fBnU(iTFnTbUZ zFS-hzWP?EcaN;08KVK?K^<6fH%!Sc$!)_50lB3n^_!q95Rs2q8{E|{qPo6!Cgc1ATwFg@bu*#ut93 z7oVjf7ZuwfTd^po^ky+UJ;{7kOQ0u+GI8{q5b8&xWQ+;9_N13&W)>JT|Mpv2I0(T zRn>N?@>cv{T11lq!wqC)r==b|n7EqSOMT%aztaU@t9x4wzm=tBWF$FK7Q=`P#48oT zb_p2gMglIQ|Ga(xbv%(tWva8}o_X`d39G11!FexUJG|$wO;5r4GV|Z>2dFm_;NQ ziw0(2e?OO9pDC0GIZtMF;ufRoPhk&H&X-LS_^vj#Dh4;n{Cwq^-T34apx>b%9V(DGHvx8nAiQ8YPlge%mB$#ib z*8|`gsvm}1K>zspiHBM4%IN#Bn}10Sg7?Vj>Sz0}n>{fwh)cWVCkzS-I-+I0-P+pf zZuh%%NVGHWV=TYN78~GsP?<=pnwjv|555oA7>enNTvWKA8TcKW0n!#KD?OL3BHF5z z*3|K1`*03;F**i@q_3|q)W@ZyB*M+p*|zUxsRLhMSy6O-jLe>}0KOC8aPd%KgaH?6 z6;Vo+H{(v0m!I1@G&Hp3jWkgeTe1DfqObOo9eHD>#s^|VbDE)pjTujsgN>V;dbm)@ zVc%y#m&UlYzID6$l1+UF+1cpEP4D{kig83qjgY9%^#rqS^Zxs#SjlW@YZhlSH~I)M zd$Fw3h6L+#^>7f ze-Ff(0JaKf`MUv=>zZHxYa1-kVD8ui*lLA$%FD}Ru>ZZR??rupm?m(?v~GSy{sMIt zVc|nOnHPU|X9$K$vB3ZLX-zpg;@g4MYjKVDBm#whssPHz9CE~v^G4zQ zy_8m{x3EwZi~Q>{*S`&h($eGWlrrUgyRzpCHiiST4Pm> z>u%~=1`elgcH7=UCk7jK;|Pk(#vksDGy9W^jmd|aKXknue*Vv2#!4q64EL|e`Jox_rP)h>@6aWGM2mqs~6-%3{tigY$0RU6P z0RT7v003iUX>4z8Wprh7FJy0HFLQ5oa${vLV{dMBa%p09bZ>GmV`XV zW6$MV-#O!)fA6sob*!i79aqd}LWrD<1Ud>K3IqZ{fBQ!CJp=-;4}rjyAR&M)lD31l z;6DUiNeNNN1N2W?Q%*G4f^7Xp)eZtd#fJWcfg~j1gN=yxZ>7Z$7m+crP^tDU{Y@Yc za>!dzVMXWJ-FYuX1)~h+Tjpxt7v9zQwar2XUzFc%ysnxMer5LE>0Q#OlA9bsvfZIF z-$mg^-pLDM>yVvDhvck14Znhsi|KDiJ#L$d9$6=|l5m_lFEp3x&I&S>3znU25Lph2aI>MZO!C3_j8*MA3i0*ne-7 zp#=Z?m5l(W`s|;t4BB>~*nf8!hq8Qn@$bHbXK4B%|DD!**Ov0iX`k4fQ*9dFVx}D4 z#KeR`tAkCIs$c&bL$pD;RP2xcA0J+34RnR!t^UqQ?N&q~>~(Z-NUx}Px$C>@$jeSB z-8*IP=$KJZ5cdD?^nX6&6b&#pU&8L~?Om>fF_)Uplw)dK-UmF=wLxeI% zg-WI>-v7D$yFY2qP|d8W!mX;RVo4l?8Sd)pN>59J1Ox=Uk&%hKtj{eek+85}EL1jY zwR3GEg@=cyp`j5{S6A<~EmYnKN2Z)AQbUB$FfnykTg*{4y2tegI4!s!Qbi*>Ht;W9 z?e3c6M~LI#;0)B?E$_}$e49BB(fOVp3`&l3;~uiGvkE_Vp<3r}b&sHug` z&VDqXt40S8gQbRdb8+wiT^GJ!0;OOg6zpldJ?_uBgKp)=6-T?^J&7g z>;CR$*|yHNIU5Y9sHlkLo0Rj_dYlAW#h-fa_WcvFL1V`Tk|0d7SQ!2H@1LNcqNY#n zd`?bAZ$45I4l#O#FVzbv`bneg%p z3PxvUkQ?SB?`|$u2e}r}knrf~=|?9g0}BfaxyvwVJEnboVb?Y`u74)ZTlUOU7>&-& zg-uQ>6AQTGCSh;Sj)nj?Ha3=h+C<0 z)|Tx{bToL#2#dMu<&kuet=(P!8T0NCZ0b_G&7t5t)aV~L-jCBX%S|6j6-3T{n}RAP~X`!%i0E;IJ?eRaJt% z{(cx|5e@@p3D!;@@k}4hk|0p39v=L^ENk3Ltf@L+8&|(nS5^HmfYCnNo)D(~aqMLU z0i`M+Tp*JpVrgkPa-rZk^cmE9zh?RU4hstl1lr%9(yL^0P-&(tYch+97`2~(oD`P2 zM$PUy#t#~%UJv&55sr)M>dyPP@n?2WY)fa3hF{LEt?561@glvZhHGsHq~xbqv@6p^ni{RXI%e_#Se|js$A*SVGsA5V?0q#+@L-$7QMWrZZJTd z$$v*d(jOlill%A)C9KOgJ)L3_+RM^m+1XSC&jYt7a;bQEiFlG_Ff^8I>-4Sl*}lnX zXfXC@dEA{%!BM&97Z;1$*sy{ERqDs&_%RI%2vk535AE0ECa3*hAyZmj8V%Mb) zu{+J4cdn@ylg8||w(BU6w6ZcR%NioUkvc&M-ZgP~&Z#9W_k@HI2vPj!_|PU!ObiPm zbw%=aDx5HzDuy{kND$A&nwgmy**UxH*Sd$TnM1Fci@+4TWg)M1tW%$E@oG`mRF!~? z0Pq+Zl5syBl@Lgke-sK%5#XnpXrCT+Hw2&yPIxRLA_9eL04AjFhi&pP6!B72ii(P@ zdyXQRqvV2uWOa3Qw!U?0HI{AWoc+V;&jnKF_QXX*{D$qWuCAPqe^4JS2a&Bz7O4r$ zwJ+|Jv_yhKg>%Mr`ePXdZk~F3m+4DWVPlX95SI=CE|{O62f;KpHwV!;`8M+UN)_e+ zzX4oHAQgZCZc|eeOjEs<=am6LH(eZddWExW=IE>JJt$4FV?AY1@&5VqC#{zjhAMQ+ z%P-|d$uc=aXUAY*Y>=JZU9_zbYS-H<*<(c&6&h;C{GuW;9i4PpeD}*kow{96EKw0e zTnL31=^{beRUhS*l-6HT<&nE~T{9op*2yU;!B@~5fp9_Pn|ndAk(!rl;B)_tKZnvGE1Ey*dUL`=T`u2u==a!_R5X& zWpX;&{1831>p`(wwrp>2duyvg@vA?q{vD|LAJNn>&OLWZJ1*umbL%^PXG`Z^O*9Hc z_n~27N8_pYI3SMB01?(5Pqm6GD}Ne!K#BGO1`yRm!H0f>BIN?}7E=q+N>)%d6-L8> z{KUwA&}ZqpCN$Ek(#n|iD=RDBEG$e+7=U+d8%M!meVbo}6?AlTghn1Y`)Ol+{WfSg zq1NQbNQQ^EX?Ig&J0PP2*a1qP9^E2fAb?AA3kyZxzD0ib?w$2YXGq!s{}UT}kN5B2 zkCZABAka;XuiO6kQHp|sq8PVWYmr{$vlA zJ=0BYT&8AbaDkR`J%bz@Ug6qO;taNMuhJxynmYR5L~QM9IWS|w8*#_Z4N z>CL1BtD(3%=(tNE2_;-v?%%QROGyKt;TM#YTzvcVhTu!UcCs-$p#k$GfaZxMPL=ql zL;4?FTwHpGh5~2I!MC`XS;4ST<=kE_s6r19j}cY@5pLVHVB%TwctC`%g3A6fOZGAnxx|-8CH-G%MFO!y> z9J$}^IholvTW1 zC3^_=@qxKr#`J29WmI$T9!oX<<4KIgLC2gU_lgts(ssPBf-or3AY4YO(fd+m9UmW; zPEsl|kB2b)n$T!CC8kL(=AhtK{h2=Tuv_3W*J(O8Be;t|p*Qc|5jv%jg|d0$HkC>=lzdQB zT!PB5y}cNNP}{CYw)d+qv7zLi#p|@6R#JiqVDAM20>XcC?mL<&NCliF8QI%fevY2k znWO&v=j)>92$dg;0E$w2rhr<9YF;S(z2Zz9)R_Vd(+(7^!NI$SVMbTp{e>nqhnbMs zd!UM6xnGth?MhkrR$5n9SA&a%*D?Zfkylm@1Wc^>;X}u|ZQi~cPqJmFkd~@ZrV@bA z9&05TS1Q<9YquVm&T23s6kc|vz)1k)IkKsNKlERlnb8jzR=8`T<;kn574ZBf`U4|+ zT&fwsv+vx{xSiPK0b7CUp?0G=u+RZsZOK0Tey+tToZoW`)!=bN92l55rVfU@- zZP3JHeoL_%ATdz5si2i4|2$#yLCDF8i;kXN{=EfSpWP}>s;R3d-TI_8Hw)-e@yYHR7_G51Dw)d z2JFV);2jtk;AsI0IiS9JOAnwZsiUBz6oXbGDl67X6c{3RT2!;}es5;ewr*_%_P#$V zjz%*4h>ptTJ@B0L9g-2^tJnJ4CKsdg!CJ@JGD&Gr?Z5Zn00Jox*e@>iyhhUZz$U8*q=ei{upN1 z=K1M}CQh(~fLaj~6(*!nr}5fDxs1fl&ThS#a$y{(&XumP{DZt-2+NT@e`GN2tH8e; zD-o9^FrP_iZ-K+KIp0-HwV^Hoj+_NHD=UjKlFPJauFUPi66fhtKzOJ?FaVm0q0j|z zEhO9Qhlr_ru|IEJr%uDn95ibDwdn(BFVN!jegmIjm&<;N85!m5rn{_kA}77Fc|92* zo+)f(M9ss?YoGyGk(;#OJ+MGfjq@gN)cElBWLTtRs{crGXJ-cs7xx96bn6_i;%OxA z>i9Kcje&u|{% zRa1mG<@U~w!CmBwr9ohTqWyu8scQ+ls{+=<$P3TnU0u?IX%}z{asUE56xNN-4nk6Z z2LFqqRzQ(lo{q~J5dGfU69W&cJ}G!g1%(Jy{J(J9h@J3rQc`$d-#aLyS=Jyn83=H3 zec*VbLr2`LCniBQPF(BT%m_2<&f-r!4!~@*#ph0DJepz152Cxg@asQEy-`VBQ z-}W?&j7mkQSm!Vo-L4#ogFr2UEn+S%+`#W{Z({2hI5=P=abVmEGr=eC zg+|@^c69vJl@&R4b%r1kV6RY+q(m6iJGjif*VTPCS*Y6a5sEPcnE;B~eo;{8e#Jp-5Ht?ECZuM7E`E`Bbg*JotO94Q{D2`O zh`E#>%>iZcMn)#K$wTa_uS^ogY9t{!nbFU%U}F1ab>6JeQ-fgAh81P^s#2b$VGjV4 z1fqCPpGNYW;_&NCbSvUIJe7$rDdaV1+Oe-s6Lx=sns5wg?6b7-!mA|fKTc6Q*F_M|?4{>*A{F!*P3bOYz%?@7{)l;3Fj+ECkjut5yu|1;D2mn5|d z9W`Ft-T&)a7SL&2iL2JuR!DtAgHD+W3p=}i04iSjfAh6884MpQkqSPPq#R$MZ&45t z5ru_^qX8?73h+`{V++7YrfW2CN0FC=|F^TE$ObamX(CU*XJzRet#n}@Q$_I|_xhK- z`ajO@f)9~Z1Bj%~kZ}rQ@Es1#@(T4d>&;XRGQ2Z0c z=kvpK?D&jDk6$}ppyk9Ewgte8Dd5*L@w_vT)CT(c)6 zB&cxzbI>DiABItXxxg}DLAMSLpmUcZ|K{SjO(@nl>9%7!J)Hv5Ix_P3|7#bqZ$KIB zf7{;cl1s9SQ~vL^_jcPqX^DC4k>KFq3d6bm!OigfiMmnH4E~-n@6|FlXK;0MJDN2s zVf~sc0$?O!%(z3vC;gwQF&2b!$o(?eJ&cye z*+gysRU4+Kcad6+ZAqvQHo^Z4Y$H-3N2bl3b2WrIrFASz(yy6GK!B8+n;Xr55FdEaeB19t?(-(BG}`0YnE@$jeJGAu;i2kZZAYV0Us5DipSImO&A~nwyzN^ zy9;l>uY72^#sz0Q2C*l*KMcw*aXDzZ7#SU9-7b$~Q1wM8;`DbP{5_t-Z4dJ|YA^tw z7nqVlI*=;pHDC}dcfR;=w+O8ior8rY;%0JKmQOFPne{QTJOQ`o-Vji=uGQ>Qrl#_;t6KluK0Y%J&RgU<;G zp#T_^Isdx7y#Hft=exro!K9HPW$1t~y)H%E&n7-xZX{Y+Kiq|%8orFA__y8IWuAq5 ztb|Zgtq)CIoor^dw2%!B4nmJrS+2nU58yIvK)30AYc*pRrJ4H^XhYg_E2@8X6J|=r zFae418LSGL@pCBjMGJtC=zG#O z&$f3Ut#98Vb3OVy{%CPuzxtEiZAlzIkhvcU7iu;ULbN#(bvP4y)E)KoDDPJV@8R4o z_G6-AVq>ox4e6+;azeUNc26W0)VMatm1lmnXaZyoG67KGN zpq|eMJDBA3FLn}sAK5P5ibs0w$1 zQdVzvS3UE-oASDwQYqI*1_;;l?*;qU*VmVuZ}vMtd#VsThst31(1?hxW{;av{U1;G z&VDMWRGZIyZ%#$h0}xRPv@=Gx^xxUUNe4&-&#IKp(4q2A;_Cc-803+nN&48r{|S78 z8Wga!%U`Pomi>L^=c2qkE)W%+`Fe*!q`x3s9Ob`z3~Gdggh1m+@9Pd)i!ev~ ze{S~dxCa~$dl^(ND{%Gvzs)GEV6!ic$P9I=`xl+RQG1kl3S^PF<<@qfpIM_G2MC_R zUL-rg0`g;YG_+R3ih#RoC>;Xp!C)6|U^!cfOy+TlmEydDJZ;W7xykzr{|h?9-=Q!*S70`f{q zxaT|In)15Lp`QPV+ZMcD~{ z8=LAz;VbdeUxdUHJA#*$WL)C8)HgYIfX#>E*|>^T!oP}*np;6XmYs`>iZ1Js^HNva zvS&Qa4!k>Vi|@L$JNQ7Mby7qh`sdo&mNsZ}+)-H26H@d#eFHMDrD~cd(!Bg#uQ$}t zp)ZTG2YlMBAfgq2;xGl`fEB>lw|eBf;re3tSDnIr@|pT^Zmfd`x4-OS6TJ4u0@YQB z2c*UQ0Cj&4r)-k&sgB3fp79k{Ut>pN%HqniWsQCdOZ-q3K@U@8Qt3zoH_8OPy@=qS z8uj+bam-qzC-~(+^Eq#&2feb_^4G!q56s?vijNQe`W1(rgQE?oeZCgUc^(GUa?$$- zJS}&h`g)$!DZbMY5s>^2APx_hs1wnap3-BiC@j(OzLPTzcee(j`5GVilg+Z%!P5)DZz#Y8 z3#S0==yn967nUORP;&i`V%5Q%L2}yv#qB=k0_Rr~#NstG9*-B-`HtclDP?f>TLXg^ z*T1y%M()scQ!a^=k+9~V^FM>apy|||oVe;63L%X(RgbZb@P*ku0A8sei<(cY$5ml(aFEqtQHyx z4xz-CFtP7;sKX$m>K`61s*La_BoP_=THZIL?)WB)s=k$LDt`hf?b`#xK+?5?SN3Nu zL)L&MB>QoR5&1tH%Z|!GeBblu^7964pCYW)YAm~``D?7pvM^6pqJcK<)a!g?%VTcM zdwu4(|m8uCaki0-*OLkp1N@$R^p$Yr=k#Jv}dZn2t zA^2JyJx8l;kZ4b*$zpC zktRH(&}H9fB%7!j zScOVNKTD(D_3W@&BSp*Tfm>;oH7i5Ecvu1gf>MmL8+kkeDX8ui<}ucr&1X!lx@_d3b*vVqTN}wpVsD4E_N+W%st`xGm=c`NScx!Qcec~BzP)Y+hLUSxv|3MG-;plQ9qEM`;jI4X*oM* zBF+|fN126XoeK7w(^G1c7n+F~vu28D4y#+`+Qw;QGC}BZ^iFNH1-kEDzcpWtDd_P` zLBV4U(09eco0fB45>9nj3p~pOljsGJH(_S;hBfX%@(E!BC8Q6MTRB@_KWMA|j*9@Z;6q7z^i<`fVSuPIH% zF9AdRFDp2ms|qDr3Q3vs@sv!+PLIHY)S2&*T}oAFYN@8xr-nI_pVD{d;q;&!CB#oV zyO>ow4~`s`i-fYKizU8SlZiO{*o4;6c@z1Q-gIQozvvDwb={YdK9b`uGR0djy!@_! zpL2}$g?P00&w&H@JNLfTq;i3xscnyQAKJv;z#b$e#*Pj%(VlL~hq^%cuEa=d#62542M3_V)Hf?Uyt08RF#B}2VwivU6dn&>{l3>qs-K!a?YFPHCThux6`a|=i*;#pV zV7(*$Z(fnoy;i8)Xk+=5#ogm|ZrnO&R(&*3AfT1xFD?xmTSEWsQ^;dtuG#fVyF^Uo z8}-NZWHp)v68$k;N>g2zuf;|}$OwlT^Xt_?B8R`;p`aUSibZ7+aErN7x$6d*+#EYK z5P8)22<*>R^v!BW95OSn>lvqcsf*wR|9JP4>fVI!4&}5UoTXWA`2_xLC0yH>9HrY$ zh}vbB*?Tl@TYT7uGD;GSr&saD3a0%5c7-OSmN}-_4IoCwd?%(Oq#=W$oJ`H$bWt4l zJ@^JUAKVyzT}X4Rwbm9q({7+$ya~|q!m)3sd2rZZ)!kMpNm#2J`P9O_3!xBB3>`!) zfb*17tPbgZS%Q!pY<6``qSADgg^bGZy2|Uw^D1;9=$-+c1KcQo+d(*=0?{nx=G!m9 zyE%o`-yhZ%`_ctpS0!$oNWk?enQ`$hIAdDvc}*HM0T^4e5@g}i?<`JB z;XZ}PD%5ynA z<4+OhWg4|k0Ao+r=-O_~bA^%4M$7@^Z@k zpk#yUl-G5{{hsEUgr8+UKmOFgg71V5JfA4$MQK<_L=XV7M3CFA%}A~V)Y?)G68bp2 z%A;8vvEfR`UyY-Y2_18fu@hU9eGL8arC}%cd3^h08rDYOGn1`{M-7Armo1JZM*-=v z4OD7!EN?_Of(S2dnf5H+-_{(5#W zlYZBAP(?8y$JU$csUkpFHRpmvw!YNzfw`;k)0f^3%9cb48Fm>NPMgL?j+m3tb1nS& z$&zZtjUl9xFQI__YfioBF07j3T>i+@>*iz;AyA@2Zzc4c#@9q5PV9W4gu4+Py8Rg_ zl&{O01zbTpmSyi~_7*Kys%S?_*z;qF^5^3t;RE?I7Gl&s8*%ZsoQQyslsZ5R<_zaE}Iv=#!6vXsr)9mBOr)2(|_5H}J)NHj0O2`bc zjFIWXK8h8+t_K5|4H~O^A ziNv?;nhbQ2n9?%`H)se5OoBZS2XaQ?1n=dEWL zDPm{^J?zc|E7*LTeM@|hD!Bb}A+>x;#PFVKP0*>eMj}m@?P)&WJvSW)O7I@6&>LtT(V&Wo7#p|2oe%2!NJJa>Jm=>_dShO_(62mh_zIYDkiau6k ziI>aM>wOx>9#ec5FH`r*>y0rBKS(=+gRSB{-CInTUPKz1?%eH{c^F&OvbY!Inaoms zOu~qXiP^IAiV(iw3U*ns$~GXm4eG~d#koL`6*v4#ZQ`N=N$2DyDKX=SPh#2B70sPliY8oJGj*~ zAyv*MRF>E19B{3hL5(eLnH1Wo^80a&4ms;b>`8X>JslSB_xR{$&$Ie8*mj+G%!S?R z^ED*G9A9lYW-JfT!%P*Y&xSo*4H}x9BWrY(4}T>=HGW8+^|iewLs>#Eu#Ylbx-pec#s!xmnHJ@Z)VHkG5O9_T2C5lDB2yIoH85wL#?cw zI!?~!gKxui(WtAu$flCp6Pfv6xDj>IyJ7@~vFQ}`?I~v9Y28{!m2V_)QQe(%nkkg( z92|Lv)#C0r^`2Q@YZP*&dWmR~UnAD7WTz#wz+AZ-(u&n zDZ^P=Df`dfJGZ@J%6y8FW4@p7o#=L}i^U1LfvCxx?RV-t@q-n0x0u{zMMa*Q_ZJu=yBn~gYDC(V5OsfTO5POHeNh{Efo zJw2+vm2(2Y9;3Rhpkg&TfSY@-`*XN_7_EE?iE73N)^3Ss=QB7Wk=ripKyu)ASP1W3 zD;(ZGwqsc0`8b2o6=nTea^7SHV`5e^oT_cpW}VypyXJl1?cf{MHD|YK`bZ}~%bZ(Q z@tSg>v)ixvudJ@Lc!OCh&kDj}=Gt$P(_sO=Vze;x3O~k@H{PX?tVnsNwQK|OMNedg zHMOTRAjZ=FEuu2s-shG|dav|UwCk8QD>CVk?2N_H)p57>-=#lLf8p*(zV-~1>3U8t z`f?q0OC^v=&Qtikrz#qf!DLJ?X~twh_FIdFbebrRwm=C0n7W7D)Rn&xt`gAQqM|P0 z-7pEN#9 z)slqnUw-4RgKHIJ2ztGX;pc&<$G?iS3_8>1T$mMAP0(ijEV{0r7>~c~NX3_8m9fnw zy#Rr6_HxF5zEgFbCg_}7ow!U^0awr%4_llYYu=ORitJZ&nA*nw+Z3hf8}6rpVk1RkcY?Ceo8%=!V_%lGUp>*2DNIm zyu7^Nh=}!W@{G4#Lb1Yl?EdjMWzSaPn`-&+q5^5I zw4Sl>lygkQRLrVIl~}`;l*cb?5a;47VmDY3%eky>-^SwQZ#I-0C9R6{0!1d!<0H3| zm?j-SA?WaPk1FZJ0tlczbUfevhqg({mOdJIEw+ z7WB=GxHtkA8kRI6LOJ_Rz_v7=IhFAPvni#AO9HKy?N5RJH#IDDA=;tF*{TgYNcZbm z?gw!N30$wwt6^C3?^G%i@5yUE%2dlmqXhQ57Lg`@kX~TU%WQn%z(>*grZY;EIMvk= zYi`gDqfC05n<>e*)5VytgDRMFX{+4dBTlMz^Jm$URO+N<*zS*uVEpFOZo~lOVMO5W z7Ldn_6Z8+%L3w?pN+b#3(n~bi6%c2j!hjaX%6#kX znS}*zfG|Rrz?T?#hLnHChPhIN7pB~y~FTn-O0`0)0XTv#^VR` z(!l9P~hcUdzq=0dxW~C)G27C^VRg7*6$B@LY)9Yfbhc#Xg%#VvX2Oc<~Ao z6_Lgaw?RyDGWDBQ3{6cr^n8lvp|~~DLH$5%d#X+pF?dsWo#b{`5l5x7xU$d%aiz_4 zc;S;)9eMeg6uXF|NJ1wznk&MCY>ILE0||AhZ>wYSd1Th?QF5s7ol9st52;ort#*{K z0elc(xcC+0l>wBgtr&jN#~K{7Hx88EZxwEcRj_gIBHA6DUMq=q`cPatO~>@Wtu#PT zgd{yG-Pck!&B~e;bR8--o{}Tk;oCuv4AdU$iQUu$0JVPDULts`%0x$Js@{VE%I>No z+6K7u8HBD^%`1ddKb^4+q;qw={zgh_tvi8oA9jnxhyb&KkQNP1KSb*dD__6UeQ$b)s7FXr<*-dA|5m`R z=;DGnJAr#3(>?=~|{EaXN!Z+krLwlqUUIYs`Tj z)mLWn<*0?)uOX)H84O(gutR8rFo7nz$`p6&fCsdTJ;_;#et@T&igOc4LqDz3ZhEur z>`9JQBN&A3dHo=lckA=~XZ&Ht1u0|=XAjw|(1o@8=FOh?&+!#jb=hDZMN8&8I!b_N zy}*-0+cJ4-dwp-QG0b=aD6P@=P9N`EjuF2^?a2IS3Byp9-Qq|o=ikKHBlzI_>b=@= zYK1U2pK$JpT5jYcKTB!^#H4b@PU9!;v+WH%=T}nOai+bW_v}aZh;3?PwTFR5elwEY z$C;8Q9g|*~+3$N26#9q7gwNGSe*S!vIN0#OR7-Ywqja&Fj+pI~Od3xX(4yra7|HJG zH=IlgeQyZ;u`o^dqb?JTlEy|pC_kL%(=n_RV~-gL-|wRwUn+(jIe+4F?-_xGJiO(@ zAXiB*u;gD<}@9>?oIpNbmTi6SNu&h(ehK%`0M#%&dCLAQ3Y2YHa>fw$L5p9 zqZnQIp>4rOYof-i*pVD^eHm^h-|c%H=CX!be^_igDu-YA6;rUX3X@JJt4lPbic5Dn6cb zG*D1J&v23G&H2j()|G)Q{MsYt#<6xYUK_?FH>Bn3-m)h79QI`04B_{P6hX!C)rUP~ z^ZqlnyI}-=CSWmadCMq8o$DJK z))%i9zj5v96pm#dEQGzgzP`@(@Bqa8`SWL=EXdQLWsePvMxE^gn0QDM$^C^O&chJh zJqO*rNA@LGGD2p?nyWp{r0kW8XVE2J3~7}6?FD2uFs`Xzq&M8j$yx1g#_)uD0U1r- zL|Trgu4N=7Y;@rE8@GJmrLIK& zrBnLj*K2>TrtkJw^89v&DInSq85t4enROl4oQMBK)c?7z`!8*+zOMREHLi6dlBI9YGI&XB^qc?K#d*qQr|EZ36Wrt4p$V`s+AFNGNu?-sD#ykp9O|@ZVhoT zsej?Fa>Fj9q^}YzD$d+X_w*@Esm+HaB>57rOfT$5!>sA!{MEsNAm%q?RYyIy9eMj@|}q9$}l$A1Od5tI!#z z<7{fMC(X`sxfL0_7=ov=ADzBevh2|Au^ulw{?y|%s(h=pD#-3jxT6$3EP!jyCXkpl zvxz8YP^WtZ2+{naxx)fpu%+tJm5oTHm_*zQV>P+rs9XsHUJC&)MF&;ZwV;P1=>~R% zNrTdp{j@pSgJ0i5dAFaXH_^g{O5hC_)-jR3ZN!TS)@)>V5b)!2zUB8mf!ycx_&vZZ z#ns|fYIdzXD#YxBL}fd7pIN;gCJ2SpV6|o~^W?TSL9V~__$_u29nRL>4B($H@12Bs z-F-;nbz)j_!B7>lyGJzvF8FWH97(hX%*P|-SsXNs)6A3nADgeaAL`&<9^2s`b9ES+ z#HNCO0y+7yS<8@ZmCv`PFH5`qlPvyy1A-R0gY)*Q2wtwd4D5#eG_;+{+%-aOeN8IZ zGqd);q6Kp9@{=Cwh1L$%XYJ!$Te-UJ;A`c^eX9g&LA*B)%GUSBwr4ePS3e%$OT!-5kbM&VIxV4q z&K(>Qfoc43e{&Oh#;a{o>z&9oI|}OeSK|@&3};d#DSN6Q-Q1Vs3c4utK@KZGE`mDN ztszEzk?1Yeu$!2;dH{us{YV7%ve)})RreD%Jvp}>D|9`O8PGZK3AcLI`!odhY^~GC z7(Xn0g^9lSXt+IR@beDUdeIM)a*tQ?Q!FuW&fL@>(H^MJ-IMt7(M-Y=@jsrZ%=;wD zGfVzH&9m-U?BI~#+hWI(H#TQKqA^+XhJxnm)uL$$5ZFeSgsdnFt@JrtF9=vL&`;gq zx^rp18@f{OU`P9_5}LNxdxnD+1{@D?jr^t8c<`R)ulWf<_xrHX=Rz&zkXieVL;TV+ zW2@XYP`!&LRnV4e**rm_>Y7}+h zL2_Pnw)CQwc${gvXaoocch_UumRI>6&CV7moL@;gpf8k8K6Fq%oEAuEx%1vG>K8*Su*tK>@ls^4b1-1xKy|XVQ6g! zIY5E@y>~Mh#{1Z zN&xufh4H_Ugw@3p{qbpnOFJTA)ZuYMtCL5Z;1ky-F>m_zIRR?xlWN4&Q~&!Ur@#k? z;GO2>GPChzbYt$L=~F#&qUCDK`A}I`%Vk|jvW+fkv4KstHLHXX)a2Ve#8S|Y0?oF4 zo0Cia%X7qjO>rui4|A}f{k`8|Rz9*ou?-}<&=Th(-L`|LpL(!!?s44xOrah}{m)te zA2c}Z1mvDz?Hf-P5IHEe96xG`545{c#j z_46W3>;A8wSu0FN9phtf*G8N6wgHPn?lwe>Ep-H4cX+{ z+4Tgh9ZJ{4Vim1tJuIZe`xcDn5(mxICY_{l(6=?7F|68N5%L2Vf>@hl*0U|11~5RL z3Qwt4qT3Wy4adh)#0~vY5@KdmCN*IFrs#I`_1^8q z_+;Q*i|w6=MvK`vI?esni&RIP{qhw)rbwbb2b43HkPSN44YRl&zu}AwYl$oU;KQ>~ z986t2h{;>|H|j{wsc1w7a=Dd)`XEz+jkr2RgUfd}*G8nL+&(R*h?Adfx8Nv#thSBi z(#(W8!Z^*);;tV#^Vu~$f&RqD!;q_`JxQI07RK_pla&i5VU$2E@xhR$p znpmm3#@mrOoIAIvzt@gLd_eTxA;si@oUv--l1d+uuj(9F!UPP!bvN!UAkRyS&x%KVLk9MJ08ra?tFGA+lPc5`*HHBH} z;*oU6@paI6apB?Oof6iW1#O-7eIBu}ut8xLSF z_nVe6zVaL2^?YxFTiQMp9JS*_C7#rN#`@_+Cclc@YXK6{dhO--kq3mjXC5*AMOz%2grvT1D+p&aqcu;0w51#>q7rTq;F!F7~ zEta;3CJw?rETeK-CXw+~h0_yO;TbzHC?!a2IZ9824}<)pHymqA-^%rjU!9;_lkn%i ztld$5s=ZfCnPmLek{08qzjt;-BqR_a2Wyh!>F7d~fjt4}Pue%`Hfg@UVD(Op(8Y6h z8`hpgHFKsF^B6GW^g+G+-NtME2jZA6UpO>4Ik2JIpS((&dtjPZt{Jfyo6R&0ok| zs2|9g%LLKjk}|)`J;-`6J+1#L+(3ehYReiwBV%5 z%+9&+wuSF9bD}};8^m0%Di^xiBV}C2547mf13wm7^(zui_7oRfr+FD1lEMucAuw(b zWatVeQ?gcG0&EB$&cX7U2D_!2*W&;|*Bsh5Bgj5PrPma>l>*gx^5(LS79!Nh3GdAn zT&kKtdHu4*t&n)KfXdSS87ZZ6IP^y%GFTgyk9u2b?!9#wBD8dU4@Tg<^ke=!il*Bt zJfszvJ2q?i^FYe~PMM)&X2t{#lm_AO@=@G;!6h$ah=Vk?NFDRMj>Df*6QC1+medgP ziBE8M?+z?__t5dyRz?4Nel_SST}nzgN!FtpPfR+hlXp_u8snY8@@Su~^D^+x)ot+> zD2VROE7BVpc$ZuvDZn+i)}NM0`*6;C<0d?+{F(e^xJadive1@T<0*6%$iq|#gE!bI zT!Rg~6$G+3Ce>;Dr2V6Sa3acGpYNvUrsTZT0N6ma%z&$KZ2TEn~fA?E+-Qa z$YzLlx{s&JPSwLTdVO+fl@~-JPD~(Mnv0y{#7%h0j58E?)xvjCB12BjXF`19hxl!v z4(${0QvJ7Z1>3sUL!8;yh5xKT8)Tbr+I=C3y*kWa2*>Mf3b~x}>dO3!lCJrNg<=gE zb2&Gbr8D)adv-Q?tR^M`_3Zei6Vw*B=2i64QJ&0KF z*|hh_B{{PncKqm0z$b7d_igL3!wVISO6sM$z?UT%J!9cX8T=zmgZ{srU4*Qfy2nej zudYdYy?_W}mF$2A7HRwBo+Bs}ZgLpVe)r3g{BuY+a+zkus0XG%co%Khr_Y~z#fASF z9eZfK7Yx*Ne)ll?zu5W;s5rKz>%j?5f(0EQxF=|Wdmy+I9D+Lpm%-hF2Zs=XySoGk z?(Xgy-2R^2d*6HaTR&@9ixH;#)T!FFcbz)j&&IwOYLJUs+OYRm-6#7n%7k0@G`GIw zEih~zDauVPGyZw|{HB)N`vu`}6AEC|eHEpV*$E&Lmgb&{&|cxO42l+zOUPauHk+gH zoJI|fg+p5f&gcS(zY*HA?l^V04f=aYV16AY6Kl;u>ej|B_yib*xic0=1mk%Xo$Xt< zkvI1(fHni9XA_z@@RB6k29za_2nu8yLMaXiWMHuVsW~Y!9`584WulawLOd4g5D9^V zXbov+e3VqSv`H`>SLM9H0C_IuitDg48$g&I8HT|fKl9t`~*a( zg!Cfa%TQpjmTz#?S!X30>&!vn+9igK#ySdRqfT|E4}}^LZ3DulR?1whqUl z)E;CM`Ty`sgHJ&2!Nwk>)kPOyJ@h`$G}6Xl@ar~OVLrKRbphfe;FJIZYn=9FBG$lM z(FVOjQd?Kb`+-ngG%$$7&ekHOl%xZYAWX@z?zlZj_J);E!}&jXY`ld8f;%(ZD} zo>^g9Vj$kG>H*mDCFuuJ9T(@fFRyva*|m^eba?6`y+2JI!oo! zqePK#W;yA5f_vF5K5UW}?(f4m_}0%l5AEISbFTa$#1h?4zn_uZhb$R|i424?_bE`i zB{7Y>YBM&&xW!aZ2>k?WV})n5wEKluJA*mbe3x$f)$Bn!{%^*!``tX!)D_zoe00x`J>+i z--QukyajX`BRWSx^MWt}Q#-8*RjtNXeblqZM`EtIo`oDMc0jE96K!P8u{`K#1nMw|Q;(AcQma#b^Af|LzHJovb}8 zJq>#K3Jl2)D>a$!nvZBr4>ni6>L3@|B|m)B99Gue+n3MaG`@O9c)4Vgg0HPw9s%_T z-+bs&6?cqZD)a0vVaXqCC?gw)?jF@S`pGAE)i-sJ1d=MI?Jw7E>_qdgQ~9eC5Co!j zS3UqJr#%2l4Yk*nRn|_x+Wi-2E+U)U;2Y9p0&vYZrg2|p+&d#*sVU=aU zqgjK|z9&axDoCE|n~G#kNB^pdPLPot^GRMD;0hS}M)i)Jb&<&^5nj>!H9AgtEPDto zjKTWID}qMI;YzHfFD9%8|9k%8$0v!uUywt$;*dsxbSbt-ecGtEM`eAnCU4FfJ_)^Xq)xYdGp7(k>of=y0+XsGQVCtvEYO5q)WF^HC^{Y&H%ZlLfaJ>HPceQr2(3 znD0s#e-WN7a$%lC0im3iObKiAnwDes%+9y;`;eS!D!qeJ=!U0}UU3cX=tx+)WbeGOJn1nrtn9k(ev zVeS0O-rKs=RN{^MjE6E$JG8~Y&pHp9)>`(A6K|YqE^bt4}i( zZ9Oj|#0eOzLD8}nr^Z7*y?Uw?88^MoaU<(zcQ*7wzj6ew<(eM8VASBD^50%a*WEv+ z1g9kXe7`kU)*TEg{+XTXw4ii9fHt5}{w#4>ApAD8@Om*S!C)v0`H5C+BCqqyis!~{KE`1mIjT285AwAA^RpvXRrPW-VarF9r9 z*ysY7wH$(t2+mkBlz!=O!Ey!B&&^s7drNRm_I1HLn(Pt!;6=NOBTPkd{h3?bd)#NiT~nedEeIwP(d zcdV{=Fm;5gA8@o%lsG;DG2wFN-4X#zPn|xdgRgMMY1_Sx5H3knn5>XAFe$Y?+SeOV ztmiQ_wimI^@jZ!TlwQV&#{6f%CtwCWHlB425A2*f>Zv%Uo_%#+VgcT4xg*Ov*}MzV z&o8wjN|f+EL4kgJq3$>K9z!YmwJWw=dfGXrkg#f8dS%7Qa za{~qviK1DJA{l|76@r@?qK|vn%sK^Qb*RW~T@*{NNAjTSj;XeulZ!C7^#P8Z4NYGH z7Ea>~WmL&zNeMv%@Vi9T?CriSIM@57j%O;4_nC70pO08(QyxjV-1a{3-ukH_-hT~& zM$if|^b(4qoiZ4gAR!(;osyxV66e;|UldHl@zaJ8^Aj#~Nt0cYKKhbnj*BkS<_HBu zAf+63r=Kcr5mH2`;1m)xZ(_IhT+9$hgwr5QOqDwxd|KbXo)UP- z`}lcYqSfoYhLGnLrJU_Z@E@pvlH>*?^7hE3%7zbgIP6pJR}0H!QAi7k;A{D-hCbl! z_Sdr%(+sT^X;M+pE81$2jb2?X$xxMO)z9Jc=*6?t&P}Tv@tMY7EIWasZ(IBHtEp8X zs+3VMa5LqBK8z941v@VP#5++UzwpJR2jCro%4=xs$~sD_@<@=EQM_!K<3S<8f8p<_ zeE-0JsJS`4xvnQ}4FB~lJDdF^H5e(#o~rm4McP+gEvoF|MTdUBrQY`9^Yut=KX)%W zyX@vPzX@k&gJ>N4H!c^XXhvoWZbs{^U|Qt>mgPGVz}2C?X03HASDqfC43z^>ZZu;5(wxvgksyYUY~+cR@O& zT9CZ<@dRn6tTOY}_tK@B=9qbe-&YGFz6hIVUEsS5Yg7w1+Y6^^&=MlVc}Yl03dQMQ zX4U>3F!NWw!YVF$kF_U2kRL>_9lbot83|TGCb{5`1IAKvJ zO&PsBoR879ZqE%h#z4fr;)3d~Jc8a^?g()>i%i1D_$*>H3h03Qsx+Cbt5Q~$O}G9^ zOBC65p-ia%y(+8tzc#L6cO)SEvt!y&+1i@zfg5tRQKU?8U!(S(VprxaO z0ll*24)y>-p5n~Bh9z=U*bY?U$qh3s@Wcz4mRkZV;>*$2TgNzpXeGShxD8Pw6B7sd z;JQ|9>=-08qmbUlCjyQ?v;_kJ8)_gGgCN{RW6E%2unTNr0T`N1M4R>hv%ySMlwH&p z##9vB=k#>Ml-;`aP4tBw4-XG5Q=$LhLgcf2jT6+c)l4jGDE+B$KGsRne5+@%D>}k8 zKE0)2)->22nJ?qbSDOX0}P!T;CNo; zvuOX_b%^}0a}oY?QI&tH%2@wGh-Goqcx0f!+Y$YKZ*q#_{6%z!i(tRFs(mG%%QkOZMPBv zwM4|n|BnwhZ2L7G1(uF{ZbZ>W&lSvz@Dpaf&rw>zPX;~h#OXiN1H2bZ&-`4o_^aO_ zk1w}G_#KaMmF9?5iLja{UBjMqy-!Rb1bi*`<&vxQhnWcJ7z#}LNk$w3vOHCWiwHWqw@oWJ!D!cpauZC@@Zjvwai;ov^`h) zsH>WxwEWhJS-;ua5rz7jQH1)>w@{0{2YkNn;J`9&YN0)(pZYqW2W@cq47YygN5h0k z?mS#9&*l2;A?J#0%H0LvSaYrSaF`&TKk0_edOP@VzLv6e!B-l0P~^%H;O` zgpwN+yzcm}WKtbuk#~1t&%N)x%=kf4o0Gx{y~!1bq3rU*`}(gb^vmqgcwa& zO@wZ)v}Ic{vH6|>;((J0N(Yao~RBVQjJS|9n_fWn^(=fF~@>xzX^2X1fUx@EDc-GNiz>jk|!C%h}p`TGHiN(Dr7i( z(dEiUdyIeDOvHWlS$ey$sG+K;DR}HlHt&+E#GUk7#6OY{=&~n{gPr z_iJUnUEjNMc0-iMo^)QQ`Ep+>adWd9vjOMFgT&Mh)3$X}s(3ep+g?~n;| zY%sc;ymC3|0Vsz<7l@V&G9&X9*)pB1%?a!{jc0m~g-_1SkGxxz_0abWo@r*sf$vjD z?_DmH*u|W=-c|W<+1(5kXy<}oWbsz-+s4)w1q%zND#+}T#h&}d4q+g{sYr((R~lc^ z=fJ`S4}(6MFU9+XO**5HSOm_VL?Dv>#aaGL9rfg<*Hg`t1Mll6ucVZ@^5bIR4-u$6 zawj}_mdO63No?s}een|n;Tg|4882QI{6>##lTNEpqT8Ss+M`no{2iks z7whOz{Z`ryqxqtX>i8$6@tzVez&NjHVE7KnFld@P=`yL{m3pzqBnl+tG|npBhgPh2 z#l*xz*g)pG9XW@K#!qAo&vnPodw#M;`2x$5WfJPrDl-70HhiFdAtfaxj{wmwUp#a# zM8;nAQE&F3|K1(69)obTE*B`JtjvYJbJzMbY;x)>m(i_zW2h?R|ePxVC2`LIzm zmZ*Apwx6-S`H*2an1E@=`D8)tRSOTYy{s%f1>P_moWd;Mr7>uGc#4;6I%9BZ#@0z5YummA7%YIyHTI)AyLf3)YUUo&$pen&vcp;X#HD5b4x z<+Uc{P5OH@I+@nRJs08=cXl9w#=+3jY!o0~G3ZBGf#mlp|A%$QrUf-H z#VYv}i$+}~mXBLKieZA5nc8bBpDWmHHFDqRdPh}CIR4Z|PsYh8QkRi4C-e^CG)NX`nJU0ZVCW@G-K!EQN(Hl5y`GWD%NtJcwHf>VFKdzQJq*n_NI%vTF$ zerDlF5xvn&hW_zvN{U%=%Wp;`fp@P#DZsk&cNibHpe9|KX&uHRY0^S&(bmkSEKRn(`T7h1GCtKMt$lsUHJFlyThw4`ywhsC<)>wyRrMD;v) z*$E@&57CS~wPa;6r26Ug-_#lkn@>UTMR#xK>Hx-XZjH*n6BqDgWJo2!pFcJxxw7Df{OQ(0?qBY848OF?JWYUp& zS!d0Nik?FKfb3={CHDEnqtOr1TSpF6mPFb80GYfe5I+z0UK%o(h5;_>bg{43yU=fl=Z*cejK_#2^E);ih~HuH-2*D znzR!H^vVG1M@t|J;wr6o+-mQb1IUo{hEl42`8!9xI*{A!?^0hXT%T>ca5)^LP@Z64 zjra2IPc@OzPVP?{IEvDikIF#Z|>Tqb&2;)y{kI#oS0uB zTY1}BD=pND$mD7cF0lz8PQ!lPgWgmMhr!O&h&v;YL6eB*uc?7v?h|sT*$Qf$V%a(8 zH+!$Z{Pe~73w|pha(zaT<@gKD+Pi^d?10Xv@`(pGmFSP)`T60)8;8JKw==$fE;`cv zvV0t+yk4haK|f$d@%YqByO!b3o3RifyBb^A7T$m5QTpbAhQ_T)2RR~;m0Z1n7!REs zoMeLo1JaqjXC?eNhmB3>A{TWYW`gIwxj+0r1%L(Ozck&SAF@#^&Ib4*1BsL|rw$%} z5{&F>J3$jR$CL;^H?3{kDL`9v_=k*LT!N-q6g#<=dU9zbmM5>0Q>=o~P|t3sOaG|+ z_9)umrXXBF5|H#~4hj*GtkJs15(7X?=`j6A!*Hs;q5w!j&aZ#V6~Vw5tr+@%QpJ_I zMJ*)9Igj%T&S{Y<-6M_xbYx#$_3-C2w_@gqTIKx@gIB3TEPjs$Jdp$?ITsUn7|7TW zb($a>xVCr4U@9tvcTNYk57j@(DJX2V1n6KC>|#dDC;t}8q5crPYdI+h^{$txfe1HP zMDUNU@inc^+;`fHR;`mogI&w{mh|Qo!AMu#RRHEQ#5E-OBm!KRA1aVvuR>$j8;_1mYd^b;#-nuNbP{G zx~F)t!u1}mwT!?TqSL!z*|~dfPt4~)vW;S)WgUi$?$1n_><0kFb3nu-rlm!UeSODm zHw)it`xqnir}i-ZzqN-^?&akT^JyT{1OA6JsrK2v4!K$iMNPyP;hQmd`=(VQ2*r3@b22A3 z><+BK-K&pKVpZ4z55OVfgqxlLRx}}t@C!=87nBdWD6bG&+WC4X>(jgQW{|69L53uH zMK2T-4|#qZ&YlSZQ}y%>{(4y;1-Hsj@KZ5D-g$rdld{i8Y2T`Ew3Zt2h}z;6a*S(Y zqAgK>Yy45xm_pV@La93|AyytObB^c&81_+ncbLG^E2)x#v^Rrn>D_NLziHmq)=708 zQeWBOrR`|g8jwG?huV(Xc_&_2!(N;@`k(rco}t3h9^ z0s6t!F9bOqt_$!WoH!1>(VF!UrVqZ%lrI_HeDP?J5&Hj^lXjRxR8imdF-ykBl6FZ* z=k*OIBbpizw77*u>-F3rBC}4x)QcTWRsy(2@(F)L!3hR9T8IBe(8~b~zh&$Gjsz7m zZu7dx9Fvlq@?4VJu+0%&MhPR+Xq+MD4;_7I%UZqtMz6EJeS-(JeYK=mZUc_n^!5KN z0m6{~fu3)T^%x{nh#PST6jVIW+gR{FxxFiV++z!lXV8CR@=P}GXDruv7ihMh_`$>> zOmsv0vo`UElCLBodQMG;HlXNq;)vfHruS>fKe-L+5FdWp1Ar7%|1*#>a36RfvMb4U z2akH)y}!!ROiVKB)u5XU^52~^&@0HB5@<av$ zhGJ)8Ses+ z%4eA$MHU^8N(j(ryT24%%x4_|Uml7`2<|5Sr*H)~GASP#`Q?o@p8-A}^3Lme+G&@# zo6O%Tmhfkf)SkcIMr7oi?^D1Jc@RG;&=D8uM-vowOsVY7G|-bEe7fMa-9!0(^U2iG zOhQNl4yBKoHJU100UJ$_G88#HDo8xXt})H0D60S0FCjAxD$6aW50Znvx&*_?6n||0 z>0iWj8-nFJ`Z%RvZd(}o8NQtO_*Awqro}N?aOfpA0@uN+M;`j2nyjAiStoMR*Izz_ z;=8{_uMcY&lTye6`CHK>(5LNMcBqj8gT=)dA?Uu4q-qN`yIaRU%Y)oGqsWFo(LrNo zOrn1fEvgBOgzY-~NbRIKYIo=ffF=F(PYF1SCs~x0;M9DTHcU0tx_eyPYdBgy<9B_` znT?a-ZOKs%(SaI9>e15Da1`0)!GD8+0*hN-Lr7v4A(7Q--B7Vr zKHCTR86qbiwaQ@nP;3dHulytRaH(Gj48Sy?##iGtU3Vkwuq0f$Wl&YFmpLqYFea1q zz))th^+$>Pb-~3ADIlL|#1!6V=rb-dX@6JNVA?P06$3~$l5sRj-(I=t{3(B@I*40M z-LJH;@X!!$os+GfeFmmeX?MxRIlwfKK`u_qFH;$cR#&h`le+$n{U1R9O7(3X ze1b*tKbk!YBA!=J6QS#pW&ZJ29_crN6hTU*1487n8*xLxFJ?Z2#DU1pk_%MZ!DwCs zl8(+>V)TWs2cr^UKq!5L@){PWx6>KP$svdHwd?Mnv3ee?8~A^MVrXul@8=0t%({>W zHF>w0`=0qW1Wg`ra8SNVyWlq(2?mvl_|GyrPq&li995c3&tXJu9l&QOsvs3mOF>EC zsHtNkA4Eh{bcyjlOedk_PpFS>;FJ2b)$f-XM-tN6#WvkmJ0_DL$yV3iERBuSZ&vYr zuKl_?{9q+N7Mp|Qp^bdI5@s90v$gE8%zDk8cb&@^X! znSRx@#gmd^1?MKSp8RJGf=Z-t(w>qA+Tg$~5$+4Xf)1}EOw{4qe2-?AoesVX3Qc*{ z;~J?;RHWgk8P3J!M~=AltC^BmTH3;^TPq=CWN1n>{qkKXXVm4vB1S{AK4W}@RRi=f z=-dgf_u-IvYrvmA?;T1Q9eSOUe)d zgf{f5mT{;=2Tmab?$($8`22t$P7Q~7K3B3f@KeUa$nMQJaatPp%Dulgp|5d4%*Pkdon;j4+o<4poGvt^K zB^dzx_dY)2!4GL8wVou|y~EftCW=h2kIYMuN%V>#Dv8?No?nJB5z^qpv+6$$@sj+j z^CI}v=Ta%$tyzHUEYRl}!z*l$!~t8?w>b#*L6-b&CWE5Aq5csD~u z%&jtVOx$8UdB?1bp- z@5fgJ=-M|Y3Qxr|bidzI=qAVb1Bo+gCO=r@7r+IfrU&viYwb)l){CKt)W23{SH%Fw z&R+Yn3jA-OE`aWQ7(1n4a%y6-1D%L2^=Z;(Y2zMplkIg7gwMOKi>oDQv4_7i+p0%F z!9ssCA@RV58nx`Iu2(+cNUBg}&TGz+*XqjJYBZO@d%DSX2iDlqtN)OH)_tine9(s6 zefX|#S*X;~E6HyAEyFb${pR;{L>pKj@npnvt2-HOm98s6V1`Evv?jV|D4c zHekFm(~lU!sw8c37eOa$S*TJh-RXQw0MfcRWxyy+kqP$}z$KO6Fdgt;CeItT*q-o0 z85e+^M#rw0HYELNlh;yKDC6FKe)% z3oSx9D{c7!-zf=S$9=yjbF^0EdtF92@rts1xl@t~@ z3TOLm!^iHo(>KhBZO<{JkG*wmk$b0ArZnZ{r!rGRo5(E?p$LE^i>tR^;8=S{#-`O- zc{c=|(Z(t1jO_yf6-Z9tKHvpfZcVsxlZHP_1cdy5q+%$^PeB%Ym{+A-{S--FAyFkv zIW>8HC#Z~_n5p*Sr?*J4{XOtGm8B`9X?lu+O*Np40M}S9LKr~H=LQ|+E>k$7b3~&w z-Tsuv)zyBQ+Hp`Zj9z^%rUcqng0wp0#wA|4S)63-rr_m5&s zsIf>FTIq`>ZP=ZkH%~V_&pcLT?)A4(7?TfOB3X!equ_2CfW%lkJD_}*WM}Qzf6QB3(p$l-8eD;(3&TTb^mVb9_@^HZkWc(<;Jy+>Vxn8NynDn4MQ^=} zr(L6C-kO9qh@4-}yQA^Nb7p_|*xsKtqte#@*}XEkPp>=E{GqG+M*;@UMbYVEitA-AK!zTF zB>+3%0emZS5V2|&zR8VPon6WQC8T;n!Ww*_6wh~$v)F=(&lpos{ox(%D2LA% zPg_BWt@c{@aDp_*E7ap$HH_eltIK4AS6%*%#PCo41T8sdQ=Caq6zlsTE_#x+2tn$MG;ElcPZaku8Mha-Y?X_5tkwyb_07$VA zF0rTLSY!(?MbYye)*1gRwZ=YFw09Xvet*#uLNdITF8{ywV$dKyM(F>e;;HHz7Q^*VMDGTNmAJ zDujJ}V8YHjuUo;fnb4r-iI0g+%1mjc3Df;6Lz9?1M0t{iJI$I_lW5dy z6aJop0}w{v=M6L#2S4x7vVrp$vFLt<^bQSO=3D8!fVt^6GM0CrIlj>0a&0nDN?59qy2_Es`r>5vzv4?RIFnPixEDV6w`+HE)4Db5$o z>sh(&@~DWJeiMX3ETLsH-uS)kmP5Ltj2Sd~qkbzv^6UQP7_1&gH-33I3SBwA5M+$; zOh7AUsAyQU@7~)(N4nNx8C5&%vV|N;NUR^G#j(CSp;!O*yUBG0xy3D{gAiJ>+h70^ zf^BY7)-ooe&f8ZP+RZn2gP?EV+FDG3jW$Qtjk1ej_o?6R%Rm+yTK}%dw*R4|X|Fg` z>XE0J&)N0qsv5<4dr$qTt{$QbddpxRzuzz@KEwYG?di@~9}t%7=42yXpm$TxXgOhT z7BX_s{Xmp4eQf z_qhB+`Vsbkl4&<=lr;d*-|KY1z&iNvUSL?z!D1u+_XLa?&9~UUBQA9A-q!4ll>_`5 zBeh|zT<$ff37|s*Oq{&cmJNy;^lDR=TCAASw>)rT6d&Q@6L12~#kdyndf_169)pmA zTk8950go2|TB-B8qd+O~xfq9a`>w#l9@-K6yzOEONL>ziHy9bcDg`zt8F#ofJ~7N5c10--Qfz%gE=s)+PHcr`PJA0wcC^|FI3x>VdFOikASQ!}*zYY51$00#K#Q3X zOovc?SN~w0*%*rm9u#3kmBd}MAKu^@|Hcwnxzw*t)0|N+Mp3ZOH*A7tfb>7>QH!41 zFo+c`EpJ{%u&OSAz-d#j(}~MUQ%m}HnpqYCi*|uIh^!sPF%+3X`=k&9u;=wzPsDrq zL_}$ecb6IT@^}a_Vu1)ynt}9N?F3LZkLP5h;zsINz_}IO-Q4{svS`?rN@mzZ=hjvB zn^np|Z2rQ54Q)VYzXTxpx@#ZGCm2%5x&cn62T(74K(?v_M7>KLcL;xS<;UvVNP-ed zCOVW-Zl;xLfOXzIIv_q{Ta}6ignSR|3a0c%R6dX5YePYz1a z0E1S2-j4LuE3MHhmt~$ZH>50ZO0Yk&$-S>%=up zXQGJQP7j~U=Tq`dWrwzL1=;fOs`$r`w%zf(a{J9byK3DZDr2y+8p~MUl;&GOp@mwV zv*}p~;DCxbc)D*9Q3iEfUo?vq2^6$3anyL|AKc#X02#8GE~Mt4UH~(}Ek>BH1cA>D zWA3w70r*+_DS}VXi{YnyH(d*g16`vDYDe8EPon|?cKDoFAeiuhr?d+hhseFuH$FF* zVhjN$e~iTyV+G3qEX_~H_D5CnWr}g~&os|%{!RpF9r5x7Hz4GIz!8SF>BQ!g1AcC; zALg;_Tj91@6FdUmIZzQEa(g#O%|zF??$GRXVs^L7S)-%dBPhH0r?lJo>93+F%)`&u zxl!h#rt%r_B}5g*f{8I`o?b5t4t%~l{502{Z^^ULtYv*UZTz#IS4UGZt_SV}&=Fc5 zO!J#9>6*;Y%C7qBcNl7YL~)mtXBTp_4BK~e85x?KBw;2$>pg625FM6Br>r;|s%uU& z;y_QX%kjRm`(%QaZ=|mdj{DqB~|6D6pv}VGH&b zkM}+LSimX?W*okXV*O$cfswx`5U{%&d;+k??#QcC^^o`ZHZV&W_P^Selm(J$VaDps z6dJ>@3!|7Yh+^lG`Zl&~)lay1VR2}Me?CK!9XkfcO80wRUC|*c&ZL_@aV3!-l<9+| zTVB?572IlF)Ni*Z7gbF8ns|Rk{OD*l!t}w(HM~!=M<_k7XXlvx>ymX88tU0KlCY7w zeCs5qA5U@YAJvAx*s&p`0tS%oVt#sfyk>dY>-7k~4_vd2O{p39?p$vxseQqjotx!g z(klP(!s{{iIb=5~3!ol#%9CF|P(yDU@77FeF0tzB^;rCXXqA z8^S5zh)PvTq%}0ErojnymC`V_v5_zkD_NU|5Cm6|`{T3B3W?#_r7fQNX(#1xkZaT3 zr_^=Cyl;f898#?&8<=Ut4m!sU>Sz#ng)Zg#=LzEQa2na9NMZoxgVrxa{iTq6w~UFF z_#H?jhP95bejESYPVS-N>~IJ3ZVk=jW?8Ix(>m z4%U%PN9(zMvhQgxb3m{%lUYXkWq-Ysf0eJL!SF;}KlcHH15&PL#t?+w_bJ8mLjm#C zZsV}U@;V0_a&VM=F@&V|D&~q6DszbU1)A~_RCWq=o|(`aw!FZ#Rz z1W}hOdHE7r)!B#nVdD|=c-YBye=HF*`??>gXN(!JB)ILDa1SkH)Gw%IQ-h#>Ui&N=gcMdxgQjeGVB36j^tOF;s;$35w7aB`x-I zzf2|bwqDc{kgag1fNari`QA4N4WoQ4K5_Z(_W?s4iT~+>tf7xRJ6I1??hCmCtF(%9 zN3caOp&5nTB5Tjwr~Mgz6alP{lRMZw&%Dj2=mUoFn>TN=ruSnK6Y~}l5)*@8`ZkuwM{v%m*G!NlqoZ$3quX8rc$y21e{R zWry||Ny^Clgx-~_cHaA{aXG8H8uy*k0l}%~g_J8Cv>$ci3J@x50DHUZCeBn9DOT-F zd>2Ct!?f}oJSAN4qu9U7Hc10Vfd;t@{p>WYP+G$Iv7xs9JymEh1gA!}LakZcw|!sT zDBw4_Uv2|oOjee)2?F%4Tcvp1&LmrM=py3J3tvDtIgFN_V8V~Uf_AKrnsxr&U*L*{ z!)Y}KpC%iWno5j=gF{;jy)V_-X1{ui2Tuai$8J3*tPQ23?GFwDGd9(*;_kT##B);9 zVSSr5PFcg|B{6t^R_0-PRV*VzYeFtL55Jmj@70{X6#QM=ik?8+T~l2RjJ$gKZgOH` zC9(B>GdQRs9Z%*k%v%3-x+Z5@^Mj{g(Zh1Oe(}O3kO?$3a%tbzSg@eb`hmJ;G8(lu zQ9v)qnHqA#VMNqQ6;M~KKrY)P-@bj*>xm>`u6+Xx_n2QiH4gHlPSUiRcQWP=IwO&T z3C>onYG-G*AO5rBpc#q7yqZwpeic(eOAD=8Cu(d=5hVEWBhha+KK{pR!`w-j#gu5h zZPNU7k@@tEOXP?Al0?|$7B43c$ET=uQ_7VJj?+P+HZPv&2P^OfD<>l(n!dii=Mon$ zFEKhgIwfh}Bak0G#(xC>Ly>)wdKa{PlT(q{PkPJ{YKo*+>0ONq+W@)_qc9M|e)ROu z9?~zM8G^B3CH8U99ZvIj@psS3URs8LKLi|{#+f;eIBM>L<#DXCtyzo*JfJs=_PXaT zD9m+`oS&Psy}!02KttSdd<*z#@Nqjbp)ICHNzc}c)Xte|i)rZnP(7D)a~1VxD?S1L zcl|@T@A+bJmku)=LxJGgXBfDR_@Qn03R7mwB7r-<>* zn-|H+$pBK1>|dB#Sipf1Doa~#=>ar>5 zX|b3ABmNyROHp>P019ke!n7xRVK%Msj-9(dtpQa~OyIf=1IAys8oY2FS(%s;uTty7 z$cv7~0;c<5wi2m7fytr1_}e%5cg{y$tDQmmuaj>*8As=k_f3Mxoz!o{$LhG0^#NG> zv>DK%`SD}WrfaLqPKS0tIbZTeOPA9K)CH{W7(F3K9@VO-g5wQ72wuqcMgYWX=8cw} z)s6DEGsa?Jp~2^aQV<{$5>wua9c51oz&RM1m>AxiZ2~s#?eABz?(gpx(a|BTsHi9d zjI6_OZmG8HH=~6#pXe<(vhW#;8vYzT*Ul_c-_p#CF5UA|BdV6~qz%q`IzlwpQeO-X z1P0`s+$R|zIVra;pU*JozrOTaENp&k?jIZ!1HQQkG2Lx9#hIQSC) zxN^(c*NNaCEe&Ydv$TBM(0w}TLV%LHF&?XXGs1eA6+|j5EPQ--S!FiPt0S3uAx52fI{h8^mg|8MJs$Rjau`c4NkK5J_RKqOHmSy@>4>6G^Lka?p4 zBPuFl1PPv+ASNCkH>mhKL9!TKo7)d;{LGYCt>&t9M5Z6nOlVUQZ~}m|@3FpHA_j87 zYTNc)kiamUaFkbhYcs(QMbmJoPf4eZyjumnLi#{IL ztk%md=m58iA``&yYlj4px*>m0*|c7s|6GVn@`93;d^g2I>6Zn%qc_oBdilf468TFm z0iD3#8#_Xta{KvA3-ZViWn6dCBmJU0u_n-EL@xGiW9Z+@^be%m{yae^V8MVfd-Dd?b;$TXjm) zc10NmpcG4o`~Xvx-A-KnvHBKJPYWQ)Ib%>0%*vObWu){Db>O&J&!Np3E?{O1!iere zC)K}pPRAvvbQoLr_)jn<3VaLsvx}>!+5M_xVhrY^G>vadc{-f1jzn;9(2P2|V1eLO zl+?=?!wmm|9V@E~m&`*g^hvuz&t1sQ3r@Bz8On+w!5@^en;OmTgo>ayq6=4ffMYLn(fm>#j|=>0$+liCB$6I z*LWN*O@Io5u0UUv57!BW_q5i6h_S>HSvipv8GO-w!7A;S*Xin@e)m)vA@(9~B|GH5 z+O@#P*cf`!^uwQ^Rjw*vqwL^VYKA@s8>itDH zc9suxoT(;>}>i=e51(#Q1n?oQ`1bUo*{N!*8W){OKM-VI+ z_e|@Y)&nt!#Q-rU`uBZDvwcW-{dvqoyAp2MuI>T+1DKt5$-V~3zABRi<|o(h$gb~V zf3bgu9^JoUJIov;>9Y^SG;?j*P$J$jv`D>V;Mxb*QTzyrvhErr|a8q@F~_1FCz;Y_rJYS!aSAMERy znCL=@esYf>uh2rGRy1+%qG=5(!F9?%FRNxAq*Fk;L%Kt{ySuyL ztnK@L|NotHt_!^oH!J3ux#zxT=2=TO?TG~^d0+4T48zl}&jJW7XmY;1yo54}qN(yz zu-~M4*XerC=)ywycDgs2dG%ch`D-?n&9moo39j!0ui3xVVTH3NfJm?uD-k+(>z9-D!I!R7K%-+^?lw7G}tN27|d z@m3>D#;av3%jJ8occ(7=SP2%4#kj70Lr zzx-v3@I%@`NDKp*(HC-vF+_;+nf4!{BY&TD`?-=Dr__*)g5HLIpT|gfZGYkSj%z*+ zSzTMQV&L&Qozb?6XJ^!5N^^Pq-yxZv+bb_{D=}y<#dn4P^bFENg6PSEH)vqE;U;1+ z54h1fCm8L8O~ohFQfjJ4Owkdy5&w>PiPvZ^|U7RA+rW?SNF!j+g{Nh)`JN2Cu&d>N*+J z8W3M7$T9j$y#8W2oyrKE8P;`0h1o9YNa8Wi>6AMQoo0ZOY8B#ce^X?|A`mw8%d=Ln zQruwIMa=tt-ZY>>jI zmFG3&Jo>Jy-AsNem`Vi+hKgI9Lvj+vl^C?-_5yGyYm?(LBXIq*y=oU@0*Z~317Pkr zPVQgJDIY_QqyBgF2a`t%a~m-|h1ws~)8^nrT{vcD$gP@-;)Ap3jqlI%6~EWZFyPcwU~?shfMznyMsO4^0ZyWkPwjRUP!`$ar$ zBIn}tD2o^A&YE!HjWRSjS8xd_B`7c_Z$QKZ-QN-n0+{NbeGaSaj|OQAY?eEb9{l10 z6CBF6$z$8WtI+KOqHawEJ4L-tL@&IpF*y#J-}1nyKhs}(4cREcG+4g`gBrXxE}s4t zF$J=#USmqcWHR0Qw<-4%MMx^Es$Soz0cnv!nQ@qM+cu!Q0$Q^Zy5IotYQ<9#ZR}fC znX3v3Rfm?x!1G^)(v5m&2-O zI_b?ZKCM~i)UPJtlY$kni_78`)BqL)SyztQ<$7cKGZS+moDssJ83{dJe43b;xVYm6 zRHIsxd-eQf2WdC2=3BlYI=nrq;SZo42`tV$Ao)Phg&BojQIod|PxY8_5UIgVo|K}J zE(Br~N(2d5-e%;Wpm6Y?WUroowM$qBv6v?f?A8PNp*LX*u~;RH_>lI7E9u3h*OUBY zFnOG#!9LZI1Ba&|gUf-#)95(=QV$Cgf~YVi5Qo5}iWhbn*z(0+bCq|5Mvk%fH*cQZ zQT@!gcdnmq4q|C};(4-q-hNzy?vj9Ro&m7_>)ASTk&fVZzBN_?Q~LdaX-d$;Swf4r zg+<}~B{gC9x8n*JZZw8yr=yq2RG}kCFs}a6&4E5lZh|Mjk3}5gwIMTR9fzE|daeQS zdD3GezZVg-emSRvl4Q6AL(L!TAdZ3aja)@EyHu8{(9mqg)A>?j<5vBr&=y z67~vXyCKQftt$f&}*+EnToqPijl;W&eUQ_n|`@V0LCvV9&!+h{sXWgw% z4J+d?2%Y9%4o#wc6u0wO>tWHn zQ|!(ycQrmAE@r2-02(m=O*ZBE(Q<>D$wHgMEaoCsp!DO(-J0&n`|3!b zp@6*!|Jg;eV&h(}85Hk{5-+Q75QGZm7p5Qjkc4X@ItQQW<1-ZXD(`*6H!!Vsz*S03 z;YgZnDlKWEdaU7AB2q!mD>T%h541lLDgDbSW%F&|m~eEX|8&&|-!RXQJv~xdXjT{+ zXf{iqU033T70*vi6+SjkeZ8tozn%>8tZ%bZN$AlU>x`g*C5sNHS77j>vj zhU~h2&Y_ddms|1%TZGJaB_)F3CS4b{?4#pVm=O9Zi-XaD!^Zb!5v-P*?0qE6u8KD< z#nT7;ZD|HsQo7^wZp85@EzYTBC?z6lZMXI_(e%C8Z@0CDuO{j(ZeowU{S#W!Be*?t&Y-6CJvJ&t`UBcdwLaz1FJ@!hBQ8PcAynqu^nfyn zU%h@Jg}8{@4K;5I_n@jLowTKAs~A3Go~)0HxysUY%yCSWW{2?ERISFk7s{*%*H926 zA9j3tW;5q(HAIlL)QQCEWYbRz$2tp`1;Pk2=?aECiuYRRqON^Bidh|%O|!@g*(Juc zYf$ezZmIrYgbbok(_}5cp%94)DO2YSx=+U9tOO&lV`B5y-mi^jODU?W@7ky56{#uW zYQHt~`vhaLCM-3ztJZn9owG?w>~xdor@Ia~G_#Wl2Kh8KmrMYM(<{&lImTBshi%Z; z=R&lx^QmGr|4*;+D6Jm7SA$+KF4Atg@3aMQKaES}&UZc6pqCF|$f%dHDSj~1W>Z8? zxVEuAY`==oFiSPtlg53X=WVplu-8d=gZbh zu@P~@@86?~i*FXKao`%MLuVKfrSmzFOqVUl**bQKJ<9L?V9rGI|BUWR$iA>yjg z(dXG)sp%zrh(_FOTGe1=3vYo!p(@lWxkeyDLd`8H`%UzoHINFwE(P&6XDQS{wb+$j zEU=5w$19TG{1Df!>s7-gk4T9>f2H2o>`q0U@(gbY2xQq*>$T-@G*b=>TJWuC&-c^X zo)-;A5S7;ZJT%{|7*@5>8&W+h`Q~YNWtv{_X97%CkC07Zy#wg^)P?%K3jhEq$DH&?O2`8Y4o zmU4$T1>fbifJI$>s}9WCi|P&E{=g(74NBvyJ(y=iw8n9bIQryc+#^}s(^^0W_#_l6 zS{Q8Nj~wFQY=>N(46BhFYP+>m9SSXkr(zTHLySB~g)R`&JWttiz4H_L>7Zs$^W;XG z4;mmEx#%4p4*HNQ>e;xBG>wdcf`y02N%y1tja4eQ{n^{Agp{7S6hlkx^nhY`^@lOz z!pBu2Caqd)(yF=oeQzu*EZ2)ssm$qpyS)hpJ=c4s)%15p_h8QzN4|IOUPcMt?W9;m zDHVu2J9CbWjh(c;AO}DQWaSGP7RQQWrRV$d9#n$_gUw|nY8rp<+6A$MuoIxNa(G)j z$85_voBwAPfPcr!=q2SVWJ-(&n!u9jFJ-6Uj-VaHM((|+$)&Q2(>|}~nAen_gg|cn zE=RnIh<4!=kyt*xY?M8YNTJf=J1)=o&|k~X)aqAwanLra>2=`1v4o|H>&vd<@iI8B zD^iw)8vWwN&>Ker%U2dWgOHn1q^YM;vJs*`1Dgt1w+%q)@}stZ8#yoR?+Ab| zuSVF>PV{SLCDmB-k>x9&ZSr3Q0hA$SM5y13?4Yr&F;Ej@h6w+g9m;$RGku7UW+owiXuv2L4F*iQI zb(v7na~jRvrC=7vmxQ164KpEP7Q-r?Os*U1ApOAf<#{@A{Sc&zuAFt#;hxBMXwbXk zURKbDmEUZ6mgqKbdEi?=@V2;GyO7z5f_6;DVCpmt$bK6Fx67{Qs!piALpbSVGr=wc zESU$EID)*>a3I!ewG-=GqejiIg!P1{uH~%w#40(|w4!|o$;Mo%@ecO(p62uR_VziD z134ip-R)i6%F4=2<+~xll=%3-;9x{Y7ncqy#5!1tByD~7uPv2Gy~GtavJAaWY1m*44-N=&9m7k| zfZuM0U)E>zimQ2XQ|u?!4Wuy;qs|;uCh{b_iGI_&75Vm{FK8S9FoECP?|9nZQ0(X9 z+;^{PG*)=MVl@DA^2g?9ENd5y5l{PpDmbI$2<^J(K8$j&?5SL1%Oqax-92e#?X{|s z^S&Bini-WcxGigx$dtx#>dgej@d+>}-}<1{!6qIjWJdFL<=C2Bs8O^dvll6q18(1l1#;*+)3XTX^ZmFmuvBVt)cuu+n zrPz6!rI;bv^nuhjyRTDf>FD2Lg#zR;U*JgNnDZ5*-beJu6W!Ox8ikkFEsT!!kNsDc zB!WMCZ2C1%ymjo;)lMUt3T+?GjUP^gX^tGx^cMY4z8n#?3O#LDaMU`lK0oe@eM0XR zyjT(SJe_ocehL8fP^Z^;tC=tG*G||3#wKIbu2)1s0M*e{aOwk?=CJUcCoWEAr_9HV zwOl&;@|KO)2P{0tXLZyTobTAMHBlE7 z9}vuzzPWA~7btkm`je8;4u*y(W$oRh8}uxvwnJ}Z_i0BO{%KeSL$Bx4r&9I?gKWId z39_#1wr`%cm0rjLlwm!HtPNme0?pGxPlK=r5IB%pY!hPXp;m+#owjcpZU*3I1Qx{z^ihf>ScEv9$x*JT7x_1S9CU5DDfBm@cFB#e#8YwC{(%q{@z`P|c0eD$*&jktlXg1AORLarw&HJk^ z^Y{UP?rPi=iQ|Jcnxg;j#<@nEG|-JS=`6r;2_j17*GR&h6iiX{G!xM%{U=X;GSYtF zDQp`BM31Fo5~ftsYRr{MP}AiihX+s7YK;ZY zN2kt{eHvs$)PFjDF{;p|BSP;D&EhthSJco5?eFhL5)z_+8=_052$GQtZ3i49%T|IH zzzBc9pkI#4Zx*)|3Y38_#8uS~8(eqbD)0^m5f%;^dW7Wq88>W&_{KEuwNS*S8J1ei zkm#d0pp;BY;JSW-248|8iFK})OO0+*wV7F2FmxZ&HWEb6vxg;UMeUx)XA<*7jqRC; zJ7FDa;mK1iL}%+I<5I2c-I#c_`VgqH2%T_RJwPW<_q~7qbfyV-Xpxx!)_O={;)Fl# zV;k93wnU`@7#D|>FO}2>n1y;P`vI6AX3+Yt=S`U-9~T$?`YB=9$_D{Z}FoMN%pdAoH)=tW-Mf}{UTdc{LT`H2cZ5>as&xZ6L!KNt?MAjLG3iEX?A z+-M^iwIeTSGbyWxa}WQcS4j)b6tNS5d0|2YZbK>Rd;s zI@1P{>juV6;N6#ZI;|^{=dGBP)}}D`vMzjq4fAYq|llB`hF@+UUW7M9_0))9dN3^x1vNVj6q&fYn9w zWT|fepj{Q3v`nC)J{^C+A%G0wA0Z+B)d#GegsbU7j9?xqa?rAVHIqdT4qJze==q>Y zfFQ4FiJO}?-P126NsCC)5Qmr`o?keLL!gp(gKE`yOIoKc)m?W(w2V8jW0t=N$J4ruxa=Av-0O?^^i;jw zU|Io_yHUY{CYCVme%YCBP}uhRw#krpINvkkUJDKx|3|Il4!={aGwNExc~LYFZBQOc zC)8WnEP_?dC7!~rrhT^{Jjiw*f;kAQQ>+`TBGzaytnrQjl^r|!4GW8ukx{OrM@JwU zKxVfSWH>%D$wl>qePohY4Gni=f3GSb0nhmQ^(cnk?uii9nGLX<{-~U3Z3+$nj(pWX|C~zB0h}|z^(a3eGRyFbvThowCc3WV(#v<4`+y3R1rYp%&xf-dE z$Bmv(*L^XS5D_&ZUDGnii+3<&6L71q{m{~Pit84+_~W_aI;Nb)3vnnbW^hq?;0@2u z&VCBe+g3uDjH(^P~UX3?2A^5e?5EQBu zmK*e-e~sZ_nQfTY0}eW-OC}EJs8;W#?0d2v%~ISy1A0tY@U+IgW7^Lne7e3VsjpUk z@Dqyq&2n-$4R7>iMB>>VWI1iDu)IQUBP^tAiAq9a{Q<^F{{Hu}UKn(aT=J?#;OEQ_ zOp3VDe(X*S{K>?j*1Ej$V!es+^$@Yu)nidTjHv0KoPF*vzsIu6aM_yikr7s_c{5f5 z1!ZObWHA_o6xcK-oZ8IYy3XLc2D2OO1>-bU}ANd=u6X$bu zmY~!Cpt`+*G+Bf=Fv8TK3i*>{-Y9Go#48_UWJX73V8Yx$ZF4XQvo^=ZJA350>d9go zt;nJN7^uDW;S|U_Y+3pFh(FUr)Z7Czv}%l$N}Za+Jr(01c}E74xN@bb z1DiMRb0>9r+<=(sX4m;xv~49^Q(KEKAtAv^bm(LzCMH(yaeag&hqomMedZR`nItv@ z&|jT$$(TvsH?M%i2_Dj8Z5?@d1G+bQgF}OUY0!I9?RZ~sPhgt)C zte6xHfQO1N+>)5^8w9I~(FPSowWSRc5ng-E6jwY+&Y5jj!q08}G4_=D-Fxp%`gki0 zNbfzretn9o-Q5|@R$|2iaazrBtb&e}?}@Q)({guD*9DgV%2a5j4LX=DH7GFKYfVi9 zbJAlC@*o)Yo%<|Dgeh%lTGDg#U<@YKDXfhCq41p3YhiLLJ4J=9_`7uBM-J0czU6=$ zsTJv`Xa6Wyd+G17Rz#hP()i~a01%(PTA7(K0MVa2KVNHe%~&TR{h*>}%M){L$!x5qrl#1h+5pVRr|~l^>QtM*^eYz^7sqA22}@fD7JJ0} zJ)b+zgW~%B)nL(x9{9R5Vxgu+_e(aAVAlv%ZyEtR8s^YRl@E{p(I`R|?LBdF1d{Ab z!#r&hdae?~n~$6_HNSo#2Vs!MTW@b|>GwpEKIj8{jb0D%bL$j#%A*iii;2-9wT2M} z;_a)?oQQuj5t*QkJoY{DU}OqBbr8~2P2aRW8WK`WJl&^(Nj=t#x;nLnVwFO|a2hJA zEJz20sh<4CX(=vVJv-7^refTavPO`d*xvvSt0(x&5Dk&?DxjMA)Rj9zBB_<$l zfYskpFfHRA+eV-hib+!{5I4;i7_2ER#h{HfTiAX+FcI<_HI1`AUTPvHiU`z&!;P9@WH;=KIM2k15PD}-75T_)GES};7f&*S@&#a`R5ZQI}cuNZmy}RDM*h+ zGefC>zqzEYZiXhz`TpwAfh_zbF7-QN_j?HtKlpv~;_}w-9ov8^EkHTUBgfYX^ekAl zB{)sjonwv`)gi42fLx!w42_NThtmW~*13~|gCBnUWt@Z~yN>@d&LB89M1V<;ltU57%M#F!_}V2s z4$`E`2iK|N(Mh# zm5~{S{4?*NZdiPU;!ky1f9#gU=T|i)!)G_H00;m2`}sYT;Tix!%OLO{UO$MKDo-~V z{EjGM#FT@cnORa-mmEaF!GX)tcmmVj?r9S*ecNt{N;o8=ULheRaj^7CxC7;b={HoX z*3soCS#&z_LQ37l!N4D2Hmnbgmmk1aR_c-CPQ`U|Qvo}+G*gBwqJZop1_E%~1tIyL zXMY>}N@mBvRLIH6<>%)^Mor=LFuIR`=wSTbZ&IsUZ;5g@{1P@^o`L>;dKo8Uo#X?D z$R)yxNekAf2_brS|96F@S|2p_4yD+vvNs_#l)=3&Z2vw|hF!E+MP}gLyLV-3lE#9| zlce6w7%BA7_Xu2S^*6Rr%XMM6+?Vq$PjO$=eVO0h-&fJ`lSmZH+QaRW7a z00aE8Uk3wXb%H4+hp#f%6BAVHhA23}(?1i95QC*um_WUFhSX}mziQAakQTPU|B|{U z>j1+0rz_z+y1x3hUHplYx4ozEyy?FF?ft74-`iiSS7wmci1{WT!H?yW+ zT)}={o`Eg@Ii!fen4K~5QW!6t=QZ>JmJcsr{~7G$I0V8fG%PGvj|oJNi`??8RdFNh z-)YL~co|hj)Dp;T$kL@}iLdaW>A~aI*wy;$9)wmZkFoIh8!f*PQCW-RN7;Z#^nVJk zKi|D}7Sv24J09PsrXqR+2a&|hR45df`eX9{mez~Z#s7hCfT+p}_?2CtiU8h6><=?F zGJ+Wz8agsPy>0(|xjzk?)dGlSIFq74{!Kn>AN5ak3SZlvKBiJo326#1=?izcr97k+ zjO)Z_WXb!NFJk#S{lXa#J_x@(t+bdy6yH$&2C~F~du2W6KT^b0+d~Lo4j`Tbw`{;O zEEbf1m)+&UU4YnUD`09$1r-$)1QHb!`%*cpSFQ$J#0$T+6}C^Em)qaqN(jppBq_O_cnndF3@88xru7H^ zGd-515($|30EjmuBcuG15(J1kO79RYu#)w6;ND4$R`+|xqUn9TebeX)W3Y$q)Qt6T z3fkv6zeGRO*yEA$42N zRUzHp-hx2IDz6uXbU(Nto?-Ul8_W3cSxCVaS)r9JHSZ}+37g|*TL_ORt_c^Gn~YQ- z6kp4xUab^n4yHZwD!p(f>8JOI7GT2xJdl$L3rh~=-!fnCYe4$wHQ6aPkiL8w;Oh&s zTjLM{lRe7KGB1rMggsK}RNFQ+i7mbbD`&^EIQvQ)4{1`;>VDgzXX|EHn|g@DG3az{;EiB~i<_55^9OsMA7 z8pz#K)6-&kL5q>Bfr0!qv36kkmlvHY9(vFOU1TDAVC4^=WpwVpt zv`PJcN`)cCztQ4RXqc~g65iPU95u~>6zP@(p2LJYc^-S$fmgb$|T+$xCvL9%~EG!=81MxD>?ZqHEOf&=i?&NSy> zSg)(r!;{B#qbd2xPQRk|KOCL5KMS+v;3Vk%PvGDrXor%&!HUF$C@ef*Btj8!Yf27u z3~s$Yree_tU|2Hg0{JRYa)$C&1UU{isIS!r-yc~q+WsE(ts%F zIV6#5kmU!4u5l=O#VEq$2rHrQuCOuqw+u^b2~99figb(UI%jp7-CJsJ+1W=&MnJ7P zH4yOZEH%7Uo=>(`yY{j}oh1lxmwJ5wW37Okg;rc^SJdyHA^k+~PYb|oxu!*7Fvv2|DTc_31&K!^!n(g_r#nHuwJX>+#9ri zcRdZs)j4#5w#f4CBMp}0H^X z-M3iK-Y!Ss{pv5(4|XTw@9f7u&(s?6e0@4|KbWr|QCvj^xMtM$GSl_I@YO={Cbw&r zyX4d%B1d|O)%UwyK!iZ6>Td zL%zi{?@E%jir}Y8DPUrM8JqN9!el8+UZm85oqGKsRa9w%Y%; zbnaN})ijS>u`qR5cRbKw@lX*0^{NcQYwKGYz~l7x?~2$y>NH;3gF(^>n^9Lr+JzHA zlE>Sh6c=ZhFUx-y57$3OemzQXD&9FD6*f7B^z=wwn|$L})D1MXnV!YiUU&+8SzYgJLZ<8(O&g8dZ|$mIUzfr7ZWi=v{UPgWKc30R?H zivk((Pjs%^YE$f`^!xC*w;kx;Cs#&7hyZ@>)6?2F{(KjLy8t?-D*CdEE@O%iSY+9!_^M;_zl( z_n|EpBVuWo&fx9-`GmKW(Di5&wGk}Y;=V>l&4DF#n)i8*X4As+@AKcxK4wxvkGBK+ zxlfH80%Ru33;f29no?W8ODCgWN?`d~A-3AGI?v*j(m9UpI_8(uq$9Eup#HVVm$yH1 zaMTzq(X$|}5T-#tzi!Dy52l&lMm!)2E^08;UG2}_>de>A9ky=YJ~Q<|J0WUy$_<9L z-hFNiYHJ58A?DB+dN&((0*JWYEvwbV|I7jmN(;}X(jaLXjC1%*85Jq8IM6Q02@-j##kacwSIHL!n%2&1_ZmBe(d|+^~dVXH>d2`|2UIjDO+tQSYdHr8>0`TGu_gQ0vxOHt_Z)0RjQK zgt#Tr33p=v$N*mQw*^{zpB{I2Zo#KY{f733R=EdlV%e|TuQ|DULP^zwz@VoXt&^U zlio_1f}Q#$ptY}V_^UPEykV!1;dqC0Xd^DZk*rn$fm!;!nXm|h6-m(#IMyOM?!XY| z7r85{hnv}V(sH4q=1REG?jfLB>dE=Pr$_;U_QSOxGie+Exx%|kJztK>>*NsExb+rP z%HRs#E7EKI@bT&pq3CI|GFOVj)p{=%+Bui9VOMDc1(!Eg+GF75#(U_9*u-3?3>m{p z4`R>eFth`36Z#vTK!C?JYtBe0Dnx+_a22U*fymt5Q*LDy_5zu!sFcR=_!{Pe`7;U~ zcPe}!_aq3qH1`KQ}*#-Gv(dDUqbN2jMU00BE0rf4sp=_ zBcdL_qzF;32GpSS@bke;oXKExRSFumF`5Bb5WoYzSXZn_-)9BHg!D>!X@FS>~+*xKI}C z-}97LE~1D((ljQr_y3Lx4AK=*%7FKS4YJa{8w@iZ<@0PO*5%n6Api?um$A{vffT%+ zaRlUB=29TgnFc!r8;lo#zy-JsH+pLRkE!8{ndN!dH@P0<1{p?aY(Hc{kmhDV+?OxQ zm&pFoxV)N|Ol@NquF#HuVKr*FAp|Cx_NT)IB?thW!z<5%k0rf{C(hgz!`BHZE*=NB z&-@`$*JKG5)6=Nawl0lP=N>IC6-&kb!Pz7*piXi6a#|0p=Az$$0N1H~(psGHL3=$$ zS2Z~NY{K)4nD68~VftQzb?SBxY$4TARjit;M9IOSd^f*!!zcA0?gaC#e%?1~=p7{u zoBaaPJ1Eu#^_$z~JXAQUA4j>AbZ^0?uPm7?cTM>+E$o(O0CZ10*t*n(-(~W(R5?Id znFfQQIhBN05x}~D0g)X;Ze}+}5)SB)!MM{EY;&URX5u@BboEjLOk*-zIHMm71AmD_ zE;NHCV|eU&r1^`iTy# zvN)hpZ~?Vob1f7C<pZMD{nEv|IH1J8=tBAoF-LscK6dqJO=e?3#dp>$7 znMZ;oBGNz$!cg>uPQ4wYrz-=85(iG&Eg(2DTt#Z+9tH!`t+^T_C&n; zVgVrP56;iA%(?hbk9a3X3Rsm0pmorUyATcsP$8t!$h~1=l^m#Q!eLZhp&tN+Yi}7k z3RvjA#W6x50julWLSKh^js#nQ8x45=4_myMSuQS_0RRpFno`C|H(N}*1e}q-c?m0n z%|#PP89ZCy*}NB=?v38Sy19RB+;M&en9lk)%8nvV`)GKSGW1Z?etT#$#DSSsbhm;< zg{x-y9V;PDW~XK;?n<#Lvclp_oOW89;yld3>dA_ziIN`((Zy z^@K=coZ;8%q{nQd_g*@-1gtYCAcDrbm$-95c}CS5#VQ)cf93HO&Qvswy?tJfFU@ds z7tG1NQiU$Sqqxkhi>4k;ldiF|7U+Hr6n>|%P2+$nsDA|aN>z=t$`DQ zVTdHd;ypL|_s{E#X9IO}Q}B8@OY6$!^P_*17M?lc^Ca{n?k4tUf5_632)Iv_3Uc{X zkWiambt6*2_^z>kX;OUADp;S8R{{S|t%KvAq6uH-C2($K6%`mzxFj`fg*eV(?57=o z4sv){!?nR#i>LBv3z31lo^Ul>l#Q8?LL zXu;!H4_MLO_tHfqC<#(`2UikI3Uv#{3cxBG`!NYRNcQ7#e>^baAetS4LL&<+1@Q`} z%~E*a)I7I}k*I_)=PRqPi%aLG`C9{2Kz1X0o(G4cBJZ?UTh`M?i2&AMirN?R; zPH{%bn~HwgM;P7pvy83xxEGuKU!Pg}^C#wV@6!Em`bBnyPPV}Z7a$mg1P9Z$E7pJ@ z$~Aht+$MczHh9oH_TujcqRV}uO;bw}Dyp-m70R!#lAU%m2CIrb<&D1|xV*fyG=v`P zVOiM{hAOKSn}{yRyifYE3CLJ+2?>>7f`fZ4*cEG9dBkcmGkqdt#W_AmNWh1NhT6gj zqy49VhpT7pJs(t)M7CR_Q7kDU0wxX&4sN6k8-|Nh1RWTm6p=2yQ25OFa&2ubXP!w@ zSbU@3@U2Mc^g1Jm{XfU}ItbN6kxdbRvgJfLXj5A!=gozVoBeh4AYnL zDoZP3q~5vz9unEjnd;-M5RYAljvHjv)0yC4#^^#{$Ex=hmX;IVuN+$WH{J&6k1DA} z;DcIe#8gNQf(9)iZK(cmADNHEvPUx-8i+s{)B7>$>BE7vL_u7COLSyX)>K)bRy`)b znsZ=r@hs&UkXXDKgJ#C0d9IN$lrF@ypnx;5Bo<;*4(w^7Vc88~|1aLE_Y9U3AOCqg zg=y(mqwdji@+x57YYEN(z=y#S;7$|W5x(pa`r6OpaU$NnQEy+1VVbQ$@UT*6*>U7G zn>FRA`1__;T^X1%In3xfGaS*%iUl&0zkCr81&8b_p?;5+m|13yhlTQq%-4f^9)X?x z(dq;&i&vcN(1EpsvHeR+IAlbF?{7{5HHzbX%Yj8_7SZ^}iC!_O3yX6|c-00PKMLI2 zXyzKlGf+@v@$dyF`c%LVC7iP*egNXYC!7%A=;Ol0D%2btj@?tsBP;G11Ap!EuC@Xm zrLsvQ{hx9zXetKU*>CNJFky{y%v71hPA8~DZr^UFC&d44`loY86MU{|orf^}ZTy-x z>-E7)0tlZU&B|dQ~WV|R9ZFp;_|Z1@NIbv@JV`BZ>e&m;NS-w=$r$` z^oG28xyq;Yss}3vy;&IO%_u`1{+1HKASAdKzZd___jm~wc0+Jo+;c%`sR=9&7PxnK zxTi$>_X#RQi}Qt|-b0{14kp$u{@>qFMf^{9_v64_%6{)#F#spz{}zrZ{pCddd;at2 zjQ9lc%Z9mg_%&%x5FrU13~<$3lH06Yf{6rJkpGUMrTgA{L)spB zGi_)}u{Jf;TgQ%|gw90Yr+0VrPsZI71C~rl1}(utu9u~ZjcKnAX4miTL*&G>`}9At zI`)`8Q!Y^Imxo%3vX@qWii-~j_J4m^`WG5uJfs$zJh)I1U^$2eQ(iz_s|S(Fe%Ivm zhmx>L<9MilK;MYz&#CQyTFXJ2wbo$BMQv2D)_)C$Vt<^#!MY^|vK&?V2p2ss=`6!6 z1sS@66E7*dL5M*oKMA$}3TB=&W*z%Tk?El$uU@b$i8nbZv*wEJrc$x$@u8NKO6m0Z z0L9<24%Astt=qXVN7YhyIpestx2%lNua}u)XT^dwl!NF9gwVcs5S#x0)`@Yx$|;Cb zS(2)PK;3+t8%)u5K^cV8d@FI^nOi(2MYk*9(GtvkgtWOfucu5o@{5Y#R`%<JaI z;;%%b=UHAfO>S${MwxP=KNyB+{5$>smoC8dE^Am2-lYi zdzSw1&=D#z>CUgFHVD%o)3%*n1$O2 zvHVg~<+)^PkSd*|`25+3boLq>uM%nlyKsUoo{`H{iPx2eX5ANPp*LB5TXxI8_m>g! zVx1-@Cv}W!%sHsl>r-aJ=vjHvUCR?TPTvg067xpAcYqEvOGrp?!(;^hMpqQpgKi>%gNs{z+^VJGj37@pY{W~@z8B<6O0&)T5iPHGz_#d9houn9M z7hbRnm#B2yz%oKlr`D%cl85}#(rtV(Tu91&y~D{k{=%Lg2VQqqms~yVl_T5V`NTS8 z$mjA97+BZ}4%%(Mr8(k~S#0s~%<4~_beHl!Z1!HzdaCF6ZHgidk$4aT*J-H$-495W z(Sx`xcx~nvk&9wF=Ves3IvyBPu9f*Zabn+U(W-StTE$XAqARYpt3I-5)N~_3Y$LNp zojES!BH@LihQ?k(I;EhXj>c2YQfLaPK-Y-2V()j^a&uYcN!wbaMaTRIs>N0%3e>U?&Q61U9ayG<%(YJ zOX6c#vJcyC&Pk0dNtWDOafE!Nbi#073=c~4^Myr3+Ty0NM@<#9wbAsn!46U^;wC!NHBVQbj^G+UJh zvWt78P@o+9wb&u>K=}@RfDr382s*>YL4=Ese=k0`131gUOgXHZo7;nZuxU5Iu5i{6 z>rnSTw!3GeL%g>7u74HXn2}kT?L|{k#cJ76IFji zBfnrH7=Sv5ZFpj1MzFYl(afqn)rLyCfF>vNL}&`Uh*}YLGzqDHok9)%>~+)>-&HJG zHJ2r`j~WOwYx3$F!MHNfD}H_w0RaIh5B&L!X5Z6|obHMW*^(#%;rRsP8S?8FBLOPH z#PoEBDMwamsg25#5IZ{#@V}?0r@aFM$z$(dQDyZ3I79pA>yM3ff>60Oy>&u{*V`)O zwgdEQjiddNSs`fuhqJc;sw(>0#xEV01}`ls(jlpIBS<6Col2+D-5`j7bPGs_bX>Xw zq`SLIy8h=H@B4e-`Okdcd^1NuXYM_Fuf5i@o@ec~&k?Y^iq7*0KBIgN!?&Y~p+JGl zH$+wf2!+S*Lc}2jL!QGX?S%3msF$?s?8nd11r#E7T|1V#fCLF3h)#Vw?N?UD4uCxa z5g-__Qx&?|BI$kB*Vn1o*godMhtMB={4j;cwVi5a$YX*Q&f#?Skrl;9!j(olIuby+ zB0|7QA;ukC=z|)VANpKj-R;$+gwvZAVr0Hki7&2jA3tVgaaXMt0Z0v;X7+H;?=5$v zE_=>opReaMLWr%zg}5o@B-IBz8neI37MjsDSVnSVxrP|BDFY;^=(&(9I$rgxa8A>~ ziq-brsn@3;G$8*13<2Y%PZ)_z0Uaj(FjojSD{5KWILNhbz7eaB-ewWvTBOU29k zCh2p3as^UcTpVbRxI#6RG6I$<5&+lG1Bb~-0J+z1`cEs+AV4_G1g508Z~^~O5pnru z3Ql=?ZbS~-9Yp`KYQpp9Id<|jjg0~UK{MuYoB&J_VZ`bMpLXcc#iG&0hGNP|oGN&E z2?4q&&>XZ@@thvI|J)h9rKngk?@3v|-M?OrQC4PV4B##!`+%NcD1OT6n3L11=2tHv zaS!8Nd81U1M7Wau;Zw>B!4Eo`p}E1>t93&{?dAgmURTe5w@#Wy#E!ryte3p~!>C3Y z#P`v53S!9bzPj9u9trvbZxYf|wVqc|NCrcnoX32MOG>&n29lpP>7^M-oY{by#;(2F|F0TqdIHpWjAYFV@GZwn2+%OZk zm^RnYRq^vKDGDer?0+hZ|Iet|DF_t+rHS=w0<=$j-ZKs&Sl}T$o8-uOPD`t(3Qi=S zorOX*D*pB>ey#!hozo;zipI^|9Tx)W3VM?D0Y-X&(Ah#MbGoF!oxY=dief8xy;XZ= zHl)`QRXJHoBbx~YCU`08!UGsIeRSXKZ&!s`%ITUOfFo1o#@#u3rRs%-TqJN)l_shF zRT2b5zuW{dko}!j%&K9_)7>pzI4)MKelv$g5!*`}_wMDgjo4a@W0PjLiGKF(!1aiP z0ibYV^ec7fTNB-$vwA`z<{Mlq|E_ttbB&>re$0v62$Nni~x4;A!ot%~c z2T14UZJ(OoKM~jrg$jA?6le~8G5y^@*quKOiX~<*XZU^h6g-q0Lrziyb_A-{1J&0+ zF8b?jTf4jBuV2T>Sx-0Ev)V&nRCL_)czK^bef|3NpBB_~MXQg!CT+W=Em3}c@K!Tb zq5PyV6b-yWk01D9e}whX2h*Co=8ZS@tp4??n86++sgNds2GT<^@uUim3TfQziEzg1 zDv`&}K*tty7~8Y%F4lvNF|7c(_&Rv+A}%38JXa+%Bg03ZKpA9*Xx_5D1x3Ncyfn4m zk7(A1@e{F3b@!s=AwWtnv9L&r8-tlQ;1J(|aR_31q^N%PwdDLK;RwVOgMnPLoQTUa zE|N$tjxWXz>~XT4_fl)!Ue}}PvaM5+%J6Buu~g4xzuaLGKbD;^MO2|kK~`gi8FV*btD?7B@X4(PFuphS133gH_W$%@ z1HSXBSiUUrLml^kVpIhZD5nA`HdDPYcm4VrRv{8rS5~GP55$T=;7{n^q$Ap;<(2kvpLd81fTD@Oz<7Zbkf)3SF_YJx229Wu(sE(K-LUn;22nl_Q z@0X$qgDHr{aR2(NU5C?4+p%{s9B zjg4p*(lejN)=b2UN}8**6jQ|oz!>R8SNF{im&$+r(2Sd)J(CKP_O`Yhk}Bx@@9iID zgXix1BoXuTBm3okRS0Rop7%|9SzIf5fv~UO4Z1FcN{;|5+&UkA)bSnD$W& zrD!TAfdBlRwkU2N_U66SMqSf{ugx!GDCt5lmk>k3SVCKJzX~&Rs;X{pySRnS4%So8 z3_7`Ow#}tZbKb#o-lT3%E4vRm9n3#cXyA7|muZ-{{~9)P@ZET-dRLd&f@P|pT*ZPr z^EDTT8asD1eE>!89Stolt;l7f{!sUGGUF38TDFs`Xo1tdU2FCw7JtJL8x7D@rjkLh zm@mupG_Gg*-zVV?`;iD&XVldZ2L=XG=}+SKI7BhycKQSQft~<;F26wZMZc(hMJ<(@`UpH)O`L@Wu;L?`nDk1gzI_1T8hx$ay<<9J-oYh#*07ianRA4)VL$Yr0n&=d5;$xxqr&4KKQKnouD zS65enEI(;T@ny!9{N9n<9}^Rcm8;TcgoFDLSHh51MpkrXWIcMbmr|d{S%fi8HYPb4 z9NUX%;HFyve0Jf{3?{PwBDJB!9B@0MAxPp6K?)uzv+k!yZ)AU`pyee}sDimY+v3MN zd%(81%2u-Y=*M%{XMCz!Vc8_|KLW}@{3gbFFJGd)C|PU^1w&|MDl~BZOqh|8@n|?s z$YajZoFjz2p&a%^5fG?J4?9w-9af^Gmnw>rg?$;vBWP5&2v1kHaxN8JN}_(}{P`e>04R~l}j|9#pddNQ!?wh31G zzC~(`omrCMKNlB2-rsu>MRxg&hr?=c*RKe=yu4270Fy3Ty&=3Ni}KmE>K*KYBr?Bk z)A{@GUIHFYa_tNy`kym1=%C;4Gc_91Mn=$^*fyw`rd!A_1ltm0fab!z1xr;74O z7TH*LB!7R@aFtkl33q2juNkh$@RuYJt}^pm8yhKSXYK{i5d+|gSwqVr(*>&eZ>>@U zBFHy^F}RFRuAWs_hctWteRV2*kw-T{07(xc0s5gOz_qFIlz&ucFaspD7THI&oI!8z zTWL4o&S-4aGcc5wE05aK!!h^DvuR_f}$Zz{$#Z>VqFY*|={>Q*m_=s8B( zi++-|<@M|>cbmf~gbz{GbJAcaEQu0giE`EtMy%PmLg4j;t#Kb?^~XH4#1 z$x#A}YG}rjtgNja4k*~{#zwNUvomIN`S4z|_TBycg@;nWR|Z{M!V%t{1+>0Rk_iCr z*P$GV{QaX~5Lf0;cg@$TsuBx||CZ4O2?=Robb!jMBia!#Ep_@%p^4Y1OJjs}U9&Rj~io{SIA`*BpO08r zI{tW+Iy|Ex{u{$#sLj4b=2oq0C#R=Pd3Ch_;FvHmF|{wZ2P^C7?4|PV zHsENye*K6Lo`%<#^6TN_|N2~7InrZ7R-G>=FJyB^+>^jvIJlBRxhkQaH|Lpvh21X> zIsro0lmHmrjS#-Dpulj_ii~sGYRi$&%*(SuFzb-w-**vJ5^F=TG^w+;vVNCWB4eK_ zW@Tly@y|fbDwlg=X!hbG#kEbI9d4_prgGj3HBajDcT#6AL;vOz>Mp<%z+xY6M@3;l zqC@D>P0h_=2WRs0^Pvax4Vuw>8x7Hu{hLEW`Eut)(-Acukc*Uo6@$~jzwfS=j5sz1 zf8F^cFE8Jz>pH)FC){8XNbD@d|KHTTQ*z$BrFfqx(2`>~lH%>Aw^6W4Xt#RN7j_-N@#)YS zj36Hl6qK=@vbq0AnPf+E0kHJNz1-Ab_aMvh_=lV^$DfFjjW!Vl@~FUTN=dK55lzoh zfMmm7gmHIw2Ot+aNn~tL5wP5(OBLerwJo@ktp2S&KwM`73tnxn`;jpYy|c4ZwHZyi z{P0a+Am8kG;E;4TAr04N0GcnPf1QVK6V%QA$E{*I^^N(Q7*xdidFr~V$AJ4G$}qM~qs5ka-x zkk6k#zpAyiu_?LWLeN~fmm<*oVaB2HvwDaXkM`UclRRx30F9+J-+0StMP5m+xGXq6=GHjQWt3k$_PJq2auPpUYT3@ z>aboQS0MYtkwgZ;MgTwC?CB2u@GKDnnDI{wuDzgC1hYzFKqBV@*sE0x_+u*&<;M43 z!oP8{4lg8zUDy}f^iN<*{7wmJk_~h#vx0?_yP5)kA!h-g#d<6NdlD<4M>!)>5uPRf zIDCkVjLa`8>Nww@RR(;%iYbvApZ{-$rj`c~>hd{|XR3}&o)L4AVE)OJoC4V~QrW&* z#Ztz`G_WWc8$*Q7bGxtg;F3LeKxB;To8=~bM^$UiQ98r|Ieaw@G2M zap(xb>(G?ZsZWs%70Zlb0kZkR(FFby9&V@K#)cV?Zwx@tuHjOd-0`h9n2(;z&0=NLY&L4lfH}k#!P`=+{bkh#t-f#fhx%3EY*#}0tr$k>S zo*8m!7w^kFOlF6PX^>w@Ow;A)wTTTU^W%rK!#xjjrG)(t%Ld=p>Y8PeE%J*u8UZ?~K33CAb&9DULP zMWKu^kfx@DYTehIxNi`l`|3r?@YCg$0uwcL^$JP?d)T0-T&OPt+p#cQxuB-IL3aE2 z%#e?`Tqr>$9wEz26biLNm|hM9y;rl*9lT;2DWeOKRPB~z4a^ev-yX#x=Z$iBS^4Uf zrk9OM7pS=*Xl4(i_G%$lblgQ+Pz^X!YOAYviMWsea{~Nui`-HP5P_602;toUa>W+a zOvSGY1aLkO@4YtNr?}UbFh7y=CtN%R8|$(XBEtJ#=pTZiLyNu^jtpR)Nkyq*DUBkK z@MoEr9&WCsgOO7~wjK_nwL+H&lMNaU&UDFD4nMQgo9g)^*cT)$uBUn0!f zNG7iur;WZ17)H;b9onC1#TNX91C!1m78VwKAe-Q&X7qkB5b6c{G)_H7!>M?^qN1Z7Im=PpBkFTl%vkLt&DD(tWut z5Uu7^_o(0GnXlk$2?_A-T%9Ac7$O>v?F6UsgcVPAK>@=G{IpPTJ6nW2KDxa~aoRIA zPpfs=+izv;8I|Xq@$qGd6%3#?R>FX~I#EJeQ%cg+D02RwsQx$0Wmwdj$^k%3hCd5V zQO{m{=tg0N%PeY2_GLaM!d2`>)i$_jWNU$1OuCwRiuLp7aH! zfi#b4 zRss(BVht4C1Z-z6AFJXK_jGX$Nq1U2zNeeDLEO_9y^tG9rt!e1-60?#xODDC2AjaS zzTZVNxv}x;Yy&u)&gkyhW$D8;o5gpnDJ!0qerkK6!-7GD!|l!2-z)>mA8S`smWyXX zwX=tsgli-gK%79*t)!GuNSrv|6QT{{e3=D(z3`O(D{ZI-XIA39JQjz>*=~|45$Wr% zoYfhozp}$xg;GT%Bu?c@Cs)Vc=t}|!47w0gee~#&*K)dEskF2-O0~^AdZ2(~7O|PE=Y**wboy>Hj6ueTEaS!<9M2mM@{hla=ubxeOmz7HvNNkPwKJwRQ1Dm27Ss zj1NC7ws^N(RBdLT0{Y|i>(}hb1I!B;i34V19|z^mnCI33j8#@w4}wwP`uZ1d+cZF4 zjwa@9Ts8vYIWQms`>he6P6{l0FCa4IgC_+z_Hj`p2rWlsNBOKp+N7 znPziRuoRbE?}x=-yB=q=Lmm(6dHpe5t)z4W)97GuQ{Gcj?dbF&Nwv@rNYa3rzd|0u z@7Lv`U_X`sBs3O<5C)VS;wB`duc;a8kAf}63~4v3yh5rY&??^D-7PmCdTh1WOs-Wt zap({y8`$K20h3myrlviEgHcI0@k|f|JCuq_wAY^91XiKYn<0^Si+F(71>3c&9%#n2 z(uPKVzL2LiI|+nS7Qid{&_>#aOoL-CTD8p3Y$(npEkT;@N9nnO^-{E+EDKYyTuHf) zvl`^%Y9-3vhotv1F(jl5!glt9{!EbWCW`S$sXz@NC0KmvbbzWY_kQq#4GvI0r^(n% zfK9cu!T_7DEVcT3wfI|{%mtMz3N#6j94Wp@Z(nwuCl^|cphhz9!5i@H_~DTwlh*n3 zyQAGq!*T@)l}rMSXi6aMwA)}HZJ04&{}3K8LK;DGqPl6gykgRlWjIuocuEG&bX_+I z$EKlNX3@S46%5z!hBQ|Q!L7HS$A zsDWa>q}<#xAN^)Yi%3;}?`D0Fesr0JUCS>tVCJai><|PHK2H(eBC$*nKmd%rb$-Ph zT@6I=uC+D$^#1#P11KaBga7NX)VuU{U){5_g&35fLN(myiodBtGl+mOOaqk~oe@Y! zsV5TPE7~{JzRT}0Q1F|5_W+6;os_gw6KPA?AJ`N^KlAc;4Nl^Evp`_^+q?~S?T^Z( zti14v1PN+iK$8G5gfNX0+Gzxkm(TI>U2}P2BNEhOLgz#Py9Sb`^lMdo1>L5wO?K)7RKl1nji6902#LO5n5xZXLgyTFQ?!i-5!(V6sUz8H8 zwl;D>{C}5GvJqcG0xk~PRFPEHHkngv(rFU<|KRc(x%Lvj_5{A(C2Pu7l`BoFc{4li z1#i|>rV@R|w-(k3P-b6%D}wAMtfUr~G8TVm0Lm^%clAY>|JArSwmixCU2)O# zc=orK_8?S}o~X?#j_4-`wi4jXsw#q;i^J~1(&jKAjNFFaFvj78cLLZ@Hf^=QK5WI~ zUW5CQbwdI_e4?&w^f;&(n)f?#P0t|2ax$i!K)-8_DgUG9XeP=S=hh7YwKkYM zoZCJ?Y@4s>Kv2t;)+}6H7FZ!NR|O5Y-*4);yB~EH!IWQ6&{tv& zFH;o=M=$J)otA~CH;BE!ll6FRA!<|_2gs+~ zf-Z=_^;Y(R$b{*kVJiT;&@@4J_`y?5J-7!BBv1oao;Y3X2SUYUa9ZaCb#LicB5?wy ze=m3&Lo>A!)#~E?>3Yfpg7y@@gAx2dnlQuS1otw_*K}Z9I59NLP9qLA#@Dadl(;9k zNaS^X#6+U}DBm8hFp)J4_k0{O+6!%Ty(Vem~= zF)7h;N;BN#PiVmG;1H8CE?&p|=`K<)gG@BDSM^20Qa}Bv}^_WL}u&9gcUh( ze&y#QP@{6F0XqmZwW;XV^q8&rGHcOFFH*`M@YR-KY#>zvikqI5)ohp=2SJlM>}}Mk zGheo1Tc>I-8KUB!62bq_0rU(Ei5Kb5$EWfi?_-FfgW!pilOt&zsf*xg zhxx0`ayRH5^u=}QO`~1!kUdh$q`fY?x3HZ~G`|q^Q4X^& zGSiD~18-d~1ItNIpB=64lV*Ofd;N3pP2oJ;zI4LzZv995;@P0Wd7eGDZQZIyoi<$L z)BMIpkFH6<_eYdqKBUU&2#UKc>9XnDZYO}9eHk#b#XNHp{8QwCiDCp4EQx`X1zjzc zK^JG1tswy|od_22oaqmd_>iod-u!XY@JD531ixcIqb>+}sfxs~3Z9`C4Senx9u{V| z^^*!DA}1#Yoq}f`M0A_?Egtnk2vx@W@qB;YZsA#*WfQV_%Oh6zp`sRZ8@e)?Ei9#V zO_8@@PokneE-z~6Yx9#iUh^gNaTy6 z>GT#Ct$fvmv{0dmygdZ=82@q4al@~dk`JkArE6ED7EDd39m@N|}1 zeI#I5=uih5dE(>5<%)%&j)ZIPt*Q!I|BR0eZ(Ep)UAv7xqvZy7$4z*Rg2aCIO4k^g zSLot&E4re~6dldF+2fCD_MQJos{IKFS~F>`$ggx}^#J^sZ{ zHyg-Df?Cwx-hRxg`SK&M5;ee$%EMjzM-G#ddoPjtfIAWa z9Gsh#WRj6xR)D|>7&3##?w!o$i-85U6}=fY{k8D8gA_C2D0V+tW9kFW&J2B!-BqC-7@O?slCsS!(khO+ya7nem-9;>K%8D9 zqa4?DJ~-MB73+WG8XmK4UKPyiY6jezdrpkQu}$_ z?^;^m`Yf)Pgk#=s=iuSx&CbuK-@4x*+5e1*lGj8^qiapHeMOy+OP^rE)QWPgjg8;!w^eQ@>lyOIoJ9G&yW7_;u6>;~`v{!h9-o}_%6RxF0kx)%Qu z%eSj27WTwfWf8m4zVw)Ozu-VpHoD>~BY~QE9yxjKcg~dvL@uxDt!?NsddR_sxt17u zn@K7M6js{Tb5zC0L11LnqZpJlAD5|ogijJOKYFB%zTSjG6lNb?2o+C%;w?O^w0w=c zBV6C+CxrvB_^)5-07z=N$|Fe8U`Af@ie0QxmrchR1&DtnT}U1Wk|i}RR{ppQK02)K zEL5X$RG|>8ADPZZ0ry`y1I$wmeX}yMPIUE+9JEwFkMP5oa+hSQz3kW+V8x0gZ5x}l z?Qa6-TnCxNrvho^5zr^$G&V~b%riOshv!9S?LFrXji-ELN@qAuUh^X|$VGqofcXPBBT`Pzm^QjflNHD-%UW z8w-IE3$Fa)Vo6U=!Lab~yBEff(2)R;{N>if8~uISYHMpNq+e@aiShVk3pH3ZH5E36 zkb2MmF#)+UzESrXSGc@s2TW{(oLx=~(jlZ&uzNyBATWcrGx(lLBB<2*Y9DDvgZU6o zO@rMs_;MiKSu2vLiiE26mI^R4m2!1dxbHyhyZLHO-3R~kU69YZrjDhM%ICN^7*pj* zj_gDoZuY!U($kBA20cUq0r+G74Ah z=Kj0oll6h!%gUE+F|oYFSFbh*#flhd)8;_h=jMikaqF6RI=j`GXD0)io)kl8yc?!v`KPo~ zSt^-E!FyxB+ysG$ql}R;sGKgdU2OKTPD)C$TlBoRN_`sJ%a_jE_V3k&UzYf*q3aH! zltf?&BsquW9cS0U7uNHfdQ@!YyEN;^gFnSpQ~T&ZDQDg-?LE9vmgC~Tfk?TiNa`VYw<2FeYGw70!_&dyTNcZhHHSl?=8CT#t>*f znDvkkVN!$*S@?MvZ5?{=l_c{7vqkmVa%7Mk$Y;?~`&eunVYL2!oYeC&*jpF@Dj0me zZC#kXYflH;lkz(}!&$=8c!VCfcsmsej5}YAQHJ)I_v0+m<+m~lK5FbfQG?dD9gga0+;Y) z;X6Fd*Hh4(Zb|RxWiueK`35JioIBlK7=b4_LY~yLIg2d6fKy0EsTwdQuWXkh2SCx^ zVs%j@`V)lnW>##(N^_lD`=}u{eFYeQxzY64_r||G{7}IQeb@SeZSCnS??8TgyqM$B zQfqYe=(f|(x8DH{+;%YEpscLix)PXCTT29EA04#UWLS+;BYu^-x(lb(0fuB<|1aXt zuz?&22}u-T8u9qqq2=U$T69bL=mKW<)r%I*^4SAtQC0dS3wZQz7M1QPt>wssS}kPz z@!v0?$J^dwRdr4ZklV1&ch*!*N^Zh^`j$Rt)d=tIhlGQiQWw*#IuEPT-5wqQSuuK0 zlDm!OtWY4ED`siQ04s&9_29xD7Wnpi5>kqoz>jH9xzgZXoAhC4;Tny93ipbiAS|RI z{U4T?5fBg<3};Dh9Uflr>qmb=7X5@;Vu-@N=L1k|MEi-H#eTrwT8AF`NxN9_;D&^- zqMl|jyd3puaaZvH>w{Xnhvr#!D=wh+%{GH#)9+7T4U;t5U*iGz7wnN5%)7SaI-^)F zAm`_Ozg&|sT@e--L5UZN7#9~u&&DP#FOP|!3BUB1duew5g?5YE7FA9tbtzMtuT=yS z1A}PynKqw&s~_S^2w3bl?^l+TL=vhW3I52x&x|}QaI*hNzNhCRjZG$@-T4#@ItXm~ zif)1;EVxXrS|)?2c7V8c>-ci?1M>pHt-d$r7@6zCqUmAl&rVmWxg&ybPK0i+D@0j6 zH}kfB08B3L^eastY3VJ50>VwR5p{h#pF4Q~kmmNoa4$%|fBz0ZcIvP*_G1Ae2NcJm z_cnKK0yT!>5(_-Y6&wnz3C1Gyk}Kn#e_g^%HWyDHODlTnohe7iMvN`xZiTD+kRpzG z>o%rI3%tqh)7!^1H6^W<-0%iOa+Lz-{l167SY&Rtzsko)ePfczWqy6A^bw0?g)Fz| zC+U3|VCSirw&FS5E-7I}uHbrCXT(u$Vs0EPh8sU!o@w-#HFI>jTKT@qnB-5RG~9N` zs3Zn88tzI2m3nLm>Q*HhG7l&$zkrT_$38~!K5ll2@@2;LNlGF)w3I{~yo%srjC(sG z+4RGVv%bE*@d5sC{b_9MB3}xhutn})|A(VTgGul}x>)}EFL+^&Ce|XS(8Ve%!>R2XPlwgt$!K#6S!&jMTE6lWgJd~E75;F<3(b3VPnP0X3 zT=IFCfUB(6MhHf)VEH+)w; z$OpG#?T*!+!74jAVSFW-a2UF7u!812+xZ{y;IMt|(mywf8vs=g*%5?szd63$ zAb_Nro5OPEpdY>J$!ePNY|rXIK^0umZXOd(08fyK$h@-_0{oB!+qNgsp<$w*SNUQ1 z(S>t$ao4D1;Z=sV!RBBp*peSm7BJ;BIhp4cenZfafsIhVOMU@7#nJ6_Xf@YQ` zNu4vMIN@Td2kGi_jJzDGmtGWLo=LX*A}Ng`pTOJBK*Y}}wx+rQekJ>5>s;-<27Ka--k-wCWa2Bac#1@5Z?HKWC5 z&$4MN3o9!LYwP`-@Yll_4_JLBu%;t`kMNaHw$YX$N>sWpFOzoF>#)}9l=zH-*qu5B z2Yo_Tx@8oD^@(<$vqlID8BFd(?M-Ey8pQN*kw$#bOgaP()TjS^ zz)ym2=;;@LENMi10K_UxsXA^B+7DMD#lwpnI4mEekoBye`1DUx{jZ(4wF|`0WWHCQoszEZqM+$Y=k>~g>-_p(+i^r$1G&sS zWTXdg!S&uqxAKqYHvwYTo7LHRkDTDRcd;<<+Y#Y`8o$;y{?0)-y>ju3gJJIIrY?Q0 zH0b%ms}T%tZ{)F>GAwW>=fcw48qB}tx^TQqfl6a*9#Vk)eU^O^{tQ-hOjY2`-h~hn zI;tPSYyC$97u3e{KX&8-d;jdn3F-2+>g`2(i*BW?(R>EdOvmF%f^Jk_ktK>gg|Zpm zPOKq6GA`_!*`FZxnQfvy%;?^8#jx}{>$R^p1En3g{TzF+?Knyf8t;+A@k5-9>soLe zKXKp4ukA=^=7mOZ;Q9X9^kv3;#KNpUvlJp{^1#BVOG7GBqMt&ZIN&1@C50*lL_JbC zQOuNDB7GNL8wgO)BhiM$zz{p0WK4jWFFY_2paX8uWAY4Oa;!U# z45z4I8%(srW3!h|TV$%sX{9ML|Rie513d!<&sq=un@ojoEnnmbN&X>_59IAQ#|LjMEjppWm*NH&jo)T+67lUoIlO5;8eQBA-v8C)x7pu^*;X* z=}h73zzJuFXIB?~mT3EMbZFj~_r}EDWEkMK*UOViX4u9)VSt ziF&2ds;c-=WY6In=A**G(4+iA*a65hJ6&PZ6*>kt8O(B8QH7Nn2hf6PGQF5zyhIdz zraz58@HV}_w%eAfY5Nv4kH~vCw#lA3x@j72dFJVyZY9>m7jRyad)ua^90Y;w4kup- z>x>%|?D8)+lF=MA8xAOtk%`L~pkQg@f2)F~rHz0~Z0h+UwWLorL-w%k9CM zUu4{D+VF4&Rsz#ai18d>6LHi%Y(=D_Y}aJS)RToKUNMs>lf7&-|TW!1K zwF`KcX3!d9)-bg0iI0^o;!=UcTbJ=BMbI4IJQAratsLnSGoPSu(Kz2W>1F|g$hv}S z&%{yajlIb>g4e_2pL19Q1#_uY1dCci2=~&Peg)DX#W&0#tA@$IPuB1d3&;YWr{xR{ zYCJP!Wl6E7{5|+pu1a8IF_52uODfxNc_UP-I0*P1SPo-jSV@CbAo;dT;>I-mn1h8oO<`mFjb^5IXr!8Z3$@M!y^Q(7>^$uZ$>5*HT_ zZmqp&u;_&%D72&BPompOf3H03`aG#94<}oVrWB2Rd#_8_TwO<@j~sg=m$Y&4W!{Nb znz$pDA3>!3=>g@$JTAY>T%FuXTje6I2!lCMLp0BZse!Q`vL1a?`h2;e-O-XLgsKhj zbRrC7-~v!N0M_<^_DPkp-jy(@#A9p!^O?K-7kli0FlsM?M0y(pACHiO2O(s(W>P*y zo|lNrNl%Ho@CMdnwSiO`Qu({DCS&NK?K9VfP}g+=ZfAJ>*6 z5gijhH9qux_a5Yz^K((e6~#uRe-rwULc059-xc-eN!^WyWs>{nRzQnCPrwUt>$17f z@B{1DBD`P3f!MirKuQRK$Zp87wE44Pcw{I!`ufeA&D32cNVsM+64!rf!J8Jjevx^qpk=Mwx1399WCg-|0WW4o05zB zfwcQ03r+~h?oRSPh&3eRigT&T#%h@jNsb$Eq23!G{pOd%KXmn~7pm)}Ao16g5G!t9h zo9ru{=GOB#TbDj zK+@s;CJI72jnvfD#i(P-d|;mbdta~!Io3v17BjOwxwlZK27mh3op( zn}^!Ho=T!G(l%egvUMQzI`>B3&yjbhgCm<*`jPWK3tN5#<|kN_lGGQd=of^W?W|Q3 z{en|xBMr4P*2zu{7qca+ch$Rmm!sCOsy|qoLy|65G*?BwE_K>U>dhNMkO9Dfbbc_w z|L=y#J%RARf;p+rs zTcR5v^}esS;8r(@Y;qiSpM~3>X8P&nMBG$^qI@rl0E3RvZ?7QHMnO{9Xdiz002$fY znfu$fZ+5U+fuD{RABKr>iVkbHk5X7iVYud>^Cmw4s?khVMOi-CXM_`I=`Hu8=K@eF zrTo6MRO|w%82n2lTmF=$URtW_n#QS>@y){}Ki(Y}{B%7i>b}H90hP(D`3a1YV|@Ku z+f6PrIwil`KZW@VyPjYF5F-M)Opx^#zX!r(XoI#R=e%gGL!CjDYGP_x%u-~K9L$?R zbo(CTR+@nm{iMg2VB74AbISYWMd1$j7Ozi8Ikh<|1!b;>dVABAD6e0?=KF9$+YOPx z`6u3Z;kzKTY%VAjzst*?tnL~YkrhLBuBL8M;h^o2z-qAp{ z7*OAO_M&(1))fa&`osu|t$AVYq^FiQX6@=1t2Jmx=3B2Qevj8ZaJe2k`wRkDygKlp zMkTk0&&H@c#eE&+`a-_l`tL~(YjnHENj){nBM!BcJX9FtlnT^-ZaV=?d96+Fzg>4S zoHD%}2_9}Kk#@Jr6Ny=bl3(v_7(a$uADnz9KL(dega4a5ZbD|y)&>jD4{bdLhQ+~8 ztB{uVE1c6Qh-L;aLJ)`GwVDOsm_Tz?^@qGm6m1GtJ2>3D_|ab@k<03c$VH(?+$8Vo zVH;R4a`q_}qWytXe)+3UUT43WBRaR14iXLrK)4{KlVz2XZ*JBqt{ikBs=ifk>rWLd3?0hg+#7DF3b3 z8(_U69L|!cuU*`w$ZLhQ4k?&-B1Kw^oy^|WfL)R2Hj{18e;$5GpIs%+#K~zpRri;q zrsQp(A5BSu@2Q-t)FTY_n+!DSck06aHBTIocw=3zVZcrV0`=3}Rxh|NdOBX;_4V~B zsjGLPJYZ~{xseIF5tvmHgD7KrH9n)Z!8Rk4{+E>e9R;s|jD$g~usUT*b@HZIjK&k3^#qMFEx0W3?yE47y9`Zp%Q03Rh z@5QwjL6gQp{yI=$jk6=fqO{Sv#O%#*fmI{{qI#*>dminyV+2?|51fnrs_qUTUrokX z>L&KMG-2d_i!$eD9Y!1gJpmKF91_=nrw-eBnypU5tPX8c`Ey!porJ{aZ|mh#iQD}% za&6EiyAG=>AK%n9M2AKk1o9Q}nP8g-OI<}_g{U`YZcM?eLth~%3>lfg2|wi=3+x~& z>gor^BD~OyyI#t*H0exX{2|_CB(O<~?ZRME?hqc-+$5BIYTPbC7fZ#@&%b2~*ictj z7bm<^i7`&JW_a6)d4=qr6^o1y6dGWwAc6O9geth$756o@HHq{b2XVE8&7csL25zc5^%b$4MxsW%jRwT$2}Ou`Gu4S}7Fu;g`~= zZWM)YA>o82i-}U4%lUAM33)079j*Q-{x+PG+1N&bvbjkUs3>u=NO7{AZGocbpt^n} zLmSq$6R2=JfOP-Y2XF!ny-6D{v83u}njR=9nvrQt{mDB+!Gx?LjB&`A*nk>SQC0QV z<5?W(q$a!F=K0+Ci?zgg_Q-42xpC3Ovu$6{aPRBuL|j$v@J{&b;SfJRc%h$0P)yJy zXs!h+oB;Rk*Z=R)8`v=?xLV-}vEQ5Gm+v8Klv#m`i$M)D>{er~mJJ++sDOS4U7~z< zXx4ve4?DmZj72Wy1UN;o)>x z6L{^;1O=6q8f3QMH&a!ZPXo$Tw+|1cot>Sh#HO9fQNIrn!qK0&^mw_g(*dO0NK%~y zNI(E13Co|k4k{;bpFxE8$z&b?{VV@}2$f5qdF~A>^4tzmQ2a#B))^$6A!raVv@+Wm zBhO8QS{3Wy7?Q!>fW|0Vp<-z5rQ(El5d$N5x zoJP(oCS`TM_?%h}vP%e9MW^S9#5Pt{Q4y=xla)nxIhYGw?f%I2KCkF}&lGkGfNGrb zFS`1c{_3O#a*424qo?ZBTTF5TYI3(;9Uil z<0Dn}S{Y^%agDN1wBz@&n&j;PAtKQ$cZeKNE(f`BJ=3z~KdPJ@%(#skH7sD^H(tf( zH?^$4{N?xiq|r(kr72nfXeEME5C}vpQ)x*`9&_Xh zCrV@QbMCgmUr(}sIz_GDTxlYhxkrsF4N=-deG;*Mco^Jjfa-St9{i~9zW%@%bijVT z*Z%}gv?$oDpV6YaNNl=44_10=RJ%C#L#oIODsO#DitZ}{g7aAzE)6U*`NcFd2U_~F znLfPh04ECnCa7YK9nJ^dya_ut&?EVKUPRfC7To6Ux?BLyaN-y* z)oHEpX%V)+-oC+O3*z^3YNb~Gb&K^vo`=hGE^u)7;G+{^QH;^<-Lss$(5&n7@n3|T z>Lzk!&)(pTRLjwd5ft?<-Sa5qrkniBPpGpj;sMq1%wZ%`P4+Kei$HwIAOmpuKg2zI!^ItPW7+3MEiFSRvxy`PruKAn>HY1uZ|j@C?W22^?0YXsPq4t1gIoBdjNoHDs6nQyqa zF_27XbzE6@G;N-~Tsb6^oN%bCt{zlTQSsqw0U`TA=%k0H=SRvSr5W@M63 zJe;1OPsj{^m=6LIvP@lQlb_!eV%4~jzrPA>`|{vv<0%s4H|~KyIO$~8HE6c6EjIW$ zl3;W@LjL8;&~I)(oHDEZQLy1bCeNmeyzc89H_e>ye*E}RHt8-THVtd?o|qV%wpJ@p zTUaD!VMeatD9On|B%ich?mzc2gl+Oy)Da+f zUo|aW9ek*WnWcKS@3@50ViC}fuDYD+dhy`Y=P+oJn)aS>;v z`#xK<$hAvhQio;f(Ko4*6ca02s! zNcE^mdu9#h<$WwV2nzhN)o9b+M~2q?kV9=@_ijJ7c3I|MFM#9HPc(!Vr48Z-e%vY^ z4-Aq&(_!;f%qw;4rhipsoj)7-aJ6kIcI!MG=5y2ZQ1haw2eLYSctTSPChv0lAx(dC zbWL_htxJ0Pj4l;6Nu~S$kF&1;svYEmME;9kC?PM(AL3tJqNMUL zKkwZ2_^BuWS(-+EARG0BOdEN-&g5or8$4LE*Z6X1Z{V{hXlj(0ltOaB1(Ulj7m7r; z*Fgp?rAKFXC8T%TJWQph4-H1mo)&T=>IjboCZJa>i+EOyThF56S+7LzkADMU`Iyh( z(@Tj3%R6x7KBZxn6(Xc4fw70->yee)Nj=HctxC|{`G9K6f#YJ!uhJ73^*O}yWfVi9 zb^ebYS;wBHBK6?~^W5$m0U}}*H0W;CMURj)z1+$lvy6M}r14$F?xw6?H?xJO2`R9u z>FT04>5$=_y)PD5kCWlbVKz#W54yQJy9y{f;_FZN9N&tCac?;4LMAK`u>xM%Y6_Ih zmQqRy7O=qu$>ZCsI7hX)?x{O)?{s-x8#5Go_)VRa)R$!#mM?=~ZO011$Y{LL);b?u zbg5~w8Sw=G(!1{_e6o6n&Wv}kA%c@rq0hs7y=C1vD}495zp@5)uEMV6?$ZNi4+4H7 zr`6b+7F5X8-RzP3a3uELJxhfGEC1%rkPGco2((~t*y8@+B`zwouK{9t61LWJJaOmdj)H^$8zM}8Z za7{bIvw_}6ejXq1t`wdgtmQB?-Fclh$XqYs$(7D@sebkXkpK*T?FiD4=bMnO7KddJ z?+dpX^3d#Uyb(!*<_1WkOixw;y;+A4ft^Q=0#R}Wxt?J$j|+QSp^$p{5|6A@n35*^ zB(Yz98aikUSPqDcZkHSi7rd+AjL7K=)r1OoMd?Sc;L!|Cx-7U?H%D@Y&8j@-le`;d zD{5=;&8i5oLa3R4m3`oNE2LePPL8Yh#)A6K!oO#*(E0t9gwY?ErP{M;Fg`Kr>jxu2 zmMZ7HM;Blx5B^!`N0BTA9h2o6MubRXm{5w9hdeTwSKn_I8t7`JBgQZ~qtaBgcBHiA~IXw+`{n+f^~uy3nr%bb zECKI^;*BUbtU8%%lW=ysTGV0Ij>zq*h&X-R;HFyy5%Rl{ zk}W%4;`17>E1tkIit=d-Q!_JhU@BUrA0){J{`m3w%ea}5iAncc5BF#4BZ3ZnGZx&9 zm%j?`*DMPLi2F3Tor&kKx$jE1K`U~#fe5T))8Uw_b>98ZWh9N40vObJrHV(bw#|=B zj$hQe&=bVP#W5m1r_S3&KwxP`O=xnP)78iHH%}KeFcuC2qI)1KT62X3!mwYrFk6R|6(Um%&Rw*-Rl zTUR3*qdH^9XB7fEPn+@7MbBtyxO`=l*k1qibW()!*r^sTkxGrCMd&hC5D%T5ooH|{ zXlQ7e4YN1(OGFP~tiJ2h^%qZVLR%vq8W!$$oUEpYjdVL(_jAGDe@V^SaTg@0BGfN? zfE({iIVP-Xn-yjFfuaA{Q4CoKR=)2_FhRIO%5)Z)!a!fE?N_%JV|L*^T(6f?~dAV5o1xX zTy)zPg0$8Sq8Uf~g#AJA3=a;&_>Z zCR?4b{&$ux{x+e9bN|mP=1J2{af!n-gLelj0-oK7i!4#l$#_3T+k7zxVn&_5v4o$@ z54kI#J94(ZYiRR*HRg7EMFfG|ZRg^uT@hnj@l3zXItb@7z3w5lQD5EcfecB*C^%bg zIBK?558dudu2~kO*fl)4+iPi>9Xam#X{W5JN=ZQh(;Y>2=CmBpuN7G4CFp@k!_q{A z(ZxLUo2&r}cSAY?elZCPNuyUW$;qL8eKKq7>nlxX3*SsKJh~9IFboc-TrdHiXWZa7DK39R)V2Cc~^OS95XbH@CDw^-Q*2VXD6nD-K8Zi=;Lji9nDG-8$5B=%oP8 zT(E^-#p^>EuTXdjfn0gz9ici4$ZJS=dygj5n|y)s;LSS=$=VsK)L=T@n@0tPzqRShWHgmjsmTy2v@!@xsV7-p6y6bL z7r>0Mv9Zj?#yL$T02$wc(CsC};QrWeuNHfgVK#YUb&S8~;_4=%JuD@^6LC8u8(&M> zL%k#NWI)#Q%kma$i;=GJw$#v^8f`D;->59H9d2@ZTs2Ev~3 zi4niaaUn&;qVuNmp-X+_k3g<@k}}vLqDrpFY$Z7yiB?4nr)Y^jmVpbZbv6nZSS;!G zvx@ls4}!?OaU0FO_CH;V-9qQLEbaLZh|=`Rp1j?iTr6`adqZs-nJ8!PU)TRm7=Pg1 z0zQGiqlTDZ>O7Eg+e4A+^+(D2rv$y z#ij$lgM&k>9xM3HEG$H;tE=l77gUU+ zHAQHIBNoY2drFQwuU`z&zs-I@H1Dfd*wWvgNCetwi56B0ChNGHUP~xFYEoAx^gGRK zElZwNvj&2sm!GEU2AooaY|Zho9|xxXJhZ|)(5RLOef#p0{G`e?Kc3gM$|GFb(8F#j zgzMdH(rdj=%IhMtG^INY$W*<2NXzXzF7^aL{~WG2hm%UQ&|jw(U7F-|)(Orto4juv z#%deMmSD4!WRi)m5M20KH>Ap;@>F2FR}Jz-*zqys;O_Ro&5+iRr0MG0J`AMTG0C?0 zqU&Req-vilEr1btc=+Kh2Ras(?qB0)xI~3TMbF>8dpc35?x)@0lvP~JOm4^uPNv$4 z@JO`>OD-pqZv^eZNZ};|(O!9<0OtE3y7r2eGI^B>%J4CycHZ>+*ULMMsX<4LquJw%ztKkhT6(oG* zsN>sQ&niuwkG^eg`)<&%nM%ZxSZ861O5m^#^QV;8~cS&zrDLXYso1ovHsqz zQL5)N+xZT%Ph;pYEfG@=lmrkIzf&eBCf3s?gmW|riTNFns;a6sH#ZZ1EZQ%(!&lbS zxN%7?FE6`5i#rSJMevPtBikpbo7WiFZwYIg(J^p+dtS@$)Q=Q0VTN@2n@*^bK!D^Y)4jF;zX}eCl?4{a&lZ)8l*h3t8EY zz=uRy#b-|J+%IUw%o7Oel?F&p{CBI+R<6g>--Q(Ay_jZrQ=FNV)mCzvLdPQFDK7pX zG%PIO>vTQ_EV&kS`=qXy5EGkS!iTg$BgTuv4b?zz)87(Vm`E?(V4ith>B=L%-}9%v zqf&^VPJZjVkw-~)iaEE{O!*z%3XcE;mW($++19bX=rGeC->(Y@NRBym?ssa-tJVq#142~&mLnKoy6|--O`Q8kM5eR zd&JEgVQ%GKyDMO)k%Rg=9VhAvM%j;qE(ZcvMm@T^b0X!N$4yI-BP8 zGdPWLchuQb-)xHd!#5T$kpfzTB8P?=RDbVXofDIKoWO3%&)~w$R@2(g7;Fy&G?!OY zyi!*7mxHk1=!uM)RYCXf|L{qt!Z_k(loH@!xfE{Xkaf}4KDA^dTBDH9qSEgCl=0Tj zZLVK0lPglkQ}B8|ZO@qVW$i>k2r-Sv3XmihG$d*NF*$=(f%!^QnioKT|7YQ#;Gde9 z)FFnM!Jo~(KbN3dIdlgPt{gWkQV#<}_DMOr0mNI=AMm36}?&oo{ ztZ_5#;*!Ebhx+E699RTD80gkeRptqcQ3XlzUCAIlPh9cQ5ajKe%M~D|@HV+k^Og$6 z)r{oH?XaThc7iwUq_f^n@Inri?Qs0Wgqd7C>D^TAA~WCNPr+ zef^1c&`>nk-K9~^D2v6}*Z`*F`^O93iv`!~mEkwM2h%h)v(&xRQ`d7?7CL1{8XAvl zIigSDeKv=)oYrVPl}&`?v0=DuDYf1}%E-GKBvQXYZ`v-AypzS>tmfD!YeYU%xp zU^!Wz*ZD@Q!NK-$BWPFw667vASZlpe;dLkim=}XCDHgdqvebsVxLwc1uDVc;y{?mI ze@!N+eggjsC3x92^S;8vhlL|aR@}g5f1wFVM^;wMf3^^TnTiR9WU3Zqjc%2?o|r+Z zaS?7!KgX02Mj!+P1bitfa(vM>vxw@Z8Jw@d8u1wy`%iI8LZV`L^HX6%MX#ynx}^tL4_YZ14BTD zy`7zZXYgT6!jVAH5OQX83UOrOYr|`SGyD%**(*=4o zSRwtEr*ONQqIL?8ufBc6N4(8XCX27ogO(eL}~~9N1~l27Nij zVKOqhctLEt)IP7(2kOz&}vHw=9R)2pw4|AGSz_tH}ukgHJEon(C*ZLXQKHO zk5Q8{t!zWlt149h)CbN>(4f_AKVxGFf0aWYkj?t{B)_St zve;FQ=N27n`HE5j<6XLDkzk<0U zG#61+nBAWNa^{DJ>&Ly(oR!JCxwbjz_I~vPvpO2l>xb1D87+|~E!P}`B~CflCmSD< z*cVw=i0DvIP@uD$q3>~8YV#BSp-34`E-Xw6qL>wAj7s6EfzIitB9Y+QE9=j^)vmQ< zxv#fsgj`_>{!Rtq%^P|uyZG(~W&6FEJgLFhL$!}|Z6E?GwRjAtv7S~Js*uyt6Ep1^ zyE`<(Gfgr3xjXGg_-Lh6Cc`Z%l#-6LyUkE~n~<@jd)IAZ>SEor*z)=E(v_2w zQx8%-y2{~xUPnt!o%!Vp5tNEArxLHH-N-$>b)iJc!)EahK zN;P~Ezp!dGSc!FFQr)Un4L(g$x9#wL<7rip*r!e!mD8=E2u@I4th5BAJ3IumXwI>- zYhFKi%nw(}4_vPh4*Q0-6;(#8h^h*2$g z43uFeICPCMswLsWO*w4C>DGwde0V68B%>@&PK`CvW2x{jyk;G`ca<|+j*Y*MG?a!^+F_p5cj@GtoCRDZIULRI{gr-VU55C~$Pchdb^-dCe1IeB?fyejjP z4F>x&RWD6n>T##MQdM0qk5DaetSipU^cE;a+(FITa^TO4$1r3|84!20aCaAk-F#O2 z1rGpy8%L1M$|l*|ZPpXY6=E??k3F?|R+n{*M|XEuHs=TW2x~Cop6_02MULy9Lfy~ zTV{M`(8r($f?xZ8qKB*r$3Y6(;;DPpNzn_kAh{ydG!PlDJSi2qu-&utg;4P6^V0&R z9xcjF;GCZAKHW(F;Hc}gG@J75TyvcN`b42%KLt(5wGiH`KqDxAh&vlx-a@?qnw;__ zIV-_1pkb%VRej=zeg|ymRXs3asox*3V`Rb|iDAw1jbCN5c}qQu`=sH$d2m~zB!8M! zyO93T(NUIa0f8X;)T*+!_U_o8J|hT4+E`?RGJIgD&@$2Q$?+^`WP$tm_<;}_{5?gy znplRJ+p>J7$%28|S09D=Rso;C8qwxsodi9#l#kmkggrqzEheq5f3*x%)OxY$(-;8O znw!X*Mdz>FOgCjHDqKwGyBUK5LZ_xp9)9inuKPt6%a@5?Y?OEJgk#9=PA zpX~o(Amn#5RzzF0k{S*Cn5Hoj9M*VdjC;HF^A{VLn|d-1 zXf~Th_*xd`M0|e&J%ww&Q{ITED6)!;eDN&30$*f6%mLzA-Xo?RfJu7~#upZ3r4i{NWnS>?ndvCH|jjdITX*=-UJhwJ2`G@ssZ zbJ~ps-(FN|UgvzosytakTEE@#yeJ|1=kp1)HA4g1?V}6Kt=M5$Y1oLTYdh0n^YTMf z!0o-%oi0n~86a)pJXsGx{xjbcHcs5j|kG4Q4cD{N6 zXuW$jk(fbjzE^usc#D@mnr~qhP~VN{P#Hi85H+MCUe2g?a=gsOL-Ha+1Wztf8U$gW zvA5G{6~*B6&e+4|no^@dP&08e43*a1^Ohe%{(|=K>bC4QuvcyWrL;73ve=6kA&M~D zk!p-xT@ge{;b|1M5FM-#a<{|h-_^@Iemc<_!D?x063u8NL#E`-DeiO6eh1YK1Ki$C zc(HeyS^tkuAk;-fh7EzHAgrlsljR4Enq+vqSk$CB-fvWR$7^%_OO5opl-O3O_xG}2~JeESM zH7;KQ`5dV}Vph^#bkzsf%02p^c*;F{kVMvgmZ zE-N8VJ|7f|ri}d%0vzV)m_BnX=_vJ1U-@g2$BTys^SR}P!%+Kpe1@`v5Kx_H3 z0`xr8SW6MU`Kf{6V;X~kiV8^nm5$C{ND@b_+fCof0o(ZSz5JjBAw)X0*MRb{vEVs47T}c z7Th>c>sV9_cg?-Tz}eK|X`k;V(2k}55?#l7x-eBfw#^3B0y8WEinblW;Ow*ZwO3c& zKYmzA_B(Ruc)fq>%udOY_{&U{7Gs_xWq`D1y-bY}qNRDkTFnvm50k|LiUG3ni_qJ4 zBF!IZR{emIo`)DDT*Cr&`07c+KvS;DyMd5OCST9!<4DX2b#@(sO{^`qSV&@ z@g^5Ka+n#@%dpPruU?W{!a^FwDTgVcN8pY-2QBFv%R1}k+sbXRKJoRhrdjEJq=PE2 z8X*TMYgEYNmci$Hzg@;Wr(q!H11Vt#UGWaVA2n)Ph89Gew)x?qkD%uUvtRM1QC?YH zJ!y2v?Q9RK>|yzzCH`4QOZi*O+TsPYd{$YRk{0u+itNk0mB`3;O|g>e*oLFJ2IJS; z4KMpT&yfen^qwAfeivs8eWXX#BSV&r8=S7Qp;QReEFWs;@@lMyPp`4G@hUDr$4y~1 zXbtz5q?$MTG~f1~zFqzg_b;VbqB*@HaU!9z{g$DF^(EGGewNS>%P{he#Eiqh-Gw1X{MQ?efTBUn@RA^51^Ck$n zeeW|67V15kbv^H97e)yvGO1Q$G=}88dgAQ|Iam&omXmu9P;+!w7W&Ex)bs@Z zsSbR)xYr1N_cn(7l{B3128~!cG5Y&CEd(Q!h)F-k>aY-$ZjdC}xWYu1BM*8Ln;iHS z+!vLP-6Al9R;Q089ucyPnpKIjt1{vq;aogb)zAq2@#6>bd|qvBqR)}o-w1_?IRaZy zT#TSs(8tKavf=wm!cb3~yR}HSg*2hWD=f#v4TCzGja;IG&({>;@#DwKW8=c^;|BUr zLlqqSAhb=-d)fj4x^-GYuNup+Srzz>t+#&vzHa#0X~>gw2;_@0{pnsBg=`N3bQdEZ z)~CL@ETKE5vn1q5|U|{^!1Q$>_{xL3Y8R9KT=2hI;*@+R>Ic&-ay3PH_-5Wfk zP6^)SRgAS>0OMbWL`VJF+VUAOg@aIEoZIhiZi?#bQ}p%qmA)ILU0Yul&r)=8&{ef` z4U)|9(J67(7z;Bd1v$Aki7-Umj{FRX`IZI;IvDrIYg0HgYU6X0b}z59e)`PVae1J_HnzZhqSA-KQrqHUK)Vsi`j6XReGqLC?VGf`v09C}O-{zv56iML$}w>NN} zzxSVHdh!#n6sh@+E9A1W3a=k;jiULIv8D_Fapga5_EX(R2Mb2js*2L0?Lp5^yM)=K z4-ajE(8;=fuAAfUkcfXVfcNdV&QXv^r3yBdQCBB$wR&iHFoD!gHe_;NJ%Sf$#Hnei zgFuGIVKwgr3}w*QD>w$P66mOX#SVunwnENVd|#ZaJO8G4cv51JCHvrH^r?$nT3b8< zC&L%zugEn{!&?r(U$y=kFNpr|VaZ`W>se6Zhm#my2up~>ho*DNbw>3SI|1x+nBtUJ&E?&L7?=Akw=ni&OCRXV%Wtj z{=;N`?0Thv;k3rkUrKLaroI}VdAL8i5*7|J8O1KUsH0K4QD)a9RBU~nuZ*pe__AaY zTE#M}(x@#F&k}v{0vXb($0`btw01NcSv?u6##*aumncD>q!zh#q9V$eCE7(;f&vpG zK$6_Wlit^WOdlSyfi#HO!Do=HCWT;=cZFhg_lBXH7zW~NV3F4wLYZx8XqBF7I2ci!WBU2qpN%frlpzm|$tI_G_|_x9?R z0&7UhwC@aqIHeB)+I$c*m8x;+w5F(bzIY>%YVtx&x~B&DaYoyb5@w_5&oPELt$?Sh z2CZ}O+XGIJ>Q6gfColyS_(b(Bw=kLYFuZ%iUt4d_B1ylu*V0*N#)hQSARLB0)1}~N zM;nP=hE`MlDwvWHxA+IJBjY_tF?MZQcy~zG8t=};$k?&aAguDzZ6fJcX@e?7CFp82+GV;Tk z*BT7@1`=Q)rM1Xh)Nfs@g}%ASWf^rCI8;(oId|w1m^)3p@dw`>@dceFr2BsTf_cVJ zdh(w6__-lR6tv78a41baI> z@@Q#AO-)qbAtEHHsEr1UD-K!!BFW@pU8ejPvzv^B)~QOzPRO1z-}oN;*|TSx+uPqxwkJnMN9|c`hi3z`T5eeU zdsL9*wA=Ll>L$`w>27#5-Rp|}laY}TwOSjB?CfmbbtGV@AP@&D5u7goyf^Q3W>NRvf&|DI;+?LT?T2wj3|FpN8?>`$Y!1J<~0cXF`F@ zQtIeOHMc_ECtYsgfaq&$5Vj^^l@$X3)!DVR_{J3k8b!Fdxw&X79#aLOPjVU?wM$ zhNfnKWgyEff$GaAEl30)5?J&ALP|1|1)c2SMRgBBPP}Ria%KDrz4SVFEG9+~H*ZJN zgPRh<9|!nTQ9Hu793&d=T@H8xYt~$ALo!+aeK^g+SbPF?C$Fu$yBoDvtyMKE>7NQ8 z^5YcnbZ_6jrDJ52(AFk_m99Vm5s>fKyt!%mDKD>LB~TEHkTA5el9N%Z7Gq;D?HkXc zJ8Y{{{aV_-E9R|>Fg7zlW_!2|Ahqg_q|#hFC8eZRxAHQKDdPp%o%gf=`G3mIU0&;r z74O`UP9dFG7E?Wpa6Z6k!D%}pYb!nESl(Z7_M_bVWm$w)PFiIUAOpuYX`akAr~?zZ zZK*OE83JzkG0|6-NUv|kY7R!c5|GQwAe*C!54z2PJ3AJ1I4BNgoWX~F8{5Sv-mmk) zW2Av3AJi#($DN|jo-|dxB&u^Lb@RYn#E~cB?A_6pqu`w~Js(m!c zJ&A7XNhZTnQ*_Gx3%BbJ0;#fVH-~uv6eGDE!_P(PhAyvTi(9KhOwTp^14}I9${Cbf z%caz~h=N@&y#rfdPw-ORI#8~pj~~p6$L$0O=X_P*TJ>8^$P{=#zI92R1otcNrXZ?N znLYq~m*k!9W=JvOhV@&X2ILUq#g@lPQv)gm?4>6@;fJr#xzXH9>)2}#3#o@3SJhC_ zvSZoR&20h0{Z6Z<#nSPYT(_TaGD=cXQgBE}TM~x}>G=}NPT4~jyJ&m`nj_O7dpO%j zq-#EdV?6SwPoMUDUwfLs`93QvtG&@up)ay>>>1}1}t(d@(yY(EOg4?0Nog7HcDqH0^X}tZkSJeIc)*JUA@d9#8&m%H@gwj2pg&_oFF(8Ya##kEh?JBR6&01APu9~in`QCi(^C`` z8!Dy~q~rw7W%N?$FkuQlZ0_s6Ogkt_!3asIAzo@VL-g6>KZnZXwhs?~7-lyD`3*PZ zWh9=b5hhNFA;^OKd(EY1)mY&we5t`c)-e-PuMO4AX$)oVMx7pinW zt34|$%$Kfa>Mi0*1G&4Y3r)v7$s#j@?qITB^izZ;HiutXkXReO+hwQP4f1NQV&3S` zaWKN?7O8=ooiH-cCvL$^dUSDdF;!)bcY6>d0^R(f{RDuuK^Z=6EHXeTtPnVe9($6% zWrqP9EUy^&3E)&rTqRhG$K6pPx3$9s3GUb+g+E76jFvu{at#d#3|vVvNnd{2!?B>KGVtP8*JZ!ADE&rC(ycvN4^HHAb1GZe7=IJsW2TaR*jlO{z?L; z9ftv?Q)X_jIUIBJeco3P%qW8)~fqC?Jp6%Ppw*~5b!m2h4cfQ zC*NLWPDx?Je283{Qbw>2RL(GyJb9`q;5!mB1uRlyHLc%xDTip0D%8pGr#*rk{3<9x zi7N+aE}lC7LRwn%)vM^y2j*)6i9jy? zkHIU!JHiDJ3(-zZ2llS6{Mbxuk3qbPm;aQvCbIIH?fb;Ift2l?Mg=5^%`Y>uX0tNc zO-~@c<%>{w*L#S>pFN9CPmjcYV$pjyyQt;O_0w%s<75MM)sh~r`!gjk_v49Zn7L+K z_!?_`?U;(zreEp;Ztz9oRt1@F!(jKfwklLw31=nWv_>+~onpcby^*bTP5nGrH7L9@ z3BtU5+LEjAG9L##KWx%dEj6dlnkJto~~_-LTZ*8!N9P=cT=TRr~etZS4W51hT(F z>+CluX=tAFGQF?8fCD*7fDe2x44)L;-(G9qe~;&ft48hh!8dfnTX#~^80YU9B4n@g zafF0~s@WzlbBli2<3`lvQv+U>zJ8rWw!gdAUpwze01yQpLHms#p|%)9!~-1E!Vldc z{%}mOmDrP`&MYvq6Ym1bv^mY#irHeymS0uJ`r&CVyJt%$A3<>%*%i=WCnV=v_)tLqw-q{3TxWbLc*+g`O4FN2^dj3;8A zJv)YZs2etXP<3>Ix~_>ywEN*xgmFJ?tE%Ok{gKY^s;kcpeUoJj`p;J`kV2!W&a(oL zu(~fS9bL$0&JOw9ZQJ-lYJkk2YBWGjms2qEb`Q_nMO;~3&3c{xAti<3_+#$jmIFUU zowlOl5_j)cWqRl@GBTom{CEvmdU-hOS(|IUPn<@ zlEc9aSPK5)hCBlzn$3B65Qyp<%YxCxnUS5iN)stZu|#aE0QY93A9M@`h87`G0oMz= zx2ctm7Q1>D6*r6X=Fb%}kSuu$&#i{FvmLLw;j%a3k;q3XI%FqPeAI)xcGgrEHHp>?>*i-Q)B3FG}y; zHr-e<6xLWR$=}sfx3tt)wYr|65;`{%;mpfvEwqq*HMCRZ`^r^gh~>;^-)`Yy)%{}v z-krzcuDk5Xn_aY`M>SQ8JZ3q!WDM2IqHFGOfa;P3(8bv7_C`I|r;jDT^B@BYS@HX1 za&j^!D+>k|!oGKVq$1npn$U#456q3wj1FZqQdmAgge0xeeUGhxrj;k_3iG%T3k`+!{Z^-D;qAiUby4Vf12UJD&{B68 zVTJUj16u(Ck3jQk@Oq{r-S+4H-t>TT$yiG6fhGzT^lw!XnIojA4 zU)GO5uD0u@pJt^MeK$VxUqJmWB-;}+i*Dznudk1WB!}Alm1Uc0h(U1gxH>BjZ&M$M zPYMHSY$cSs^2ME8S}R)6zrogy&IVTNkW+F7i>1PxHdjWfR2g#N+R2Xbr{6r7it#w} zShPlu)Qn@m8bb8#-amX-V(f^sb}*+t-*;&2ymU^J@Vtq%gX1MOu>DxTxMp0hJ&Bch zfQyTZl0bunEPQ)z$SlqkdV|*aEa=huG0#>bcI5FgK0ZF^sF--X7P=0JJp5alM{;<1 z!k<=;C8_?1eK^b!KUCwD*x*LJv%Ptx*U|6p$0wmP)DgzT{uz^pzPJSE@#Bc3%8Bh0 zXvryMK#>lokT>1<-*KM3nbiMtoTv1?(4T1OQXzQ>X24LaxKL4||5cJK zdlMpHbB*=L-3b|TK-SVjWZ#f+dxZ@Ak+En~57eIj(Z+)HQBCaCjg6@=jZt%RP}Tm2 zlEx+`R?b@Pnv}{_3dY+F%8>R0)EK)4(*y__-{B%I(L^JaSdJauuSHFzRP z8J$^Pjs+BiMv>F^#Pzi`peZWQOQQaB0O{1$XxDTSy)V3bpCrLrf#_Hx^AYQ}#uG|F4@Mg%$5OoVga}%RmD+E}7phkv-0!8A^y1r*$SyGW(0xEkCRafa3#|%7 z@WT+pd83O+n3>Vb$jGFEpp6f{);MUS?x5`w&HwmUDHe3Qk`CQ_L6W0I?Id^_nSdkt0`xB z_ZAKVGqWTx*k}l_4*VqCR&za>=ScqqSWih)CFMiiRG#HllLUyUslpN+6(4TUqPtJq zZ>%ykGzdnB1a|$RM9q^SKGhBlMqGrBAXW;ZrHK;VsQ$^8&XEcsz_|Dr_d}_E|47?q zL<7o59?E3186H*98wYkz+f4>eou-5ja!?cwrE!r<+j2&Ay}-_WjodoXJ!ZuIUYW+6 zJxPx{1!f8tCMRD-Q5t+Shd1%`6!zPI2lmITiVz?kT40p^ zKec#FA=WC52#}l5oyDuGaRCe|-oHaaF<%)Po+$(E5A?j5Li&HnC0qVo#ipdpa4fz+ zxV#MdymOen9(bX0V&UN-L`X=;3L#(J6VZi^n3R{ZE5CUI3jzHG;ib{vRV~qp006$X z#<~6PfQ0aN-ks+IT`g9*=~bZ$PMC~ayQ0O$+w^o&{0K>iXbhR4Zis|0I1KuRJK%Rf zV%~#*W%P5PW#eQ5#tYt{qWWMCaR2Y53>CkBhF${a${h5kT!@2GzI{k8#{izkL=m*P zDXtQIoNO&tgb#FxYaczQ$#QcG-W4C^J`{2a|7FLI=7`v~jdE!N4Dn0T#~n}I8mW`~ z1u!uO=>82u6A*?GVh7j&OMjd((b4Hap6W?JK4=ypX_i9l>gMjp?&p@j1=-eJ5F)q* zVSH8dAukITqqrYU`vfpYs3wrj#T;%qYJ&rsH4+jq0pP|`{$Gpf!K)F$!H_bw@4^+F z3~c`y@hNOzR(->3~D1teH-U!M#<8bVZT zorI5ff5wl(QjaSq=u2@TA|gBw-30^$(maKocJQmM7b9U2ABDfq`23j``upxkl2s!4 zdj^;5_f*r-iL{)pUcT7K=x(|0Z_$IkQ8Yh4DTZy!MbUV%J0&@}@wOgXl)+CyIc57Y zVoG~F1KRUJ-2KQ2f?h!)7d{#q$^fBk&+AqJaKS&X>RZDL37&6o1~~owXJ$=V873k+ zDKUq>!}bIdCpWk2Px2UORShY7WYu_kqUg)lufF4Eoqcf((W$B7;6^{j#p%yhTb8OZ z#(KJ6B@#D9E!I2s7nBqB}YAPxzi2yDH zXI5IVY4c60q>F7+v7Zu&WocB z7*Txl4ENt5tmz_`n^ejwD#$NXug-@C2b~1c85p2_16QUN?s0XBJPUnxX68qr33*+Q zHxrK@Vq!+8-B%KyOL#Xo1C`g@i(`WTae&!0x0aGMqF%GBgN{JI7A?rn_mQQ=eiXlx zN6o{{T~AG)oSb}6k#U2jTJRVi9zHlM?3tY0!-e-7BnjPBYK-U8L!N;kC=0dfunJU* z#Fdn=ACU?MLl>f*pOkp*ezbwHc>El6CpfmIc+?lPhevMe_L;bI2unl?wZBSk*7j=7k4#*tO^#0x{$lj%; zHb3bXFT`HG!lb04dZnb~2Y#3deG%{JPSUVFA4oe+!iPreN&TyiPEOfhzDQ41gD{77 zJ@|Y8%X8@NR!glgYK*uzxVQ%6UsWI$x-Q}JytCc*s;aoE#abbQgYwYL3)7qzz*VAc zbQ=J^Bn}vV%FBZ-rLiU{2nYi=?zpWAUCSpR;5N5bErJ}=gK;{AP^eA&+-ybg5k8cR zv(*c*Tg4#f2hToz{+#{kQ^$K!lVCc&N}Yw*!IBub8R)7s^U31p zKqyys5X)R8fJxrvM0N=oZ}s1O#dgPE7Rl^mD%Ex7?JQ@&?!$=m^E=XE{Npi{d}?-1S>1R*2i6V-uXEPmG=_ErFcc#iCc(Hw!QYJxLa!NOk*1@=|ltjNRXJ0aC1++rTC6 zQ&DAbHl))4I3swi?FWBPfVd8R`4|b)whzV&t+snXPccstV=5> zIOl8F3zAIjt@Xx2mh6(V)EFftB?D*UzDvCs3hp%MF)Dx2R1Gqf3ZMzdRKwyg@)FRP z8dgrR*dM>Vbk$!Z)~>R&?ze4$-zMhb=0U2KiAAT;$96(++}aHsvf*uX;f?l@P4?L~deV)yc6J)A;Ya*Z zvw1HojVS+w|9NwEHf3u4Oi+miqvypn9*Yj+v3gptW{p)uox*HMigfv;PQKgkwO+Q2 zD38Kvud_|h>eEG!7TbyO@qnHl=^A9!t5nuY)cB7daiY$GL@l&ifky+NDhvo7y0x2V zB2L>RrOEhq^_#CC4vBefT6ej*xVXg2JLkn_Zoa1pyxDxX(Nm_IT7w?Cdqa&*DoCdc zhY5xAHokV}f2MMj=n8weWshiQyp;lIX605UU$wSoR1=kvo-X{hWzwL`r3kO0$+1mf zzY#VOt+&m>W11=g$DnO$FyXx!DLGO?Z z3lEp@@@kn?ipv{aA4nM)9wukJesH?Zrk%!-RFNRP(G(6loq_9}Ou?i*4LYy@_655&Cl< zHJzQE`ak>P0P#t@e_uCi2?#+urtB2OvYYL#Ny+OB>BlufY!>^IJDXEwhAy`k8vz>$ zAfrH6C7e>99%}072=BR6dQq%ejj&xA@-si;owg+;AP4~>HPqU0Z6TR5iXa)4FiEfcb-xP7vVz?&(R49JX@ngO0Qqr zocvO$2}6l+%rx~9mbjNd?=|)Hvr0|pPIqTP%X)*;KwrEHIPNd(EHmtWly}1l(thf5 zMFlo+wjiaTWQ##SuvK0O#c03M`ZXU77xm?*LnH9j@PYvov!w^M}rc{_}dlJYmp$;k;F1H(5Mh*ohN z9c$@Z82D6>MNyA-REsnMzJ8?#;F$${DnLc(`iECQya5FdsaC=`+nM&;ovjg|QNU%< z39ni7Bmx?z!Fk`wb*`~dP``7t7ch1^5G7@9XI3B{_(+B$J3TeZJ)*HG?*X#$IU_Fg z)#r39EO^bSHXqZ|Biq}>6R0;LNd!v4G5T85xt~5|e)(eBuKOA~@hxX$3G}7>cmaS@ zp!;lOVyqS#32Ln7#Z^?|Myr7gk~i!T-rH4a0ECXbva)i&40)l62)LW}^O~rQ{LA)l zWsWd_wsZcr5?J5Fa4-@-)RMA?rSx>h3fJ6k<#0ws&e`2lrl8TIna2*pWfXtQ2gZ!(!jug=j_qNpLr6zbHssT9|P1{JcSTZ zF}sN{G3(m=8R6$(R$K~%qiS{)ye^fNmj(~@dOer8Ct#E%CA(@{>>D>YC&UUGU^}j8 zUI|Xql8c0&-d7Zt_Y|NBY7?30bb8Y_YWsH4t9zz~q&p(-${I9d_wFOXX{ScE3-Z&;K7B6~QxoeG1?zhIs~=!RY{e#Oinl-S+}z0|@EkIl```B20gg z^dWByC?8_Jf`q~z#7M(Uhp`w8#?Ua=a8M8}&CJXUPyB#ub<#kMC;|Nz5D*}~Upws@ z%5pzRV~yk=(-myY0(_w4;n}SvH1Yo!LU+6dFYLcPHl`f*zZJ3I;Lphal#{^MsQ ze=H}wp97}&K_alUn_F*}{poA$4YoffvqJU%Ya*rp{gZdK{(G~~$6^2-a(S|CdvRIA z>spN{hD87?E&;9e`_eg!KU%|wae@FD)UL`ngoQuI^&uU z+Td$PfB8oTZL_{_ip=ufE75R0*q;&wo}~IDiv`eVAo%<-^RUnvp3w>oE{EAl>`w9$ z_|;ZDo#nY<_{7k*M{xmA3h1;I;vL>_7u?fw@3w`vft0It*orx@2WNMox#N@G2qCyX zAo;PYtE(O-Aq?aN8saNaJ!s)%e`ae?FPaIklmau}l_uCu&%9@8lO`_<}Fl~yp>U^W4F_$-rF77%qF+jMJ z8IzE&;Bi$e+DkUKuA`Jr49fAT42%rTz0pZgx;nG0MIrr6rao&c*i{GKN)Ox$`c`rDYI59u)}V_0c{ zB^`c*5^)EtjRqO~P~YuRY|y~L?C9v|b+E+uuN23;bQQY!XO_=y&|);nJi;!id-> z_^2Ty!9zW>@V@vSAGBj)a&d8SjDf%OgM}PQL8W)sCNXzd3SdRys1^RY+x0NvM%Y~q zg=aWmf&h6wrS1|S*^kjJQQeJwL5+P=bfCG|l$PEOq=sEsRa^0ssa(al_TZ!kC9fRt zF`-1x6(}@8X*bTsS9w40y2cVw$wPhQXPkQv<+^pPd0ho1mIQm?*#PH~pTPof4WPTq zq-yN9I1*?nk-n@T+X#Qec5B($`8Hr)C9pG3{PYKJ^IS`UIyHmQ@XSm&C?odS2*WXm7nY25#)T*U{4hHJx(ZXgA_{hcwSFBqp*I@PjU}GnPrmK%_mt;quIK zu7uXzcVM*|GMvLLOdOA*Cnvvu22awp=YuGEq>Yhsg#s4N(UPG^7cEVNi}cQf2c#A3 zjVerSe4=l7c*$M18#99c`~9n%;tBFid~DYVTI-CChR0;2Z`N@LGQPT6bT0F)=-I>gX;Phn z4YvOku;QNSLNT>4@!xi$m+juZo5X^iH1?G~sV**#@Ot!%9;EvArb{0h=EgVuXc~ZA z6kM#x(wULp7l@xGJw|d4LwV4NdA_3<#=Dm{H}@)=6%YL5-6Mf3HZhzBzChr8q!C7{ zPTCB5S9ht=1#i=`SgS7;ER=Bs0g%u#*7%@ zq2?utN^O{JY`A%QtD@g~B`t^rXwimO&p0yw?$bC^(}gdmn&S zbKHkA9p(I{3 z!tZtCL1azyHiA>Q9hBnj;Ly;AOg;uxq1$f@g!U(&z{5~tHArNhO*es@jp|$k7V!gy zi8^~pBEbA>adtbHxk3LSvEWC*Y?F8$mZrUrb`(|H&Q^)BC}XO-u-d}OmLX%eepY^h zl^Dmix?nGPu6T>tRr{nmH}|f4eF{JNi}9TumIHS|O)ahMP1E2KtOt#b!{OYI_6om# zWe_;%6@ys~xnvA0J`46oL0Z=+E&*xC+U?zZbyUO!0JZWTcJPk4M5)A4u-9rZoJtH{wObe zfg>d)B`G5_AD3I#`{gGbcpwJ74ia= zU0t%OZ4V+wK$%F{W0-rAu5UlBj@8IOiN3< zH_k9LHHF@!>So9mACQ`Sl>L0{YttO@_s@_#-Gw!idfj-uAIajm3vYG;wb;zs`nj?) z&I4@hz)R0CuQRiwuBC}x6`{c=!-sx$fdAMm$ z5-;>CY+@L-me^VIii#w}TCR+@FVnx&ZP#5jvOE!1HgUZ5q8X*5$ci;$(!6H9j1IH5 z;6-`g)_apgGJ|l=8I$tg;oHYs(;n`F`+_uM2v2_s#_W0}cy84gWdU!frgca)H}bw= z)j$Cn^+z3?n~st=j`}cU@$~(Ro2G0n_gL<+u(QD1c!}o{*7vIm*S&Pu?=cJSSLY2e zucm0}0DC}$zrmwbF?(Y*~6>{5GG7nih;Qi9@(Jm}xzI?a2wS|FSbHo2dVrphQ z@61bWQMR8jOjeUp4dIJbdFZ?-u{#TB=kkgQU=U`833yLW%$U{i`RV?r)KuoEUpOj< z#S@!+9!Fm(-@8aQ;kc2>-(^`7j=_%P+?Tokt9-$-#`$Pw!G2UAeeMlKQQ{cgO^VL* z4ZF>eQ?jD9`nRiR@JbW2<(_1mgb|b-LM(?OEW5kEq^q_OHGQXeUN(qQ8(o_Pzvg#Y z-SB?L{n)lcVPP9x^O3_++x5!SF6E<0#{#{^6w#a5MtMRrd;8F|;L0~(SprBJA*=VB zPCOcDq-yL=lWZKzR!rm(P5x@kSWQ3n%31lJ*D&f1JP1wTa*42!`IYdEm)w@ms)V1C z-*}l5sZRXIiRBMqs@00>;Dxg~J#G@NDKp{hL@x}fJp#dCe9s<&eo86u{u)M3t$~oG zyKX(zh4-~RxPqct{5|g6#D2d_1e3M7Rf3-?jI?YTj>w^g6(b1ye9j&sWk@mXe!mKO z^z7y2!7Xp*n=lv*E1LY*hP}CoWCF7C5~WF7AB0viBICJS8)tXBMw)r45*_NB zIIqxmGMDyEiv+7Kw1$0~nx%O!i7vfAg|zafw4su@OJ`5>GpZe@(m2lKO$!!$*%rv0 zx~kIfxU_RnuMFLxV`ThvvF5~EhjWkRI_FjhoCSl@+e)`w&23I)!Ey?gV&Hz$N0NxU(0k+5ZBUbMA2smZ6aCSe3mU|EMLqbNXAHU-CWWj9 zrkIU(&VIG!>A}6uch*9-6=7R`U*yk1ehaa>=|0xJn8M0^I#ke?e|o$SR<(7Mx-sx} zyQqII_DWc)KgHB1QxJYBeY?f#lfZ=+-2Hj}CG(K?=x1x;Gmiod6md*q$n`+JBst-D6^$-du@9-G&r4y^ehAZ z`k3G+oEs*Bxm`f}^j;t%-nye(w)+m3Xfq3Qbd^K;9I$OTui%#`f`;DkE$qQwkmz2`rndoiur|C7?MSges*tfk557YZzXqxmId@+^~81 z>;9(*@3yKDmmR0?mOlpbu)X@1UpGonx9l_aeB?5ibt;9k<`IH5zO99uc{kjE`MKIY zznfJ7FmQdc+TjKny;dr(0V4a7r)CpeC7uU&+h5uZ2=5zt_Yz0wK)GpgHQ46(E?N#rq_{Lp8IhbDp?hr9d9#X8|S2;)O{P1kk@N%kJ z=xM3P#B{n-{qg=ReVfz5eU%$zWVUtUo)nCXFF^gNTN+r7-e#wxqx%i71b5C&Pj9hx zQ?>Zw9Qs-S9X-`j@5Rmp6hTI*CZ+M*KcFkpSe}n&s0*Q1XWecfwb8OC~JK^7>e`PFk#SN z^KALS7B36Fq(9>{W%M!U>L|Kc=7*G;oL(#wfK|jsM^gs>d|;0l%2x|V2tmGZNUalp z*5+nyW){~g!WHeNj<^cc_tub-nvEhJ&VEw#$wI8Pa`Pa%mcv9+)e7m z2G85A+YqiRQ9|j}^01~8i>QMV%KD>(lG0KjteH{)X5E0HJpH^=UcKm-!7ScEh+ax1 z^>apVky|alg|*kaY`^U`{nZw6at$YmpU1TNwl#l^JGIfJI+W;5J6Q@yFqrsupkBk; zerZczx_=R=+S!*0K_#-P>_@bSpZVUK+(Pwg4tNi90sLW?_-tW1Zwp^_Y!{d4HRM4M z@{pNq{uvkqCKAUgiVJ&#sSI$5$frzg!uuenrlu%ofd;Yg`T(S=v&XQ;ezNGNsf#?_ zlg0cG!NCIwDmS^0Ay5q?E>iqHvb9fC&!;>5^@%e0UTLT{yZi`ItGstG)A>E zGc%bbdUapGf4|+VT8`CnH&R{XR)k317I{CNXDHv%BS3jGh1%ep8dkSQOoIiD`{<1b zE)0`hd&-B@DG?z1y()pLEp1*al@z)=d)qyCdC0!@@kprH*3kx~OO%r(lh{u+-`U!q zX#75bQP%SsVb0N`@bhXsy~JmFb}UHGSQ8-hR5Ug7hKE(9`ro1x85OJ3-UG8TAoOKmk>*N#VcU37 zvEl5|?nOyOwfg-InNbENOuvJWxK+CUyZ;@k_b-7X6uxN|9;cM#UK{gH!jAii_s^Jv1A??J}RKdc6ksJez{LzMUZBGhGoVNwm zA}s3`k_LHzFk740XJN$~&l=~J?2s{eLh9!)dDqM~lzf(#BdOJBJph?@a&cL|IG$0{ z(n^FjTz`Q%<6|Rf=-=C_@(KIB9JXaXc%VuXcoQZo<=Z@3Rzz)SWAY^={_fd=(Q?LJ zWBMmgfHcT{NUtgxd4@o!=;$y?1(f_V$nRyjk&Qrhx?3>vC3HNnR%`Zb^Iw%qavxq+ zeEA|eG&H1HZJ%kXp{tuhx!TP=6a9=94F-FYMkUEstDO)ZLtQ$yam)h+46M~CgJsy7 zEuduj)mQ!ir^nIAz!xmIlJ1X~2?ci&q-6o-$T_fPrpT-+l4l9mU9sftZQ7Z z`PiGGC9v4W&CLzEp@oHoQRPH66gDgtAs?ZUB*lqZYo5GUhRZrax& zi{x)C!`)NcK%rH;LW!fCm=R00T0Rn;oLrz&>wGF82U(!?$Fy7EBiUC_I?3bHOK}&~ zI+kzNz)SM2M?P7FLBS?5bQS2ct?IKJiZ#OTxY8SUbBszR#%!v_$@?)*Ya)MiJ#Ypt zlXm;_Ti`xqkWckxtx|Q5JX7Q1B%fx*y~kkoziUWEM?+&OJ5dcT4kPCMA`{DWDyXWg zoG~~!$a*+4Jzdz*A>Fv>GVPY_z2i^zngT#WlRtnUSjc-9a{l4odwn#*!g_Fl{Sc72 z#5=oUK^Ui@pV5cHNcfSM?M~zt+nTWAqGx4go%NCI zO5h9*hFmX%0t!Y`T++pY-!fuyQX7>Gx!RWcLAz_%hm@6d)0{-B!^6X0CZ(adwjf)$ zxuL+qZ0C>${}Vkts&(S?xC|EI5*AMVa$P`Jpy5O$H-Z$WQu)Qj3V>+fAi*#{T?3UMy_DuN z-Zylg3(N)N9WMvK{w1p6|cmah5%GZ2Vs6>aUW=jWauZa}ZsVktF!C%;F0Q=V zTK2hG|SlNC?2qxLDmYMyo*8$+n zhw3G&e*a4BAX9E_xk{@>>G>rWR5NE|4BNtTYiiuPE|LU2R6%NV#hq2{_wWymj4YRK zL`aYl*n1t<=;-L2Ekwx=PE2&(g^cnB#q58gP*sb2i=FfR;Zru*aUvlsiQUq2a#@)F z*yhHh-4*dqILTDeudGTwI%1Z)#wI2m`YZv1!&Y2~?qjGp-wOh9@CNozk;1%L0qAU2 zbvk7JKFB5H9adu{&*ieCM6W{(ha>a>aH$UPqG(DK8x_^_L@w*S+Td%kNX`eDk|mIm zlG5x~Bo*|b>-Zx0>IJHwqN86ziF_-R4h@QkfsW43PoF+z*3}7s;C#oYny&&1;aaRC zynq=NMf4af?j2ibXz1G3Ru-lReyRho$bTeGexs!QOALMKKl6)@jm|%;F$;$i%Y$A9K zu&{u3gJQFbvqKz+A(Em|3S!}94?3+!yN>91hhzT7>6(3LM|6PRQ z4a={N4n=!=wm|4+>MRh!q%Cz?AO2|D@sNzHC?w<_6&00&By|6GqEPMCN0oZE3RY#x5(?U&8`dXJM%xrz{oA=HW_%2O+)(#Dw@||^CnJJSGTaHhVMFM zzWr;HhK3Yq2oc=i=lsqay@ru73jf%Q17uWwK7B^T=H}*jqmNHJH}XwzsUvH=EJ$FL z8p@lCFzP^WDW8bJ(Q(2ZTXv|RWnpFyRm&4n; ztI?2`Q9{S8RR3OoF9f#0<818g#w-Cx6faB17=nL_VnILTxGs}F$_lh9*|yoB1b!=W zZ7kzXT;60k)N9;Q!sI?g0#i0JHVzb^F_xD8z-2v7Svn>Q)f*T&D%SsNAs0aTeH{U{ zo=shjZ92n`(Rg*9YLTzLuj0up)XM%*yS3+$^w*jI%6`d|iB$v(MUp%`o90gnzCDeI z;*(mhC1>i{zgX;yO}Dw?RZGE`|6|?%DNe~@+n8I8m+OsREN1GCO-tSeuIkRD z^1H~%WwToxZI;4?l;q{ZmrXB43521Dd=?LU_Jo<4Iiq5CcekUx{iUMf1IPqTaZ~e$ zUS3}H35kj6294lv6+Jz&*TOVW$dQpcOj3$q7!Y~jr6jp*xn#b@)6>q%BdmFdH@u;v zF<4iIIhqw$BA86M zNjD+tU2vBMQoQU^rq~+WKzk=AC-BNZ60ZY?$I-^O%{DNor;sS~i_mYqB<@$I!*<$L zub)Ewz9v0MbWy)>hP|p^&-u-i4B6QUag()-{#Cj@#l~8m?k$$6GvM3=K>L8w`a|#l zYpl$2T{Ao-g|zVvM^cGSAssfZH#?J@16BRwUxL9K0OFBuXUs)<<~OVgAh(i0Xs(b| zSEsF^p+NzE3?+STi$O6h4UL2~;^-It_Y2972a?)JJ5AP6gQnYH7YbsPQGOynSQE@RikamZWao>A7-|4+5k zN44Wi{wqCxLd7G1ZSt)7hvdgNCjH3&aZ>;&@%Zkgk2be&!$cVD!*i&No_&3MEly-R zySk#kV~(GYmX39GHvy1o4vGw$IlJ7_;tobKc=(45j1L!R8UG;{*gyC~K4pae{!J;W z@q+~dnlD{3j9Lqhd~{HzdV134df=?j6hth$Ca(xhP;%Za z6*;5wXBqI_E%si0g1=Dpzw*=sAaJ%&zJIJd-Cvf-fDaBTC-0+X-wrA^*CWBVUBNIG zzC1BhQC7~Ws&efoMgXs%h(OB8ZhKysp!l4QXE_<_4%WpNF#;x|}-!{1v^rNWaFS7Re1S~|M-qLAzq zl?8gURZ>IN39^|iMQ(2Hc%56REH(B|SaXv}>FRvA@NfdBCGBk(Ikl`KG+lnS+9{^m zsjbRMBev5E!PiF{8t~)y@87c}cH^-4{Z%{(iHH^*`NR?`z!-o&CP4c<*uZy@9F}vk zV^{fb)3M2}TitO^6FFxMcAHsz@ZIt(l+px=YW7&TUqHPyE>6* zY$NmBdFnM!G_#|js;RlQzyD{;rYh%g03;0nN&>v;jAdR92Yl~s-^4^dB;Ob-uS|<( zN-PCaJ;bYS=T9sR0-;G@SHHGqQJ`M@C`-asvp^N_gSE6E(*E<){R>iV{CnPyO-Bl} zmQOEx)5LB_3_tQjxh}Sgi;Eqg0O{(ILf{~xEGaFmXkhT=?CeZjdt}VPaPUHp=sD3= zEDJf16)W;5u6IU*aTyIhl%hQTo5MT-MCzKuxL+KO9F7`>vohmA8zn=9I_>wNvbwP3p#`ru5w0+_Q$Kr>6n$4G#dp-m4T1_(LCflI1u#Igvf1AYKy^_{*sO z!$W!`q2b6lTY*FyA-dWF-vs?8T5K&a7!f3jsAGcng6M1EDJ4-6p}2g70-|A%IR zh1ABx;DYjxiuE+)dbR(B{`}BUx+Xu;|G(ttUta==46zGYRJh=AlJ|b%%*%IDA^((s ztt}hW8v(n#BSS;a{}F8<&H;#kWDXpxXl&Gb@#4kW=4R$cXnyAcyFaj@s`ltQM&m@8 zbZRm#5XYS+r3%;F(7S(Nz?dzb_SvmJHiKLoCz}mnuZY=yD9e9H;J*pULbowqE@KK$ zL9h0bkqM5BjEt)w_k;G6{uh$XI+q!%8#!c=iHY?Cv3J)iDG`vrRJ)HJy07C={x!m9< zDwsaFp%M^EU%xUeMF2(-)$9Nl%$}as6+Bx>$1#lj0ERXx)!=v8Qa1RF=es^sVJWQ} z{TcbRR8WuIWC~aD%7Go*>#W-O@U0%cmbP}+&}|rsw4q^oO>HgE&8^GYYHE0Y6rXJH zr<)|i9n*DN{WLWEgCo1ARW@x$-m%2X2ti@&RwS5sKFCMFFe%D6x3|@ll$3f04zKkT zBlIaS$2=dtnHM{L!zSr?04{#C*`F!%uSSEhlxJpVcN(!NyhBOAwY(#skjC)puL}4k zLN@rPKk4?%7#5KBGn*D5ac(%GAk?9An~-mj&|ZI zA<bu+J!O;i6>o0 zM&XR6g2r2hK4YJamc$mYccQ)Gw{LF?UK|XF2{k~Xxh3u2B8!ayEmOgakP83e02wTW ziu_;a+dA@l9pPO`fBYDL2!D!hEK zdfq9m36^>`l&Ho#PIUEMedyBWm3NsGZp$tTsBZXfqp3;Q$o)4wZhagd2SCAN=l2K+ zpnI`qL0(Z&Hb8er>7BrcEN1eMP!i`_ulBozK?xpgI1qYOfs&5S-$?nUw_2|3SN!E#a4r(4*13)Q!B?X)GBN`_$^7whf2yNqgJ(4ZE*g~l z3UG_^JYaPgMK^eTVt)v%uF$%)>{)zKM06B zYOYGH1w=I}d-lC7ysm<=T+;6vc3#WipG4OoGjG%P<@r6NV3sTf6!KokqQ&VI6CGinR(b8)jP zIIuUOcp~_OMnJX+2!kNBSnf%lq#!|w+D&R8?|;ScroGNq@?XHT!n7^%IU7h_17UEz zUCHV=9aQ^$!qqOQn7gQ!5~~#{f{hdk7Z$hcEi)8r409kmBrdPXDg*S8vjQldbZCD1 zZ1E_DhA%%?2MF_yr8R`X+cJHc)yZo@jL(po)%EQG=F)TbfwYZ!`_q76z#}$R*Ii0A z|C6XVrY{3a$a_@dyN13iIMTHISg$tz%1JpWU*Fh`^!Goioszq*8u;H`gFxnrI1;^} z`fms9uqg5B}L# zeM)FaD}#?F%hVEB(nWwK%LoGQI-&uMRdn5|UOq^iIe#lEYcN2QH?Nc}Clz_`w*TJ# zzQ4u5cHX(!P0ld7h*WJj73)Jb{kP;d_35NSkA& zrtQuVzhCnlG@~(_9dAtuby`|l0zpJ6mG|}Q0k3c$!{|j^uHG4c3mOEr)+YXF;~w={v}w5iWe-uL%}c=A4JNzSxt+>4 z$8*NDYdbtpeuS;gjrUI1dz71WC*&kqI^}$pCyYaCx(GU%C3mQD?xPkK7PiPzK?&?L zBep;DYimtr|YEL&T)gELq~idyqaWumeIZJOQJ+!VsSen6`wyhIT&V{ z#nr%+Vm+Aj&Gj2*Uk6_KifU}v7Gbx_k>1Lm<+~vcHz=m%=2nYk)=Mda7yO~M_G~v` z`2M@Z-VTzWd)1OiT7i8T#-6wY;p1R!~p}qz%ZuVepFAIB-M9fEtK%R5Y}Uab)|06$KE+ z?Q^eP#jQ<@jG)*S>k(Uj&EvQ;`&30m<=5QnlgSVUVPU6* zeycc34nh?Tjn#ol4`C!b+m;K3W028cin)1t($Aki7ps`4_o##(z#8dEY?x|-9X-RxI$FMkTHBTd;P#dyg(OFH z#5}J>=vBY&1VHpl6fkT&d!E7R=|YzoFST&tOP(TO5&RT~EnyLCY-~DUAe6-7kdKUv zj8q>(zkQp$4eow6scc!*YePHz*m7WCzzNI}Of9dZM6uRoJLbFo$CkO53JMV*Z_!hX#X{d6swyil+{LV)AQkdd?~GxLq6Dkfkq9H+Ez2z^ z7-|hAT71oO9##wn1up-{fqCRU@~x_BblGlu9>YX$>S>lo?KCH$_C%U!A3$}p`PNW2 z{CndS)`=KoLK~IxTh_7xd3jHuLHk8q`BSbEmoP?1FoK{aT?btZVxG?c&)~bs!ally zWe?`5`CICuO5r9O{OHccN@-u>_0&eDqg?SjFysn52T9V0D)^z=J&1qmbsl<@sEcp^7CZ? zC?5_!X`+RdFcg3{8h*n~*qar#e@~XEkpY1S7dm?fD8Vaq zBeCR~CNK6ZES@KOo^U@^tYK(jIAvtM`z;xg!-0F7U* z9I#|dSl%IqN)T#okcBWQ_dbZBC$zLECyNccp&punFSCB&haDf>0eQ>kevqRl3AENm zJUs!dHSga|3|Lc@R+(8}MgzsVGUn?JzsebJ{*}J`$GL@ts^;do@RB>Et|HqFh(d7V z!vb3`nVIt?Zo%~$w@SNh8GHK@Jw1P@>mWHfna}&&wJAK5jL%UrTR!zjV|aXg?bIdb z@+OJIXXj;j>aoD|^t90LON{07(|sU#224}EvU+;tyv|m$&o)ZoZv|q~*0^08>n1K% z<$VaNFtg;z?DW{#*_|%W-Rh60JyM+ND^F`@E|@abDe(7~;bitDtAG;cr>Bbn|EYL+ z)dL!$tfrPNLFUDgGk&Wy)n(EyNC>gPJ~TY+?swGHCCjK&qbw7{(3k8o{VV_O8@vD9 zvd;(cRcZ=X_4E|@d8^roVfz$VN4&+PG?eZoBj7hqPUZ5d4>|#H12Xu-H=6vN%qE|Z@*0MEU>Y9C$7x8y5Kzz-77{5{Fgy8zE8ZB*G z+wFHQ5i*jJ_|7^YfI)hk9P%q(`G!4y$-mvi(OV(DH)fg&ykOHFegseART?SOK^wh# zeMn@{cy@M1i5{X$np@!;=91xnD@)>!)m449rq-AjjK|zzQ@IZJxhyRyE#)-rNwOP* zH(pFMLfhi-5@0nCzb#&erIiN6mXe$tMv)QhQOBwycn_j(>qeZbVf6qjhzYYQ?LyY_ z?e+Ef`p(bCcD%g2ujb=cJlcA z4ok9AAjdUp9CKrs^$NGWwmnk%e#{qSXPZh3ysyiaz=yLmdv)84etU|Hj4UlLKhhP? z?zN_-qC%BF)B)lX#`?pGE69+4N#G!mlB#hh32-#oHI zTsV~Rz$?Q8jrNk}uI+4ghmvX(U zy}c`f6>d6R`Sas#bE)Y^ja;dNS3d`?W(|3_@xOTcA9dCy@4hY}j;(R>5}$cjzA4Q1 z+RmM9`}G8I_aTd7?VDxlUhMX&c6O2$^!Xu$&1KUU)+yUT6Y$!ym;E!YL-h1(n;L@21rk<9BXFSX)es-yG^DJLpgM6 z?0rQc6}@uWm0LTog;DL*Jh__QX_A$Lb~T-T*#m!Evia)fm^u4z4v)DmR%`vGjfuA# z^R-$Z4pOt>x$_3G(^oC2pS)~qmRYyCG>)_Ki?g10qZhPn$*)%jr)=XH^`KSR{H|N| z?zBzh?cU#hd2xp?Ok{IQBaUjbpRM4_Er-6(5gNwD`BmXZO0Vs z#P43|{Hk<>fB5=l)BS3G4X7+KQEOS~(4sR5HI z<^H4qisQ=CdYQ=R%ghPE&7g@Tv!bB6doDJfg}zzxf-}p4-;9(IV?IX~O&0=c17BJb zOuBW<24@7yy0TyNh?d&NBz`L1z^Fg(+P-sEZKqO-mxTg*L}xc0!g_^q$KdCe^5AIG zcA|-WYc4o942DTsir1s8E4{LK zw~*SvgV*(qmq#Kf!*<`(uJ&8wDG>a2vn252V}XxEuana%SW`-DkUPm5TvY1?FK&#S z&i)`s^(xof*gLnX@mj$m^x?BJNjl~fiyRyo*e;d#S0Oo@4c=#^jSj&rSY}%D=N3LV z_cR@DrWiqUm8%kP*{yCkFI*g(Pt5YpLwSkSwo<^a453dtBf6CROMz3($N}`)b zhvtS80b~PW!Y4HuzOd6pQ=e_Tj+A`!;rDv?13W-5bUM~5n2(_egsasb(KHHqc$^&; z!Ow+OMBH+E?Y=d-nZ<8)5sn_M3wzM(&*~hG-%0VRLHKHC8Z+NRIQ9Ev>MdJnzCAyi zf=~Cuz0V`hY=+Jzz|G)hdfRU<7fsLMzuxPm?r97AyIln}HBJ*E^PfyswT%B5+ZDV0 z9frv;zga5wN1f{-w!AeYP)K45wxCEV)q25 z^sYG66Hwwg(6w9h$2J8nE&A#)aJX6>yjJ`BARt_icpi`9;A*n!O4YitFv$BQ%f_Y9 zrTh#@&gR2xUGJr1KFDGbrT&)d(=)Fv1xK<{tuJCf4_~a?&dj@X0mBO(T7#bou6q}j zX+3qcG)z2mKXWo2MxyGGdO82O7hy}PnRQ<-Nx|?%u#oF~NY79iEu)8Te+ll2_KV=` z`s-XIv>(3%LkS89xYgZgm{Q}eMfYbbcxcGf@i+>N7TQ_&V`C(AHrN?N_RTP69t`)n z%rND9GwfjPK0mUZv(|fOt!nn=?+w?7LVFJ{G7KD=L^ig)&tFhsoT!u@z7Zvm zTe-b2!m=;w0&idJ#7mqn#UaCBeMLw2L;u;Z;khyi`s+-Gp=Z&)x(<(ngTrj5!7DN& zW00Ujo0mBwY-#|tOAC_9Z@z27b(Cj5`9{1Qs}yY$*}x+{+nKsu)b~m2k|l0NEDorxd0%(NpYBT3*Jy2?v=we?UkBuzI%`wQ!b)$Y;v!*!DDK!M}v06 z-=%i$mcv$1jrRjnnw6A0_JW87p=`0u>>E94uqB0V%QzAl#1E& zq5Dn^$6}~=Z>^^Lm=EkNb{ZF}i%&W02Uu}JeLNzgNj{}w4yGAv(57~-7hr^n+wqym zr=^AsVfC9MR8suT8!v5aY(^^tUqQzwDBbGKX_uGY$;Dou!!mHExEu(7-l9I?m4JG4 znytV3T3yhP<+*8wnsn7LF0JF|io`Sy!u~q+I`+OYJ#_MvV}&;1PO1g1pLPWmM_jjN zUH^H-_SdORu{uLS{78P7B_7>%^osuJ-m2K(kJof>`)ez{>(l;0ceI3+Ey*}&q3irQHNp*#h=C;wkexI zYxYxNwd>Ob@$>TAuqK?ygoM01qz!uS_fLe?$ce4E5;ZNxX>a{UL)lW*>*rHbQxxUp zV^$VI-RSk;MkkIb+e%(uf`M^A{yLQIIiIWhtMf7rhp*>w_0Rd&=(kkUjqP*o)TE8i z(lA(n!u%&DDxuf4dwZgZ5*7QNsY0h8XJ$lrc2fXn3Xt(xcB11vIHJp?TeH~e9jdTo z)op`6u7Jva;)qVoxN|Z+31A8}h0u|iCd7D`{O>!JC;mG`aOWbS65>nqBN9O3d$x#h z*hSB?7}~qLRSXOseYyeDe*pL%1w8QjnY3bRR#pX*Qr@o<_jp7rzJ8TOM@LV>g25i? zgJdz>nvakmy^BahCC5#5*jgR~p>-|CgJ&*}Dh(}CV`8#M_?=(2YuP(Ev@~?D_LZ@N z?DLH4Ht~+V`LqLSQPD>^tu`rEKM5d!WW25CJQ2_!Xw_bdiVys`A6fB14X+{$&{>=n z7ZG$`r10IQGQXx~-1Za-WVU#tVs%F#T|XjxRx@KA+elo@F3(R>jQ5wiqkbBsoxBpg zZblg^F%C|Wqk#s18T3M2c{SYUJblJKy)WnB;DGgbroaD7Obl+SaWF39UP!`=7cW$R zMxZf3`dQuTZpj6Mu@nMEE=pQ3GBd-RJ&;>hCjfON%If>2I`lV{AskgJyMd*{`bk($dmUMBsC8 z@#^9+Y3D2~EPS)t|M4FC>|{Rt)5niZcTsL$_gRR7alzNjo(A-L+pomB=|4q9iS6EC z{;z!j3dVEIfsq-*!^3ycOs8ILyhSI9li-rQZXtNn)6+w-{Pqb0!=Tsk6rTM|eSLjo zMt^@lz}CIk#=$akPs!V_Ev>ASrKM4?ZN2*YXYhEVPorv~Ht*JzuPihAPf>k4-Z6u^)fIY)ZuW~5Zb+$ z>LBT;k?0s6841r7K1OdrF?@X8%7wz3*ganDke&4+k?U33R}Z-yTTl{kh~r?m!OxA2 zjjvDtd0c1{lamX62IB<{N&xXm6Y_lFN3}K+o-uHVJ-`C6Jg5Do7X@0CHj`P*`hMQz zJY-%65zyAVPaFtzDr#y)Ns#`kc+9%WE-uG8S3;x3hCv`9==5)0AFreAlhW}Ihm)dv zmp;cw3t^zA4_0^t(xjiDTT*Si@jjSu_;nM_-P)$hl>3E-UXfU(^YCp7Jlm^Lj>(7ZFZ@M_3$QeN2XC(8xKzFunIL(5Hz}9y{G+c(y zk_slxNMp^-%^$}f;^5@uTa45C%F?N6m5o7>mHR z0y>7mUm)oi9vn3L`QhQc;dcfDS!=$$#261BKFqDE8Z~vK5r`X^72 zrddbLI4s~Pf*tMcy{(}{ROlgcp)nC9FqWYzv9YWyYJi|nC<9tX6N22TU}~BzOC1F- znYq|{0Q=xakxpZ%$Lj5m9SxQK*4&hI@@bBGdQMdj1^XC(K`hj?M zQ^$i9g%5XN*zHzao#1QLvBRX)9Qfg^Kei!ba#H)l&5*t@5`GXV3wZ4y=I7ToH_=Z# z9m9oK<7I2EE)jIsP2#vi4(&0~(K$Ie?Y2Tnwp-N(Q~N)q6@hz}4UZ$syb#X7o5*#2 zQNX5X%yplEGr=6_n3&{_r#*@)Y-dPcKMOecNu0lRd9*c^50JxhYqAZ@8E#f^jm&B zf5g5}tUtWAHf*BOcBKAzdR@bGzBN>A_;K%HvFq+{tYb8hjrZZ2ypeSIi z_->QNMUzsE>gsB5Jx?5HkJ<2d0(qo%q&A3Jiem*OrTJBw$B$cv#>Q4Fo7AdExx_Z zG3VU$bONX4+s)c<-&kgya5t(2JWsymXJxg1iip4(Y^c>{Qd3eI__*$&_t^L7FMb&% zqkN}?Db`k`%6g)Lf@~jyl%Ag6ixj$<&ZkeGgr3H^n3=KQ3#@Z+a#lkd^&q$7<=dCK zN!m?}j9ifh{QQuh!=g@o7FR#^ZA`hy^|>H2XA&XLQRqyC@Ad2(dO<<2_Sur$++PDd z`Ycr##5}XSZ-H&#LRF0k2?f5;e3YBGPZ}HO@ejqbiBz%;;VW?d; zfNVF=6HwR{O%rM)9!Q9*gc5*C@(v}fo->-T`5d?LO7Mz*Ab$0xWpYeO`i>>{l+w^l2L=$QvUX00qs=Um^78VfI1%!XG1irxygf&P{P4t8 z^*^0$vooeWXeG{1ZEJ+bcuYmc*-4X;hpe8@7`BBOCsUa_;C?T8NMt)zV~pxa8ctL2 zZJD8Ik#A<~4j_tr!Kv}b(C1@2*c5u2K4oXW^8VloB43KWgD*G&I>Wj^9LsBbcB)`3 zRktcNO#nnlj&NN&(9_grscMOTL}R6!VZ)T4TFqx^O=;P6k&wOCi!{8=s@8E;aoY5U zTS_Sk`k&^Ypn)VjBh#~}?o63j>h6%TU^ftj8ff09s3ijz()H{u8VnA&Mh*{;le~61 z=!+HvT6u5wukOQzN@6kDaww z&+y(HV-hk+%v{?b@^H>qYViAdQOBTF!LaQ$@%*GKzP<2r>k-QgcWw z2~m8?SSFeQsktDD@9@;`eeccVyWjcX-h1vj=YRgo@5ep=dv}ALs22df%walz`E*dw z(=!+#&dtp&E{c0^7@M*vZ(h6*@_eM}=ai=MsV3i|sm;n^+|keN#u+=lUq_1YmTcDi z_W++fI}0=fbj&wJ`6XH)5a7Qe2ImfN(v$^SjOg1^#pr#^q!H^(%U2#&!j}bs4+zrT zQ2V&Izk`kfCQrJ2dDS-?HVjAevxX-UPXq+O=aa(2-G(lnY{wV}1OybBM4dU~GA^VF zLEJFS!#jm&YHCKcdb8G*1`Y$F>uCgkPIT~TAs;W)^*@;A=&H8^zLu=B4 z;m7T9w4-a+tTEL+Sb>z{Rhn){Bu)K7vb@|}_0j+l4USQV*x!DOxRbIxYX%K^;h+j? z^i^5S&wFfa&I1ZFGP_>iqVoRzpCnqq{Z&j%#CiDbl)Y1sCQ-A7`?YP`*0kL{ZQHhO z+qP}nwx`|Gwr%swA17i*{O9KET@e*gS9P)0imZI!dNT8U4-OLNR?#J~2@Yt4jwMg6 zuY!1CXQ!{&YOz%2+-$*_!?Zl}-5NrW;y116tT(K3*)G{Q#LF``2S@%1AKd(qECsv; zkXSSZNU%_TO65*RslBsnFA76j&+V+5(I<4VE+nH5pXDy&I!x8fgec_2Ew!?^U!pcq zBg0nCXMm!BTxMi7oaq}#%3$#3{Of)8uJ})I8oAI<($-=4BTs9-cV1I?X7=gp*x4A^cd24#% zw)Y^LYv|Ke;P?36^0;@f262#R?Z}3%gC{Q~WJ0*n|y$6h=T| z8BGpO-{a2B$K{c9t_9l+5v{4_F3HlORMz)}C5ma;F+a6gMM4 zVwkpp+e%}TV`pXk`r{N2;@>Fr4WdP5lmi?*=ds7URD@$s6M0?tO$zyN*~GfY%zT1^ z;&moO%L!qo2xIlAREEBR@O&pJ37gN(8G-V$Ez5ImFP%yHw(X$IK&Z4c9%tGL^X^%z z^O5=0v2ii<%2AFr{5U<|b_vv^(qOXe`s+@k_I^09CuggpvpwYPEVGtj_}@g|C-Bce z!IESrG9@Gb^w~HS#20@h(_bAODYUBcO_sguEte|m#H9P7Ojfl!peHte@AyS5>(FY0 zoCW?=xWILuNjwkX7`CqN9N1@<_%l8=D}SsQ$}C}F(55CDQ6fW*pNmoGkKFr5N1IBL zZ{|_?;CSBZr%uS?**Kcr0rFiZsHir0NxKyVwdGBxbf9(i2~$l540X|EK)l|I24E36 z!?#9iT3|j$*_3st{*^)eqS1|H1>)B6U);O7==9fL`pC47wqA1H<#rl3ewm^-6NVA> z2m|%@RmUkS7^u5kjf&eJJ3VhhaVmD_He?Gj0P*oHbDB&bjG(%iys-Y|)aQpABY4&C z<>h)p%})Ck*c&EI4%}Z)4Q+Blxt=~%&cMJwEE!)FOu1bqhu|6-6c7uXiu@+Exi_RH zbm8Shp_CI5N#_w(8vU-sWFp_A(L_v7noTHnN4YJ;#@ySmdcSLY;E%N|U+qTMUw}TI^l8$*s)H%mLK!5ozP|qA>ZbbS;1Re{^ZL5G>e)vx;iH6?&^n!#w0>o9_Ii-+ zlpItVaFF0U|zE5jYU!9+m4g)EEH5dVP&-%~8tI?|=-Z_oAW5cR9rTdA#W z-^6TD`5|RD{&Kh_=DA&o1&md)6aVz|^xv;2JCXBf-FMa~OjnH?txWp%-Sc!*JGYyy zN6fOgm`Hm8^rBo(Kxzf*;$exER+iB1H(g#{Q3U+HpQ41TvS_M1{Ly#Aqf-!8D0ml| zn(%-WD<6z9aTjpxUc3_^9lRaL55gpk=w4@|=M~+KM)H5c?h2UmI`A)ws6t$|NpkDqGKfpnNcctUU^p3y-bZg^ps{@|$bcN?OYO973)!B6u zaD0B@210ptAkBj<2-ol0))FhHmN0?j3*XiYvafSKa4v!HlR|Oc*lSD0S?sV{QHJsEbrKA=8GvhHclE{p)E=ZPN=WQ)4 z$=5e@c|ug1OG_FQ%KItotNAMNu$vWtV15yVDJFg00>lK{1W8Mp$3g?)R#v50mPwag?+c?n~5#1||P^sHsnTjL<8@94j>R-hDk4yubHX}F4!qO4e z*O*e1@I}Vn0=FF2vSK_zwl??rxq>c-4Ph*EJw|3)t4tI?R22ysU5J-!XeXlG?Oy$> z(8#;97y$yV74@XEskiBTC#VVwo6CxKCT&!Wot0DaiWKHIQGW48cbI*Zpgyev%jwdi zLY9?ntvL&}RHylgdK7I=i@JX2c;>oN2ps39sD`Kqfit!)h8j<(ciKB0-K=ZJP{-QE z(`=keQcI>uo6C@zO1+Y)-~4Y#D2r)ud98`l;?(ymwil?tbZ5_@hx-Ak_q9E`-=oN!ZP1+BiL?0&rDrL7P&<`_A#H59FQJdF z@MWrPElhX~p2-S;MH;*4ykD7XS0>D_KKU`TiIH3QV-G z{%^EHQQggfyAQ&QX~m)g7U5+78uvGJNNQw)@+%x{>3a(PM4V$F5L9_kPwF!>K`w^! zd`W9Vklj73jSSIr1WG|0G_*J)JQS0<+{{lOGNt>i_*|A?Q@_O9ObRSH97$6=0?omS zBX2!1>(!3hVO2qstQFa!*VwcO+(DSd2VSW5;rR~!b+4^Utr^n~n7kASC@KIL00}56 zN0TaleABLk1pxjM0|3kb0Kmw^!rIQp#M#7=!Pw4-!O70W(a40s$j;W;(ZbNh+0OAl z&!!e;E{+Dy7IwDuj!w=snler}?8rT{b^V?QvdW+0-Rz~$`7JrZEwP7<$udWzfy{&v zfB)z+^@s1{-*3FQ92osd#zfE5t!}|g|+R|_&ygkTwf4Nf96a5)l`Wns8MFv)Qy;uO?^e#{xjUCY}aBj zk~PAIwlR7oDS07*fGWghKay7Po6js%CQ)jm` zTi})b#QB6Rx zq~_wu)E?zQgx4Uz8vskGb$5QRs=d{V{L|ju)0q>YS9|T-{q{yb{&94_ST=RhRrS)g zf1Kp*<@9xZetmw7-Penew$c~rr>oPK1qF6sK=rir)Qmt`HBn!w8LlN#s;0COS#uY; zCY$0}C3V@b1?N~cJi}AjJF+ZX_AaXB*c6hPQtnceIj=+p349(__E)Ipq&pl&|K> z^GOJS>r;cnNZ6b-Rt6>ep|Nk2rHZ=c2B|MAYg0=g*ec#P^1($?16^L~m8MakUE{A& zO>@>u*ct~3uTDr@5IMeR{F_|n4(Qv{QjOEBd}T5U*^YsJ`RET1S-9B1W43C(apcXO ze6HO5tp$!ev3^f+$Fu(3r(5QXY!mi!=qlWGKPjRW4UkmDGHbG0l=N*`+1}~@*S3ed`LK|Aao?-_ZXM@_*!E1&xiL*QOaCrEu)fl`DmE)hAUwd` zVjUWAlK&76?VvX3lRVu}-zLWb9gGw@EXzOWJMYJ*Oi6eCJkRsHn^tO3?J*XZJt{9> z!C@8Wunxv<)f<9H)%&$+bH&4)F1UR|N*Rya2v91XHTi-C;bMWJG&AQ|Este16cW%x zyhJG3LB_kilhqKev<1!4uW={cwTg)pbshh5krkrfS45AN%^SM!( z{w~Z&y}Gf2L#I?#hE%iSFg-;-a%~Ges%=G~9B^XDK!`-@WOO=qQPARClI?d8-+}m7 z4lG}QQhBzS5Ci3HH!|A4_6DpB^MFQ~ny8*GxSVk&`dd22b*`Mn;DHa(M)a-v=@UowoSZS^34bHwE#OE?LB|nUyMc%?mL++_y&rJd@B_b?$*40rH#hp17B4+*7sv0bCz zFkzDB3dk7*H2#5Yft?hI%?phF_YvXJjvdDS$2N;D&EMHP2f!s&K$vw4sJZlBu`Bbj;K7e8Q|`pDR8W**1L6y#$SlPn+J<-s_q~c~^&L@GfFw{G)gk99Ng?Sv zW6CI~tnn27$3-+dVfNeZV)ccI)m;e`Y2(C(B^i}C8 z3@^ar7`VsLzJshX!-50E z5cV86qHY>qmSSBdiQg`)yjn0y5Gv6nW{rtx?7?Bda+0e62|qb<$kk^3y&eB!K53+b zj!IUAP>{v^WQ&dK5Sq%VON3{3oS@lW7;-~D?p=7@%NAEs(H(a4WoBh@pTCmb_&juw z_Y4IEdY^ttCrCYVNS(V&PO+`Ct#+JzZ0R5k2gaG@h;4KVifb)>SN=Z0oft?6yq2TC zGchn<%%cn*e!1+*AjGxI6xF?%r3bje(YRU6FBZTg^2LgMne%A#)U*jcYFY_Unxz%; zwfc)gp8~qd;%&&OcYltd9Ied^8)o1mmMdmP0BSCr1&P>I&Ch!~cF}90>_dEWEn^N3{R2%bgNZ3F zvCsPtx9pw`{27c_JX`;zqZi-3x-wKWlA)V0n+R-Fq>UkEf$NKa>?{{l>Lcr5IuPk?Qe-ay?!otDJ{okSS29oM4kgw z%)G*b1Eb_g%2|t-`vj1Tt|(I9!Qg5^WI-M#4B~~^>zS_5xskA$lj7N1#26BR3>UO9 zh)?V3Ir2h`eN_pV&P91RydYKg5|&A+aly{z-Hjqe$jW#dTr&{L$D4sp_d}(5kSEmM zFaa<#0l(bjY7BS(v)6uL_ijYDv%~PT2&va1Ewbf{C{~q`PHK}lTyJZ(Qr%Y%GnwPE zu*HerYNNmMDLL5ruTDGgKM!+1VM8vFChpG=KyxxlP#)8q5_`*x@j|_ZEN<23vPhUQ zD*5F0m(_@ri#xGPL_yxfjY-}N<%cGWS2N_JwgMZPb%WgbXg$fQMvhODb?SQZZ-K#I z7)jan%aVrZ!5Z~sKK=sg6H?83l1vbG{8y!uVWAUIX0yHzuOfKwp3^Ft6F76S1W|DY zDpdKxw7C>W@U!cd@JW5g;u=>9Re_*4KSA(l_mlJdT&rPga}Cu#($&8D-5jl9mW*PScR(Wp77AuH1L^iy|m^ z932nk55?eJH2`9W{&n1B$ zf~lb&F!>!{n)6Wddigr1<$%jftXSA^7r4LR1OIV97=beMv=?dTmZ1A#cDQW{^pLRQL;g}J}V=Qjols}@vb+vE%pC3!T95%6awL$GOoDpOS& zN1Ublq*Is7atLZ-W~Vd%jL^94V9XmAiv?F2v=IqbS_o@LeJ5haKl6CJYk@;Mv4=|= zcEBgxm&MVkD;l^KK*KYmv&L{)%M(N%UhYV}=w2&W$h%fyPMO3PKz(Ko@?XMso``wz zmIztEiA|54CosOd#C!mx`5GpVHSZ$`k^d#Xjwih5ywZ))cj)PiUDDxRKjFBT@FDlr!}1`hlOj08*D!ggr$prbg_nl$uESZCX0eH6zqh7SnM@M~+z!XW z{PqdtHZvWnm%NwEP5@^&M1ad_o!KtNSrH9LJ*O)b2REL{A}8TulsCa{DhYK}ju5CL zaGoQC6mMXHLuLVxI9khKyX22ve5gBi865&1no`Gw0suf6-4SR zU7=)l$*W5|Fle3Pm&wt6NZAnd6TWxPA+P;>B$Ut|&8gIt<@x)SQwh{7^G53mp>FoS zWv7mKS53Df*7|n-o}b8e>Q$+nG-Ye~i5>pY{D5#D-zTfM^~-q9MwD|7)pBu732|mP z>%#lX3sneY6zhh(ffszXZ$^1jxDiggvbsvpO+btC1H&OdK=6$5-zS@k^VK;S2>`I8 z2LNdQS0~%V)x_4>=|5+>N7KgXpgrL`Rxcn6q2X|0Zf%p@j6r2PV=d~&^=fH7tEWa; zGE`h#P#Re~u({g1eJ8i93#eB-cVbEr|1RCoijf5a0dZ99g7y9X`4k0wTn$PnKNlPGWgn!2So+>Qa^OY zbvv$ubINIb*`S-&#fEif3Agt(HytM*7Z(m(rXf$W-YuOJCN^y!w~xKWt)a4)Io|2_ z26`LF&X&H%+L2LqF&k|2)GWA1x@mzA)hr#WyXuF3Lf*x=DFxnl15etjsCY1>)+MVq zD}&(-3Pu{D-@kPE#uoqaYKZ%5dV1(;Nb<+|N>N5HSW z@5BAW-ODdbZs$C!EAPo~XWK{H0_LBP|5$JSC*&{2>s!YkgUA*)-saD1Fh&H8oZ4JC zpVedN^sKdvtU4QPj)3u;{4+!7b&j|e=T9iFtb^|4(C8H_sznAU_42V)GSmo=p*^Ep+tRQPnPdF8NB~#Gt(!ORF9l8T4`W`tq6SMa?)svOeyx6yL0W>y=Sjwzqz&3Hz$PFDzJ=LwRATY_0JHw}53J~N7A zb8D7Mk+R@boqgmm6nGjf-7UDN)O;k10{jk%r&--!F=%;C46QtZSXS7$q9&7$9mMM9 z-umqt$$a%ibAn*mrKd6#gQumA@DO@>&VcdQ?3Tbvsk@6Bs4abD0E%GOmPUHR{ckEY zl1CaR~H4}b4&;Ys_TX26p3;)=x+Zu0WDY>K-H0w3r|mJVXtWCz3~xZ z!TMKj9gr=L#TFh8&}RSh)^e1GRZ^Vn|OOM>@B0Mg5;yeNO2lI#+x9xRr4{aEHKdZQiyy|w-$qw zB_^sv+|8r$7-`_)X5xO@O4uK9$o*l|x2c+KrvpwHu5q}?mFS;dSPEExI9&)3aj~t7Gz3YY($ZfnHJZwNlx0}}EG8@ZkzyB&+ zYEfB2CP?(N(fuxVISdV^Q-2!4T6V594i^)-Wz|O+GZWinJ5{%pW^!It*Y8cL4!B53qZgMwxYCUj@Gol$zfldKfqK z1IYS;@qipV4Y##74wI5CISiuK>5#P6VaU*9-FSHJ4GaxZkV#}0{$e%Kcc*3~iAnQr zP(gze+qw%!{X*QJTXMaPN#S|{XcBTA4`aUyTVrQst7DxIK*4HR9AC$95@*)83~dj5 z&L2elG~+FDO3#9|guR{s31!4wIotO_mb&|)Bo}!580|{)B zGcJmcp6xAPwfhpz(9IlD)t0fS8VG6xH-9MwP0%v^n{H&5Uq+JB{EHXto=rf)b*9Io zp}7hPoV=4JxE*bxIrnf7lXg|iB*q(G&ao3259hOkSCLVGLV9v9&rDD*$zhVAUn-V* zw4QATCMo-4aL|M@6FgZ7X&)GZgNc$4w2dgpqdw*eokjqSOMDyU>M#hGXd-tHT?Xky z;pXQWL8+<3kEF30O176VS*C*6n(SJ4Pyda@l4DXiy7mz1M4yX#!~|`%r9WC>pT>vA zY=-Q_@K_f1y+ndDbEM|s%2vi`C0xNp#!rX;Na)j;^wDAh^FXk$QGF$}+a<;vR1Kmi z-iDp)eP7GB{cc3TApJG|cVrxt6uU{EQ?OU^dN;>Jg16~PX5^|^twAGKGGm3l9ieK@ z5_%$;8VhHcouiOOETJ#eEr-PZQw8Uh`HXm4rf_WfiLk#s5+Ndvh^_s?2#b%>02yKY zunmcFppE}w;KFj3Iqp-c!zE34S-*W&WJu$m$Nf+kS}t*Q2{v#M>%Y!oXcB4t;`XqlHdqE7>n|vpF%S1=m+V|o_F1=cNPHlJ=0r*z$mB19Z1_19 zpOi94&}ttYY9pyrC%S<%IXR*NJ0Cz#7|pgKVyH3~$A$g5!bt+;X>h5SD%1^Jds2c+ z$X1UbCZw;3?8YRly_;^W*t?-hj(E0~xGdc|DNL>tPuqszDls)kYvXU|QtJ8GQdEq= z&{wWXI~XMm255*j&MXmE+b~zTQ1OTps>muc)y#bH%(wZ2?sCz8bGt8x$}+d>)Sy2E zWg}w$@mSHQ-eP{Si_<MJ7LzLb00Z}Q>s{_s0X-oY_ET6$tGS=OHaTTz!-TS6T zmDAD1w(^>O)KZ(AF|?2V1VINE(v3arUOO?Yz!YjJdCIOQG6Xh>_8$ygUc>D z{3G-%^iUuifYiiFJv+7ZrvscacZr@zOJZizdE;2qF6-8(`6Cc=`rzde|X9n_pC)U6y}EDZv+x;?w}k@i6wv) z9{BR0-D7NGkEbWL(&8ct?!y6pQVysVa)`=cy6Sn z*+g~i5>72IM6^)0w~i)S$rtOtI8n?oP{jdj#H>Uc7=gfzZOzpsuB0Oh#ew>M0x?oz zm4TkjzcAU6DS{Np!v@ECBCjd~PAdi62AvBsjXj<(g~64~*l;gqx*IigyJ=o)Lp+Z1 zYnnq!(J|lsl1{nfIAEDL%A9Hieq}DjbLR(@1tO(xvOBw)#n$Q!dc_UIhld$FKzy!rfd-Rv-AZA7}?X&IZ1Bw{FuMDxcnd%&W39AXSXNo%qpA*IE_I8jk?sC7l z?R@djBX9Ka7`Oz~;}*t?s8VBhEt9tB^^-jq5!W z?Ju5x3FUWSyhC_fJiBcBv{)V_``VQVLZJJcqaf|yFGb+R^{VOytweCezpFJV{V|_h zje44%i|SZTQ#R4AeJrVZ!*HWwFnLI;kn^BALDK+H(`AYi2dw#xmugs>57S#4)#stk zHgv{dc<|T;X#c2+jF6&Y>A~_XZ~5mt{f z<2xq_VYfGyDC$_JX?hinjTB}CIMRX|af!F+-xs*kcz5nth_EP_^#>+nm#mG`Oh(Wu zp3%Aa;py38>sQ7%k>EIRs>ZP*fsivoxvImq!(!|%^p)ov`O-+oYfgY@Fc}yl@wm9Q z8-yAnR}E=M`RRimQ`-hyd*$_(AiX0T(myc!Xg;vWS~_PDP5TvM11n0Ak#oewB$=;7 z*~zhwI}R_MT`T`_Xg%N*WnK)dQNVU%3Pe~^cHA0e60Q zA7zWi*+x+xR>xP%tQM3S&sKQnSd_a)FI6LkxW(P=udO>YOm&7Kns1=oS_vWqrvpsr z6>Z$_6*%s_A$Kkz5ar{jz^F=g2~4&Vy3{*)wgqw{<+%jTvfl+G;A|JBw9q8EWE%K}sAd_{22viXUuG-F zQ0saG&s7zwg5U%g2oMdHFxJ3?fWutzc4*e-wn8bK=-lfK zo^h>xB>dG|e{B5ytMYfn!q)}y*xAW9zqFShK9pjouZ8f=-2H<;)~Mgt6D!hgTTmE7 z*)p7XKEpB&3`9QpYhQCun@CSj;*svlj}KNtl4SBY#$Tx0KltR!X`W;uacSKTG&y&* zG{x*pq!NMA8Jsz0U`F^J7uR8vKj<1#y(Uyu&b(5SM#kIgL!-l9Fwm5Bb_CZ(Wl?&S z@vTcusNIRv5S@vRj87np3muPjzim z=x@Aj7|hUun>WcrI&OkpC~XHvagqYcBddQkL+t0UP#1c}^FelnFX@rdjL={hR(?kQ z&CoaG>&X%OI3 z{>{Ys7;wtHvREIX9dA(K9!GDN#o{P6iE-{I$LBF!RMd9PvvmzJz_;oB={lWOoZRmZ zRC06n#bVETE;_mIr6o8tNuoiCrGMZ>?7bn#B>Me4+9K)nN2Z~tFwH{9t>hd0zug_( zLgBc;f1V}PKWu~Qf939&**N~k+R0IsaoS)*?0HbTd_|rhQIaUtJ7~^O!0Vc4N#HJB zl$IqH9z?Z7)(4W0{`T1kEFLDcWTIohMUD#F^69ce8bb;>nOyR!imWM6!9^EDCmlf0-8${mxl7z8)_T3CAo zyOI$~S$#2Icel(2jdpy@mz20SBDa#0R5GpXR2DQ#)I4h2E61lSMZkm2h{2G2F$eat z{Pe=yNW2ZY`Lyn-V>o$ewJ}2ajE$i?HZi+6wo6r8sXBZI?nUU@K2zipQ~lnejOu6i zLT2Te8V3JPEhICNKvgxI#(C~;nWWMAGoAsl15M*qtj%fnxAZQr*zOhu3loPhKyY!5 zxWL3ww2wZ~gsJFd>SLwt=Gv?KC93P+04HCMoVhDJovm73x|_5%8t<(+!>0gWy;|LA zabgb+N#AO^F(5NE3e{sqvP2~Y{*qLD>67#-lTv);P)wKka6v@_*9FU9(U#^EN9m@Z zEY6flMLyKXi}_y2U$KQd*c)?N884;I6jnw(QNEmC!t*K0B^AXGil!_|F$d*|YpUi) z)RssYphO*;6AS$nGdOK-x~io2k`}TRx1*huLVPe4WPA!}gvkgL4U922`%m5e=L4EW zLg_^hM`9VQxtwul_(#}J9|BtBlgQCfT>N;uoH8?hUS4kaOc$-M%tyw~wYQ9c^|(6T z&%*P8oj#XuqWIYetf$2@9t>W--}D_`uClUdn#tP1f;VHmE6c{ae9%6JnOq!v4*GsU z%`J=Rh>4d7Rw^1ymK?|(6*#kE#N6?~SxL?4287Aub|Gb&>UE8!s9{Ek8!>yqP)k^k zgt(ZQxW^Wmc%Pl+G8)98EG0GeL#~RP)xPh0V>gS=qt2pq=mX*uAQtbRN8S{d-7F)Y z;jBN%Y@s5Vt_^1z$)$0)YhWjlT(5kp<9hQe=O>`gq$DNcqBbed1yexJdEViL!yDue zF;_5`s5^gN6TnkJCZb&%8x1TTPf0?cy^$dCO}^E$1<*utlLYlLREuOA=TgUqtQHI9 zE@_23k!(4jYmVl~V|ARY1BkI(bwuY0(m_vsA6*(*>0ajv`_Av3E^|AZ4D~i@CR=k# z5waa~&IYIJIcad{wfnE$1sH)3Vb!S|-8iO01cLFwWzB5~VCBi^ACrQ^5fXRkI^-$m z_8K5g*(sY#>jwQ|)q?5t1WF`+0j=vN<9rPlWxF{Zo}x;cJ_b=^Z-`77PC;SlR55~# zsW7>S^P0r8D1IOZn|fm_$#IhnqK|*Ujqd2}LfHqIzG%fNFx=-OOYA&aL(JeUHYd{Q z5I~RRl#ls&!Pnb@(!5(5z7+^w#dj!Z+Cwn3%DVld_>Bw2KYWD9D7h;8({eY_#tx4E^ z?8TJGPI!&iniVDy!`B=`X*$S??T0I@>#W|Q42cL@H-`G03YRPz)*iOk9Zpf=`7O+P zf4H=N8x}=5=q(6*52CqSb1*ne+53Jo>4^OR{yUI!%*+%L0097>|8AQ9RUo&pH8yeo zPbjyMpRxpDgzf&Ic?7b6=B0m37Ch^Dsc$fI18Z#=cg6S9<79xYk;NvOjy9#}peE2X znRr~|AaoRUxcNzQ(#tppUjOQ(X&ZvmDV~ooDvof8837e}wrB90>bOd+e68&N#X*d{;0~{T z!8Dh30m3QR<$WXe6h-yAj*3SSJ+huFeYPrmv-LpmQD`(%63f`Dna;6;L7qG9B-ewm zylT2}ZZm3;r%%L}P$;ex=hIW&E=w~ROo&gMTG*P^avcff}3yHZCO2(}I$+r2sl z`yQV$aS6U5<1b+vC7>YQEWBn-s)$CVcf9h#9hOY1mx!uUt!Eu|*x`M`jX^DgGLV<& zToA2P^3QDM+EbIh4M%d_D`8W}9L_+Wtvu5u@S~eQThD1{yvbV^oLNf z+;BaFi2e&&O|5iS4(aKFsj0B0pKhg6K%>(y)^vHK7*V2AHPg>JUs*dJJ9w#YN@cla z&cOQ>w;+ovokS`lqWUDT&-+l;}*m8%_ZUM{gD)o@Ugfbw9sOc9F`eZl+RB_ z-qDuJ0|Oql8t(xsT%kxv~JmP}=UGF{uHRe~c< z!;SiyTJ|}{m^-982M^cSt?(E`j&r`mp8G^4Nu8WtnjIzHl$JGJ;-0$al3OH9nTGpJ zWsZQSHbH(DUxCX&5(PbIg76U3OJl|LAXZ2um0?L&E+QMgP(s`4BJ)lcSulhJs!%Z! zMMgOh9xr5dS0`Vbx-=U0UVAWJ!6SQkbt7UiD}`P)sE^H4Y6kfoYEQTw*B+xS3zTH7EmsHV<}Ffdo*~Onmv}d8QlIP+H$5mt>|Ad;!=9D z39%_4k&GOut3D?|iMEZCZ(L>h;S)vA2{I2kpMNds^Y4{3t86}*?Kzyy5?W5})`^ysynR+tR#RTrb(#u29hQ3h2lSk%(@2KkX8pcXJvxl*T3*ZMzKbZnxeczOf0kIc) z@M^Q}FFSXAjDDH#I8r?Ut#S%cwJv6qEjZM=_e5nk!XD2MUC=R+iA|Rdx16;vhBqvN zqUYGK`Ln%AP9JN>!32;6N^2hX`sK7<@Dei<|IGj!un=X^yXWb2Z>J@!GvUKSaZ3} zRNb?_yN$`)5Na=vp8VP_VmVV3Z~`P^#z~&BOi;pZTD4im55#{b9aT=TlVG3#fX2VX zF`ncAK`zxWJyXbV|V_TKWG_tlB$gt@@OBq3A({Glo-Di_iV%h{RmAOYLlO&=E^LI&Vh?zm zr>=8mB{GxrLrq0dEXZyBCGE>MlO=&l`2|uZA9UOjryJdi-o` zX}AhVzfiAKlvpaS(p8pD@i4AZz;?0LIugvnGe=)4SM}H%`U!p(3h+oh;=D4pi3S<2 z<+y|w`7a<;J`EIZzRn@>iSBfl8Qx z#F}=l&ywh*=9S^fT7@Kn_zX@|Zh2~%y=p!aej6<=Q%ki^Fm9aFJMCi-)O^MQJ`?P` zqBDMO_}-Y+jojedF-t)R)j6KaGEXJ3V3cTnTqky1Q{##Pvi%FihPD$QPSrGS{MZ^0c8k2p%RfGYax+_Q7Z>-<~lCKK(d#sn1;Y(xnzPF%@yL(FlSV# z6HX|51$&7=Ab_(?d*;Ow5}ITMdh6iCBF~Jyl6H-$HA*O&pUFzoTel;Pkb|Q;2y^2$ z$k+}Eh|D2<&NfU}sj4!03ujR~fB%isEvq%O8*RN}H=S3C!vjC2mY-#kXgUPwqF&#S z2*`#Lwx&TXW(Is<*LERrY4?771+EJ>Jzs4SM$}*rUu6;T(f?k3Dj>~F`mV!*Xg9-k z)21E8^Hgjs^B{1v@;1Okwk;&`A@AxX=N!|~$rstCX-6#ki%<6Ox`mEj`k%A)lZX1? zp+2~HhMG6?*q*$}Qh{?&a!005l-CoNu^z9>;fRfW2uz0B2>-WH&MFM^!8+Bzhma3z^Ww``g2w+aPSr@3}YHHKG25FE1;)-uep~6aBrB;g(N}@wG|y*|jg*3{578L}=Unu=8g$R=W(rr>t-Q&@n}ql%Z|=X-mLP4+je=q)nuaK-msV zs=^Y@6*|Z=WZ&?UC~?8}y3)^LAh{#X^zEehTFm|*%HDxTv?xlqE!(zj+qP}nwr!lU zZQHhe%06Y=uexvgCf&(P`u>N#*P83Yn0nLtM#D!SKpgVLh){q9We|)Tz7I zf4~dN-4hpCngj6CrnG{Mv;qd5INQO@Xi>=y;rIC9EpHOs{zi!L6iV-K*%WO#Fyx-1 z!pen}`!IW&i@!P;`ZFNUd4eO)WDtUA*BR9p^{t=E=P7rZYXCn3aUH5?$2*eW>wxXb z28}&Y>U!;~7glXk^nO2La=5}8$RDj+^nbn>sz(EV95RCLnjFJYkcnAT`Eqkxaa~Y; z+OVolrc>t?h8xed@y+O2hh6S^R}HeYr>;C7gz?9W52 z5^xQ-*#q9~-daZ8>>fU-yWnzw4;Q^%9T&7-SCTK`zk6fk;zIw+*%>^iK2zFm#Oi#o z`*CsigOEo=i@=qibbnriILQ0MJ~?!;)@Xa=;51~yixGzX1b?z;xI6gz>VIl^nX7$| z|KDehaR?2e<^K?+eh-NMT`Bax1e5q%q_uJ< zpVx3Uub|uyH;deS@MS}_H4~jwiqu&(ZzB`16yN6lWE_HPlD7;p`St4pOqVWSelyc` zij&hJXD!C;B$g$@iLWD_>LeOUgi5)WrU#3keepcqzN;O7%AsoZPjd6uhzC{S|Oun!|#69UP-o^;M92Emc9U|r$-p2t`a$W zYBdUIMTjNMGsgV`uhytCgCmFUiI7TGs>RjXc=@*dZpZZnwgdDD6go&ln}EvfBO6_v ze#ptqbDax^yzAV#TlPk{iSqZVVdMDXGU3Vz-&Z)ZZ_him?u4L^XE$ngG>o%b0~1Z! zH702A{OrrpaarAPR)I9W@t(P|6dkr;q0S@)A2!T}T$iKifyuhLF`0&A7u_6JD#1_}Tm3jhCgFts(bb2YU2 zkIUmq^WxW$Li(BQGa{dnNnS0y?5mgar?{l&<0V9#%PfhQh#+cRlmY6>TtA`NUux?hfl z`5ltT`$`e3+8IQC$H!9$2|qX=JhnUZTg8f!-BYs!k4+gD)6^&z3i|vru@P8Fuw<%B zp=gSmW&~@Y-@t-2mQ6OXCdR2s`_g|N zstrvHT&AOGzTEAo{m=SX1R91sA5at&KF*9Ghc|#-yy?sa-Y-k<)8%=e==S64^z-xd z(a4J_xXGD=kK32KCp|akpwHdG<(>PJhu60Y94R(jdP2U1kXJ!NG%UpvhFP*SZBu*d zTPSE<%gm~PX}Lj*&4|*lqOQ0?fwjDZGNr_}mBI`zlqv-|?i<{04JD?CB92fo#kG(k zK~gEIa$s$SBnr;nizwYKc|VQeEwy48yGK%vtlNG}3AOVNoM^uWg~>k!O6nQZ$-&fA zi&z+LI;W7rcaeej&A%ZW`!@SuHj=bq`rkwQfYZYc}m2DYtBlj?CiqM|sYyne2iOvr16we(X3MDHg9r z_?SJLw0X|yn3Vatlqm6!$bveFtzy23B?d6-UK-iw8cW8mN~V7jHTaoEr%kr&Gj8`N ziQ~rG9P7|W%^R3sk;Av9UGTsnR^C>hp0ahDo2xU>BrE?djOk5FXdd-!t;5^0o0%`A#% zw7jSwl$7p2)>=pC2f0ACZkPw~il{ZD-oC!wSq7)bFiDLhVU81j zb5-mXg(8>qMrRyr{Y}Co`h=&hgm{$<^;&;PVWG}P(e-WX^Lh|4C?liZu_*hc1W%a{W4d*V#dZ{kda>TNUKo7 zi4lQAJAjQ`$}tWh&6y@mVtKi%MX(O{)rpqol{L8NSYr5a=t>o9RTK=o;l=kS2K+)1 zQg!N{ze$%jdlN&rElJ9Q`>=A`RIX(w`b*sp$wLfGl`Os&pZdmtVzMH7ZY4Y1_}<&_ zJ=Wy=7Z!b|M;2m$6-mJhCf)v*B;bN$AwNTA2G;LCSpFC^T z<+jrZ36w!63M(5-5?KPv6B11OWEoH`WN?U(`w%vl%>Wlx-H9_NP`z6MS!AR{vz8I- zN^4owC>=KX)yzl)?2>+mMu$l~ESYzZLJj@Ti#a{Lxt&`?{?qc|gk$=)S&^mR>yKg^ zi1@N{2RETyJdh><3pp0q8bql=51zB%jb?1vRuM$bTYEmyP<=^!2k9y)aRUuyoOz66 zW`HJMM!j}|UaQsCoT31QDm!2S{$& z*i|~&HUti#YL*t++Ow{KPQ`K36xAga+FpE%6|jTUta zQ%e~BNvT3;iN8+Zb_ZO&a{fVxQA%%|ijOoTigv%tvzw`Sf;q%xj9msI$9#;b<;ha8tQK!Kz(V4r{6G6mO6QyNy3LhcZ0%BwGoW8rrXw< zq#~)$2DA&+2j--!cG`7eihB%trBsjr(P^ySHjD5dLNZuM!n&EI*u1Ls-(iA9x8>&s zSV5YaR-Lm71)~x|-VIXw=R}9T+-RL{fSX>t8M*V~y6Ia}&X)h?0@$Rt`SAb=k1tjO zS}I|pey&5yR(=?yWi0JlF>_x)RG>xQ%VQ!G9q*OTrrWm#$RTY_q$7YLCeCz(Iy-u6 zw!}uUWv}o;=UGW$XBnMol$WN2FV+0DC9i;bIS7WpnP`uzTfpd%^=_A&4yl6tvv_}M zT2KccX}l~iOK5PG&KySncg;$luD+(CGuDqo#E%`dDJ%QXh*bOd?nMf%^WS^R)!qJ{ zjrEfd{e(ndylV$b7%&0Ok!#kaH7plvrEWNxP{0U7ii%*n5-8oN_>Oh=fVhy5be%OUEMu`lm~G8ie5 zvYwNP6G)`i;ydL&+^4zQuhbK5`6tXB%E-l!m-rZ?YY)DkmX>$o(K!bx%@gR=cNnT0 zzJY_cfrl~;as4ZN9?xf)-psi?-H=_`)<{i9yv` z`C48ONK=L=JzHTK_ZpE!{)vVYJcyC zpS_s4h8Qv(Ft52ma_Uk{PD8er zQzIeLABF-5G=Q1Y-Ipt%{NZs)V_loTJ-_a@54V()jJ-K;-OAMpsYlzA>RW75v>ci{ za=wg6|39u9%?GaE$s9${4hp^utAa(S^Y+n)zU7-2e2TOAD-(PUe$ z=r_?*ZEI6)bqL;G7si_uCn2go&l^N{D{|v-i78H@9@v}^#-Tdeq2@aZN5Lz4Z5J61 zrO(05R9cnI4{CK@{DJf%kRWjM00Qe#$s=5q}a`>x*N;nI85^lAb%cp&8yL=gDcBFN)Z>xgdB|&IQnjm67D~W%ryQ`666a(g86|Zs5LfL8k7Kwz00K z1u#n5a{i_VN)h*p@dB9FgnKv0Ba+K+WV%I@mlsYqLrHR=J95jQocIBQ_|FnM$P|?q zr%^+K&AIq06rJcywDD?Lxja*8azR9MzKkL*QEU3C?V*NwiBBl7l#&S}Dhq4YNT<4r7){OFyIdM;->FKF=g^k)WXpaKb9 z`8cnm|Hx_SV-jW_+{Dp^I@P@@?5j!h_Pv8um`aSPSla|pb$xGIC9fS1Dt zlJsOjiUd709BGK$WU{iQ8C5GU1?RFKx)L_$q$mhfmw;OU#ObedP02NrEGi&M3+rYG z8iQre<`g$dbha|T{l0Z3YMZx}@!rc63V(vwIck9U5M+Osd7hk8?lPe{QdconIHIPL zle9=n%CjKU_QNt^r+(Rjt6)lLAgXP-i~s}c7u~fk1+r@ z6V*^YIUrpumcu^qg^$$4kh@{B^=FAqRg~ZAW>M!E$ zZ-mhS_TmrHbJ^e#Me?Q?{<>XE-7CpXA$B2zM>Vg^{0P9mgF9k;lw=M#HpX7VZl~jy zlyu5}ig%O~{@>TW5lSW?;p9$uPb5b4TolLRyU7 zm+8W)w}^w{D9oS9ITi@ZS@m4giuW6!7#8?`gK5$+3a(aW$^r+OJzKbm$PI`b6M6p} zGDm?#Ay{kM_km^?9mt-6HS}vMcgcCa1aG9>=J9+gp2|j(2Hu^N{yt-7W*3Dlir7jt z`MBLs8laZQG=Lj()lrgk%$OWITEVP=R!G(%*1iN^FWKYorEz=9Lc(zlBy0G%!AxvY z$Eo6F?}t9Fhry#ipH?8iR*8Z>+90S&{-43=#-+d}5n?sJU>7!XTQ`cZsM68VGL2V~-9C+Jt9d8J^e)E2FoZ?SQ+rw*!j{MK03W_4#lzs9s}7&j zWi@jIvshsZsR7n8E~{Y{7H}pTy|o12;c_vku|~C(D@I2I+vYGD)qUEt3kJtfwbW#= zzQ`>MZB@W>ds3Vosj>vGA>yL20!~9zW#}4#;nRQKET8{}BFNm&Su66(N)Z2bBL8=+ z1Y1)>XICfF|F8-EvsZ4b{9l4#M79=zY9}7^fm+gXb;ooNB;Z&B$+^jzQ zV-Af)IdpBZx7QtFS`m=13`}o_$_>P=ZNH9S6z+8HKd^m@=398R?-#*$F1WC)@l@hh z4FPKCrvYvd4Jn-bVdEHj^PZ+GTanuBP>@B0ES=v_;7dZp@W7dDAT{D)ig;40#CzUx zsREYcvc}e=u5t5}8&5T01c3J97!2A;Qt%c@)-?XqbIyW`k=`8KMBF(towdk~C$uqD zWKWE1@_5PXL^EjY(_bo2)z*)AINx?D#`~MV5>wMo9j3i4m;D?GDZ+7ykki~{5@%L0 zJAalX!-16wcsN^Z&jx#u<=ysp0%8APi8+EvvIX5ZrkWUg$g06lovZ}BVDa;goKb0- z)cXXjGv$z1nPl8w;T=4}`jMUaz>NQMr1oi}J2hye!iWwHfC+x`;MAg+Nlb4`uTna$ zR#dO4Mxc5C&oQ$!SYVwDXY?-B6sW-xO&atS_#jabNkpi(Q+QuB49@&yiR#tOhVaV? zQq`w5zLkr-C0)uLL_~8)CdgwLKyfniFFe|rOLJuE! z-qd4}3g?tOFyq%!&Hm#Xl>WT=&vP3p+1rq2Q-Eprg_<0ARu=V~JcKnZk$Wq> zSrG+YR3ZQE=CkjTfQRyfzlzxwH>_c-KB|#ocCvpJCa#}5@5XyUIsDjVNYi>&3%`kt z_hBGI@cx&ksKpdNZj3idQ}{pl9oxESo#DUsmDVrmfZ=~NKiQeO>;EU)@ISxE7WG~G zO%5c#HGRfYJ`O+}&&?k1yB*v;vh^xQ@7Y2*?Mr1L>1I(8q!tp>wU@PBc3~;Eq@5lV zYLr;f#GwrP-nWz!%n4`Pt|I0xs`)Pb-QJ=UzWLat%7HqE`s+x#qo?4feI{vhKh{vY z9=Zy9=_?AAOtc)TTXNrwMf0of2HKt}|6=H!TQXlS=Qn0tTlrWnGRqp+Wp7x<(WTYp z%*Qn$_dprxP}|Op^4575hJvK3r2K5Zc%yNw4bE8m zfyRH}=0TS3%J**AaFb^w6)b!lO=m;QuVB1^{cm6ZRzp zd^_dudujOmbgHk@+N?W2B-Y%kvW~y*?Lyo1EgIf)zFTy*Wh8-lbV~Z%;;sT3!va@K z<*aAsFHUMpYGR|_sfDE01vIP)(tTy zvbeAjcF(a}6GW9iYS|QKROC;#XWIt}tf>t3Z#^#Jq-_)03cj*#eUf~jtq;*s{6o8s zI@)-eGgR;nA?ZLK3`*%o1+*cOM2pf4E@-}%rL+d7ZDIc0X$s`XVSW&LW}oWNUWfC6C@u3<466Yy(He#rIE<|3oM^t6Q}@96QQ6EJ!4nVeUs`DYj+MK0 zVehk5;rCMGs)4ZFK^>{*ed&$Y;1RKp-8#j<;r}mojTk{>s#SpO@nD*FX@ez`PUa%` zsBH3iR^RN$#03mDb}TWV9!^<{4e z^nL)D*4#a99TqrSL|;8(4878Z;J{!~LH9c&!9<@50YxM?K-bFngJC$3OB4t-rA30+ zz?Y;11YH@I9KbBLJbkf%Ni>DfPQC+0W{z*5j<{j>-!QrroAScWsxPr6lDpj_!q)Mh zRq50Ng6sz>5QzNt1&)8`uQT{ru{ETil{2GfJ&~BvKBR%L1r%cA(Nk!g^@;I{1ks$f zQWY#>t6?`?={96(H15tYm+ccD6Q;R6Q)lSC)S#{T%%~)Vsgeih&kt8)ly^TgJq9mA z(U)Zwy*M0GCK0?k11U?EtHEhtE^>>c6095+T#UrqCFj9h?~kBqzHjyI<`Uoxf>t7| zA0U*}(X1DiQgF3mY8i{pSQiRM^$+xtigAc<9;09mzR>Q&TUc*|o{sHEo1i+s?S{Ok za*`G)4$qZS=Cr}B!B=Kyuy|AdnX_HWJ45`q20;4Q)^XdIR0iTm-&E`~qq|Kd3SdHZ z%dUBXQ3`F+M$Lu6RIm2H9>PB^x7p3qNZ1X{P(NJYjc1DBDM}xn9yxZ!$DB$~3{9@7)o3 z#erZN+0yq~B0G-3+!N%*0utMlWkBSh^Ookub|#KVlGrXAIF1pr6cqxh&HE+I7ugbz z>ibV9G+5l`+p6PGax3sS74SQs;>cJMk()lB=?`9`kdi>Eh|3VdMO&5WYAdIdAhsTe zJlJ-{rd?tGkW2ziC9G>LnDRdLS${@T_V7Kcy{q#+GsjG8!8S^)07U_Muw4){Z)@J2Bk8F_J zK0Q=@V+TiKQ^LWGpXK3D!E9z~-3#SLi(p)oEQF;qA2vT5FqWpPRRm{hCj#c9-fTyLXP{3t#Ff{0$7=(ePFW^`Q!=o~er(fuZF9P>bEvJ*{ zI1KWja!2(kS5Brwy*XWAFyrVi2(F@8zEd=6c9Rh~aJ4H6TRjEvmjE{`VLZk(xkq#K z#BQ0d8D0_tZ*{i8BT~kwS^_+MY@PNx3{RIKmf>0tVwm-~pC>~GEFvu!-;LA zFd!Oli^MkenoIQ3ww?kiE7c-WBT_|jG7j;m&poX83DKN=Q`xma6n2-V_ss|gzMogU zlFKUb7>$m8=M#W^8YeB4G*65nO_B#f?M7ssUXe*Ji~s^!;ix;RmPGhKjq+Jh80ZX%l)2Asq4X>p^*o27D(ga@WDIgWvpk-sdnS3*h zjCzWdA0Q*dqCMz?IWX6B?86!K@pj&}311c9&fnFQMXUCZMY^>!uyS?a)tk9XcYB4N zPRloV^Dy!R!4VZ+`zl;=h9jYtP|p)&)PG$$Ac;ww*#{ zf)>ahyiY2Hq@(|`nP+MCMcn`a90n5Ci0g^4_mGsnEsmxsVR^I?Nh)P=9k+UlkQSAV~IML}4+N#%ioi+iNYG28Cs^ExgC~apH5rSI;bE$`cu56xV zL`B-hF$9FRI(}ZVp+OnuIfxZ&`a2!mbI!zfj%13$#C;#S`gH1~7z+lA`vwf&=RPPS zMu{N1E{F|_vD#@et55;lDU^sLeXN~Z9h?ge%(u`p@{GCvsIm%WZn^)wSD1y}Rh7~f z@Szynd28f0{iq5ZFT{nZy&w!q9iL6&zCr7Am%CX=Y-lns=aOkmiN6hj5FM zwfv0C5<-^g#xlo%QxaQ!Og4W_YQc!3Zr_AwWV}1lFtyZVcuO(^cH{=-V#&Xj0m{mt ziTbbJS&IqjZu2IkCWN5TjIl7`Lu|sR67@Dqy>c3Tq|{pl93F9$HcKePLP7A=W+r%q zSZ^<}k!Y)6)o7P=_h@BWoQYqUu;2*1KX0onmy)W1W1~|QY7=LTJeI!MqTzbec2gml ze>|-Gc{NkC7($9rEi@f-xSJsKWr1$H&qpipGT(wFK>m!>8plaODKt$7rjZ@W5G72w zyu9Db(yn~)fT_$j=u$6wEZaPHY|XzEg^$hw3+&p4uUh7sb1PxF-2Kln0&ktu!f*M& zXBoX%*EGvz#J3NOTAerclt)osUvXCY44`90sd?;*XB$~{1ecz>ugn(r0JS&S+L$NQ zS1nOj!VkZ>=4YIbna>9$_rN|1cj{8=*s%9C)JbX8eaAVd(`qd*)j+C!3mcVAH9Muw zR6iH?uu`QYoI1SpqEvMbTW7hVSLKg^VGmi^`yCdDqD4=B(2VDBz?i`N*Zq{xTFx9Z zKDa~dQR4?m72~#u+EJ3DRLpBBy8KhEPPFJ3fjJI@kroDD2ZXJzV#!b5)guw^X{@7` zkr;fz%A(ZHNFhC?_l#h?k96kNTShpUheyIIF z)A;nY2Y5Fsb-H*1*uGd9|HcrO2B%WavP>~{?eg-O$y}1fhm$h%&d9hwM9PVla5BP; z1$c5uzVewcbowLA>k+r4n}wc^ohGA%9VkLIHitdAr97G`D3nazEE7C`FG=D4x&C{N z*LraVSLS+eCA!x!i5RDgbZM5tWIYhT0gu#~H-^kj4GJqlQFZ{!CZ%0xg~_y~X<@xf zDMAAfe54`#%Zw!IN#%k)66<0dOaLyl2_K7%@-dJ3ATH?WhtQI|OqQ*cMu5(D`Jm>( zmYFP)wyq|El6D4DxfH6k?es3UdaME^E3Htme4UK1RR>NCMq5f6wX^#ox=rwNKN(Rn zNGEFl;Hx`7If1Et*L$3$e{qdyUv68YPVaf^QzyFlW~eP~5CE(f!1$1K0ur`1HkMB5 z_6W8(q1|#s0GK_x;jTB?4pdV`Uwu_M18mJGZES)ZCw|QdvB=!sAEe;AqM!G+m}i#3 zX|RyzSCVtyUem>>E57>^{x4T-rQ>m|NWRtuvN%=BD(&9E1zs+0fC`;ANMy!IkLCC< zBq_l$RHaj~%wSqSi)4rMax?VWl90X%GPAbzOoy~Sa%K_TVdepkS0zv~<(j1gy9UdVpJhAB|if?Knx+DHRNG`R3}~$m$pg!-fgtH)&bLJ}+}O=B7~6 zYL>88#^3I&d%5L-zbo46S)m1v)o@DGLCydnebC0>Exa;npdz>T_I4tg9NgIOIeTsA zT%jdB=9%1fGcf22scztYG5Wg#>5YWBO*#!fTIG?`nCOcKQ*2}*2vb^8tG{h<6s7ld zpW3UQ2Rzsf{SGp-rYS?~GHhE^zf{BJZBJn?1QYSNCasDji($gphLo95PR-p?@w3^_ z|KZ83etB1*!U6!q{Dzun|5tyRgN>{CZ~E;&ezFqHfuzlL#GXTHg;~>XQpGG@IVy0^ z)vWS^m@*zW9d9H;q@?;%2s%KiRlMiThfeJL@(jnMn(2X5k^Em~;`UdkCW_RjJClYHiX@u}e+;d!BW+ zIc0?${l!NGN#!(8H0C+WLMN*j^YZL=)2&l2E8VrM&o^fK%E*x`2WrR*y?2)uOA{OI zM$O&+27h<9zbOruf%)aId%j&*Ayu`4?~RS8>`4|Al|`wSV?6H*ufhqvhfZPhmCD&{p?UT)MPv zt=6e4P-C;rGJ-3**%b-9-@ziw< zhI=iH(`|-&H|ZlFO}pg#{XTCoZzS8Rqsev|zVRn(YDIid>8ff!;J7+zr=tiKre_ac zO?@Vy?$!53{)p)w-Jww1JBauUVV8PAIjFxA?1Sj~u$AWD(V$*7Z1|nvU%z@Xn4V+% zvYx7Et9S#Vh&)7DY-`9R27^Hb=(PS_8(BVRumftaC+;80r@gGO+-N26xaHWDuX(e& z10)8!OW9!Uw*oPRW{nxH=HAvzdm18oWdT5~vzIL7XKjJnHr3@1W*#pWz^X16ifV{q zW8XvfKY)7ZCfZql0^wjl##mOU{2Os5a|X^YOrj}+IsjA=IOc|=n15DVGJ2$okvB_s$X(!@rx>YZ=J=p z)8MIf*ZT}~S3r}9a-GQr5T zH^x?zS((3yz*%;d$8j{$?g3#sMalA;P-v}TZQ?*|T{$_M30R@g6jPb+@B%J;WFbbr z&UOX*y7ac~!dp9O-Pvk`3pPWNboyRcud|oNZ#Y*|3T6 z_B`625y3nvUbR+Ui<1MZB=e$>z^A~?kdT^3eS*}iU?x-m^*Fs+cq80PNM7+4{!Of! zk2qZ(P*DM=s=^@U9*)q@O362xvB#K0wXUuAMWGR_oplwI^*G(4TX#)NAbUQbf99c3 zON*-c?RQXUr)CEw409l8aCCru?oHygh_)+?DtJ(6BEI&C2}d0WS<}&95)U$by4|8| zqcjF0R@hM|lrzMpR68yz9meRZ1&m* zig~A=5wD1*uDGP`Jb?jw9Y-7Z)+os z(+QTW7A2|{ev+%0gCMc_0}{J3>?QwA32yN7w=Svnl$p5yi6O)u@xF(jOT~WVGEf~c z8#&%lVwKkkG_c(?cacnqi>#{3YGkEY^_jX=aR zvnBH$i*b8-p#ui#(uyYUPo+LMw?-1nK)wROqUg+0p3*NSD;Dk0i6$XoV(ibUtZsC!J2>pUJ(5a_%al8k%(bg{_3Q2+9DbjRE%Cb|mU508^ zwtmLVts)<_g{BEQ$4mF$G+-t|cZWBXJ(7j<=kSEWzEdUGi65qofzwmdtn<1(Z2*v?9j5`h-!H-fL25k;-nylEqiql zaG5#7(gtMm3@gVeEMUywRRI(O?OIvrXZp@c% zKG`p@UER;AS2YTE1Nl1Q)08Vj8Xg2YvIHmRa%k>%G&Jq_Eg`y;sFKh=v)ilV(slwC zA!jj&uz6oXg4-OEE80vvGT2upzi9)(E$IwJ`@MY=Hx=LmawTS`AvamUJv0TybBXJn z8oDZbds78R$Q{oe_PM-&$U>~G(Mk16eKGdnjkw5Jv5=7-c++WRHGp)2!zWQ)CwpD< z!_PwasPnN2vpPWZP0Tfwlrb4z!Zb5J?MTQy>Z{vmkA@ zt*ysFTOQ9zVg!xayGU=+i`-i6OXAgXV?VYehdmON_C`e4|BN9oWFW_FN3UO2U7s5^O5g)10Eid&K*d zO5iG*B;pVqLRGwK%P6F1No_2hvZ5AT-6Sc^)l$sNHbHgO?)h zqYhn8e|erX8&9onr>*5krB^azR-3HfGDd%S$cHMcSnzr?tx6SBY7sIy;I+g0r>8(m z6$LB%MR7$t7_dQsGD;MH*H$Y|TeaJYjDzG$Qq)EZWFi0X6l0Ld690i-$Ti!p_$eA5 zyup{6UnwBg3(Z9d{feOq#AE(rEjmmv52y)#B>y}(Ky2=%LxN0KD@3pkfwXT-F#jbZ zOS4rNc!W4&3}Rr_ymo=99|r!c1QlTSz9IjlkOsqxmo}K9UL(3mE8q`<(o-GvYdBg)e$s*X$6DJ19qjs$u})XKCS-!t|U>!fkUldMTA zG;Dk&nS?>EM#xW)Wr5@5uL%v7UR6BX(VB>a-IZq&z_BffeEq`v-KNN5Sc!>{DV5j6 zWC`8c#g1}ksGpURh9Y%4Xo;M;1tf>&k(I&tinW zu>ZS?@#N)Fr}C>{O#c=~{&(*y7gJ}K|5~@8w(0cCFY{efziiKG*iIZ5kn6y^5Adw}{S1L4C z;ZX$5;lli7fiU%A3G}w|Y2#`IMRaReDuXHLjXG?#B_41TUqx-Ww(<4h?(t*J>ccd= z?9zo7lfD_4ppSJ*_vi#wG&aeQVAP}4s)rNVC#eOMPHd9{HH{+l=z^+oXcV7JftM?h z^-%it^fdyFfobv?9GEhOT>OCiW&SO_A@Iqf-(2IN@$QsOe0`a;ruSwHZS(5v&e)Yk zpKZhB?F^bcWA4bCvkNC^@VNZ$o-E>F&=3tx@dR;}EJ>5shNj*G{b!v~kuu33uFO)H zpzycF1xz_ut5eF;s%ebDdA?Ff5X9?xp;w9l3&zj?8*__2>~7qS(D!z?9#coU#FiBJ zfHL`vEbRz|87iV`6{7-X*>wR#JF>QuN`QdJLOLZyK-M8vkbjm9G-<*v6=Qx1qI49z zfRzNYS30SR`uZb&FKbJv#>!rr#!in|0Q1w^w?Z#h&qR`wZq2Aq%gW8tcezY? zwLEVfy>2`hJ={)FpMq~8I_pRo<_s^rzlS@qIK!=QjC`i?j;$xkG8jdE&D7Pg@q=Jb z2d*G5(`f68k)4_AI&nUK&u1S7v{U`DyR}6(`Xz*VaDSMpO?@Y_$Z~g${Xr^0Cn1%z z378jP4Z8>vlw)%cG0zHaz?4)taOr9A! zVkZ?WXI}$xh^&MQHSI2xu!uBiC6cVr;JmJrjOeCf1#*P^4y>_stsh(S&h)fT{b{UF z>&ASUbJcOgh;i^yYsR{}>op>pDZSE}L&+thIC+Q^DbjhaR-w;k!+lgt%b8sSa&qqn z&nTw=ge05PX0fOgL2exW%6ZG42bT`J4VsnP7t7T}Q~S~=@lv@P9GpTOjcJDBcp>eF2gtIE zK3}^}OM_u8%XN~kMskb)^(UzDR*oMi+;cEcpQ_57U;DN1-y0dGF1#XL;Kusvx^?ou zat4jawSb_^wyN;&miLcvt38BGpj5B?C8$xnO%^Jy5NZUUx)&8KD$s?laWWwR&z)4N zMm5{nMTnbCnHZz&diio#3KXOzs84O*xa?Yg6-%H(>U%c=-IvI}+XHJEeE069$iGX4 z{KJHzhr`jVq^5WNl&JIMdx*l7TbMPM4BzHMdjE$`pVmn{9CxI@)VH`N9JNZ^9bGEP z9O=Y(XTcXdkEFbqnvCOEQb=Gzvv=aipOx=%qEXE^yRn4cwn!4}Zo1@d^Xh=0+_A^6 zJ{}nV^^Us0K$)J@Qb#{L?^WTNb=~xNmTQ96`9hpou;t z0D#|xp#MK2v$>7Ev$LU-=YMEku^PJ0o9(E+FLnLp^p0cFwoB~p?|XkI#FlDu8vdBM zaplm6=qZ*<21LVCzQ6Fk0HIiN+pZ-`3L&(&n~4`u3RWLnCYreB21^}yOk1)?pk3LGO4Z9;&TnTR~1Ei zcT{3jF4M2aIBk~4(yp@1!f0&Hyinna@4lJiA3F5t;Kh$gMen9OTs2O458a=vTzz~z zec|`&W$P= z4LO}*8!eX3rXUC7|m#wS6dkMtEkm{rDEe?1#Yqo|JRSTIMFE4$~M#rTFMmZa| zGO^eu*>;lEc3`)tg%!bWR=+8nLz808ne1|6UUZ8(pc*>5KktuDc^(&f&~w?_fv9Rl zYqh?;}9hFSHVfng|=af}g=IZzRFr_s-p<9&+aJL9bA%pK`Kw@`^R z?;n!7y<2MIyp@YIpO8UC!K*=5?yYqNXj7nax-cLE2+771wcBYHtg#b{^a^jBE!s|e zD)Iphpi(vh*cx-33oXQRyHL1aY7OZuT$byAG8^;e{BLX3^{10D%Ne!49^il8y?je! zv)0{uC9A@U;~eWk`#dU^0`G$O7wvGBPb~=Ak374E1V>@jW4E`H5oohR!gHhv&}n~T z3(lB8ePw`B(afg(s?ndW2IA30O0pN3(*>h)SKqsxp~42|ppeJGKV^=MEuJssyGSKS zBTetKLhA(Yqn8RaZVvY)B4{Ax9zw)~sU4_CUKdK)wR{%#I0?w|z_WyDn64>Xckg~6 z=ECO{2G-$&dBPYNMBtNvCNx5S6dD>am*-5Ap?mLrIVA)!Hf)MBS-+<;pvYas=(n#c z-1L;#!j09E(_|QeNy8H!=u=>}u%3|P8f0hapc|>41{jB=^>rHTFrrJ%&bBTV3B3xN zeS`z}NSiCeu1WHkL);H1s9itKnxaa{#XOu<-=A!NwLnif7DS;CS1DFkPFu}QF`<*{ zlw-ES+yMNE-~Hgc&zt!xHK!>IS zxz7vf^qgA&wtn}-6mOxnNT)&`nNnzP`Ln>1WrxA)$YF4BKfK&OD#7nfOW1raGMS^5 zOUL63$d@>b^>hvDn~-kxa98F=-&Cw%rXlc>MX)7n!NS-!3Ek$`b3z{#NANU4V#;kz z!qFB23K?sZvv+z`y09)jnI?jT0ZwjYbI@)oRyv7bVpjKw!?^QM9xp4LaLl zW=%V{k!-t`T_(#Q!?y7QE-qd(6GnUAC}oLn+SuBBj>)%G-fDn&7Ny7-A9!-)O-F9ko2)P%#(*XTf;JR6Ho}XjB@}Q0v<^Av z8Vx^HTS<|B+6MMI!OjWQtSo_yi?t1p&Ef%VP-|Pv&z9e$^f=B^fT0;XRcNAgJjcBm z6kb94LI|G-OqJe1_@u+}X`APn(|*f92b4J41LT_w;+(`U7R|c8ej}Dx2v+5aQ&Lo4 zM?oJxa&`IY9Ar%eZzW{43s`(IjT_%t&|K<+JL}?tKK&&Wn9^-Jtz{Yp}ig#y@WEA~YwpC|Rxl#Dn`@q?+La^k46OR4jOT$N&bL7clb#px6G3!^M9% zNW=h4tL6ZY>%D5wbzL+63LuzpgtEfsV;Ye|J$4+E*yJj#CsTLMdGl6po@47N=qA&b z?zrmmr9Juz@y_b<(bK*u-s<)E0duI$9Rw^uOdDC}2FKbsX&pj=8|O0@X`2tDt%EGO zjx5Jd^Ng**umkBdJ=v%BfuLUkkGVJd>kQG+k)F*Ht3eC10G`as)xVkptWjg1)Dm`- zebcfrGJno#DGdkp;MzqB)E-r7jTv_ooAJlRT$le%I6r>}mM?RLt6rK(9IuD2!gw90 zTz5)C*7NVfYD2-?7kl^+Ai1A96Cyq?KzD(1I}+D8=R&T1nbM1evctTKN^37Dfop>Z z8G~{u2nqM4F&4k^ogzULIK%xdcZ}PEoxcL-m5w=oh4wf&9ov1i9{1qv>dKkaIG8}e zXkpSBuN_lsOCMXaNT2-Hx8&^S3r)5wO}*+Z&j(f|->00?pO|>(y1CkY1+95qe5X#k zV|j*Q6S&Hcq*DNq+d4zs#0@nL6K(H0kiI!&`-wE(aK6`&dmbCjmY0~xIxF!Zv71H` zr(!4SUVgjVwo;#BNJS>9Ql)URxV`dDf}V57W z-#Bv<-=j4IkCVekfg&b>E7oBy6&jf{95d)|odM24$G2i8=Ej&ZfHtx{IVyq$x5?d2 zXnIyRMW}s+KStF2!;FX5kB_=AmkVB%05dMAjzqM6GK};9Po{!f5hKnH@aP+h0|yKG z0I`fb1hI`5ZIp-Zm^3m5m@id=M36BUb8w>7Y03;*J>~iocOI!hNrj+IrO@W+1+i#y zFrFxedyV&Quzq>3yOppZt;JBAbUpc`WT{rOr&M(@11~nolv!3J%MbB{b!|3)+wbBE zy5oXES2HopQ$(uyxytqr|2-8XS|h(^i|=Qt-t%RSlDKzXK2xRocjb2Tc|FWC@)yVcg|1bG}`@bfC+mg`i2Kou1&}Fd=s+b^;UxpLnbh~nsggS< zCDRS_$htjMBBK^PQPNPC)mx?XfK1dxE3n;-#gm=jz5=!I?hsLr*tqaWVF%sAewuW- zuLy0NuRr>Y&_rmDO~I2K1;}`$s!E=kw=&EJz#sFJ(LJnr78ADod~;p1^Y|7wH00ND z;nAVPXJD6^`uke2B#T`_299Q7?O>wFJarj zBPgjg=n9P46mKN{*He#E^J1J`STe)+=GY9DXq7_rW4VJs-stS_2@mhP4v}LM_^DT0 z<}mK7>9!wT1&kRVf4S-@5tDh=0s!O#h%I^lmjF5#|Dk)RR_V1~|Kk}{2xnR?a4+5A z5+m3EJdqauWaau;zRhqcRteIMFNp6Cv8LW9rE96vrzF^2UvD?(JVhsbg*;K0`TICr ztRJ9|St$ZyQ61wN-|IGnMCs@IW6E}DZKa5Pe+M4E3No5(nh0HF<{BcQ5lwdA){Nvz z6R~n30PFdcsxZZD(tB06{VL8R-G@Z$nplQqN>L!s&xVn%l#l%yt~2j!Vs{dK*2D~S zoe%~lRiq$?Of8B>7DR~|ia~oK%|7b#YySB?9;t?}X;m4&oRO=Q?fXx96OQVsrZIbu zfEB$~8FmNtch?SlSAD`-EN8seeCA}BxeBF^T`R_6d(^Y3IgcYBEXJDH>Ap_A1H8&S@r7I^t=sC)@{Y z@#+ZiySN`y4_sBvWkD-=f&k6ZC z*-nsCxZxM97x7Ghcfj@SeMfPWCY7$-jQgsIGru>us)W5{V*<2YbO#*|DbuIaAad>k zY)tq90SE-n(FSCDt1Zf4c&DPoOd*$E;u5WQE9?fla@CZLOOU9a*D2PURfkp{yq40n z4siSA?!q=$3hC-WqnNw=Tn4oBLPyuJ7VQd&LF*FZD;Mal-t!L@W)qrmU06Ci zg4(G|o9Z4W&}U5;qD>tBTek{WHWzo(WH^n05b8l>Jo_>(u5qZV3-z7)#hL{W2z`GG z1Y-Aq?j4Y7@w5L=&~8~Wb$o1!bu{*(`#`9kYX)q9=z)3 zF!GSIVTRk+bBl+^f$Ox4*T8a+JT=;4%YT0X5+E)vdvu+3phKMeNC~5DL(A7AIFpW}|0@QXk^CaueLU z*aocF5y{|?$tt%yfdmqnYb(D(|fK=zsVz` z=fS|4a{q$Yz~2&M-QM_gvSf3d16P1kkN2Q&T#jCeS@bqGgAr|q99f{?D2lp)D4(kV ztiqxLT&-XHuA+(BTtCI$G%^e;HzwIvpSWhMBC5$ijaa@uwR~Dwr>GC=LfYNVvse0aXnG|jy!9|M~@08Elu>fCat~0^E9K^rC{wkLT zm<}{k0RjCRYk!Nw>baC(1V#l}{6Gja6;_iM(=XdaSU#!8yS=f{LJvd3i!ryROshfbiK0H!W;4dzd*- zwZ+Q1j#3&oJ*+0i_tZFO5$AAEOtIyXCC%y|-MuaMjybb_cThGr7H7UL?#}gFS1uFn zhs_(=s`ZmOo$a0<7iVJ*N7HE@Z>k!D+zXlC+|8o07!YMR70ae&skBbI>Z@n77PmPa zq&IwZUg|f;lN)S)E>#C4tDX4hFz|je{a%h&!>0>mbD|wH#klb6K=b|J?f0%T1h$}o zZkNyPT*}My+r`@Lk_P6MekG^F!Yya5fv&Dz=hqmAt%}>Ft9b)P{h#U7pt3tyE_02= zKkbMM$api+u`g!RNzoV8Rh?s~N8Plx&F@R+aEmw|RvXzFigD&HWh6IU6&=B;)!Jyg z9^UpRn|>p!>ym%lHE=P3dEv{b@lwFhTgzPS2dSp+v_l-lo+`aV0D;j-(mC;|8eXBS zt){$aI;xvdE5U*78Yb54X5iEtlc})LbAuRdmPo)p#^MS$hEsMux)_{?urYF-l`YN_ z-Rv@Me!&SSRyVKi82#iHFc&|D8aP3ajECe6#=V>|2DRU9cAxTq*D=Cw?Q7Q8qO>oV zy4;p{M}(I<=aQS@(z4lE zJHsQ|M|m9I-C}=sjyA6RFrErsA`c6(g_f@F3}Div-+bUI#ljFBNQkw%59~kAcp=v* zwpj5Fzy(uk(NE)41;VR|EEKMo;Fys7ZHk=QL&<#^|0}1Ifllv!QJ+I`IV083;b`gh zGqb}v3GBS_7A&y&nhJ{A?{~smT@UE0CJ2p#r%LoneW;TMiiH>S)3%R|_A8>UAYlmN z@|qcDFsvH6&CjdR6#vJR3Lq4Mwr3IV>fE);J_KzSXeJq682Pq+r z!o-!-tZKZQyO9$O)_VvfS81ey%iUd5owQ4w-CQ+=15%nuqOsLYAUuKg>)72k_G?We ztja~*Gyw=L!iuW$xNwl7oab=*lm;+jT9G=NjnrmQY7;yYY&7}m3yw8I=HWu2yAwmo z_(`K5UnfAOO$p6hEh<7l@!ou zm)3R^lB>;x>GwSbW7c+1B%uvyDn~nk*du|jHGzb^Uj6r*I!Ru z?mb68hhsWw-Yc!gP_PMwr{8Tn8bOTLq5a+&ssTuo0=(%o?}lbKlpRw;i$HXk?48|uhuG#O*$229}) zWsZ$Ps+liJO^pCZ_MObcnTih`lI88a3cGA{qseJB940cIE?UV%&@L9KHm|t?%$Jb7dpD_af3W7wBhV%-n8z~~&gs_VHEF`EkKfU3deAnnj zC|6)|zlf#PrlRHtO)?HIimXP<6#DLv@WWX}2g_O^t+MJ}sF`>pRu=7r94JL=prJw_ z)})aUSlNYG!lkfc*c+|;W@CEintK&|H~R1hxP#fUfvDA<4o3j51I3y3L_SJ#}$q}{@5-Y zVA8Ou^A=!E=c$35S#qq7+-SsxR9;^|n|q+XHea5CtZYZ=qSN!_ewDSdDrd&&jcPZ(CN3iXQ70)y`5|$IN2{t zq?=7h1;s-i!PqlnKKF{G-}r2o^;(yJH9d-&wA9b=AqQVAK3u5wdZnB2~+eVl;R#@EH}2qH?8qsl4q~t;2wL^B`(+>kK}3wEi-!} z(BUrpTTO(NzH?UF3w8a{eq08T`n}QDb9$tnY_2O4xV) zxSmyocP;HJn2q0UMMRxk#>DTATaV!u(9q(B=;pF6CjCmT5T@eKX3k9bo*0?c`;}4Se2x+&#<|b@|e(xOxg;Vswjj{=0nNaOy}+kaldfgZOyW zH6k+re?zlXepU;b_i?yPwzo+E#tAyjhpDZw9{erhynS)$K%&pAVuYI!#3xO82frf5 z^(3T}RC7BgC=@CHp>v(tt*~uze~#i%rY9zHc6R3L8j?2jC>N9BEJH3_y%nK5ncE9- zmer|$I(bWRUr)ryxBEh*P4o-4p~<5V)GCSO{uAG?S}_j!pY7c5 zk>-%!yu5D9%8(X;dT1c^m+Zazf006NK2K=Eufje{i;MZs+r`}2(*(d-$*jz$s)p3C4Nfs+lRX#F`a4+S8eZLgcZHvr7iXVmv7I@2U`V5$fmZR8C<5 zUisGPXdK3lBM3-f*dieo)+wa+8$+5DW63yA;4*Uyuf~WuGA7!L6Rdi;iHZNk<}|_5 zcu3=20_>*OFw4>?Fot$xs%gBWm^(5bo4u0~K#drE29wrbG6J3xWw!^>QsG@n|CTj0 zuTIy@$@c_fQsHEsJJhrG5|pH$(#wuU$w1+{Nf+yFvQ^<8^f2#&2DNb%RJ;*(gCJ3~ zCvnHHj@w0WY#|^ztF40{Kkl#vU~NHqr9GrTX59dX!VPwbB)<0uTnIM#4ynZ!&@j#{Hn{Ie*QztyUr>?so7br=5|Ll zHpX+;aM|NbE+k`LpC6QrCjIYmA>PTW4CF6`uI zFgCx|w2c1n-er;2?KI<;7BHhtf*6+F^eXOPP5i-=YQO!IZkBJag`uWwB(7~**UP%s zHwJt{NV^Ni5MX^upiCoVyw6G!Y*cff)CPvUD~UHA+POIuMfVLeLZ>*yXd$@*R(z+H z?p~4Kv`$Y{d~m`WfnunX)g`q+^W6v#WIHv^1MHQqQU|Px%CG&&gkeArAFD4iHT_W! zZ@pn5XpzbLOW2lw>xmM0fi;uV1X$=mBlHl=2vg&-?(C@^q};7FxJm>#pUg83YdKgL z3GtDFDz4tfT^WJh$XgSK2VUDz>|8+8VQvOr^Tw~=Hr#oMZAP0KQOuj=d1e4p7YcFY z#B6?kqWDVX^GF!9W)LwYSW#`9W2}@NI?+`|zYaoQDEA=ATyVs25O;x;RC=<|R|`(f z>P)Sta%ulqfDfF$r$lkSPV{!l+fs5tmKP<*v}Eh+ZA7!tb@vK@>u3b$6(CI(LLiU$ zz!gD}zJd~@uDAJ4>cpswgrv6@fOTW)DcKEF)8{V(#}$u>Ar+y3_YfdP9J<{lx5I!j zvSZx86($AOz~1$(_|XH54^#_LPGF>6*eok#z=e5eH`z|6mh?<4@3L6U-$wXMp>&=x zZ@l7>)r|+g>vL9!XyXz(sNYC<) z3I8ki^Um_4S*r(~@S=qr>GJJ43#TWvoE9V$@W#>Sgov%W{CMBy@Q?k*QTOlJlg|aN z`B^D7F&DalD~zKjmKlP{3te9YXMj7C&#GnW9DTWBwdWN`ihwlhz0}vDX))gdpV(Iv zKbS&azesBRsE1on;%6HB)W>!lk1Qf%+P+D#8`OkkrarADcaTcGMdyL(fD!;1@DL@O3;6@?@79CZqC3*mD+RQk|_V|U5!BZ~x;Y3BTwec6g;9&Y#KRZUss#wE&~AWG(doaTu+ z_ZeR(i9k%~Qg_%yZyAAzGTS1bg@+@b7+;8GBNZg~wYS+82_dcg$bxg78iHGOcIsps zCa?IfuO#x7fzgSD*!@O$quHI}Bkf95lrNdKY&ki${c zdlh&My@_h*%#=HOE0LJgYo-| z9(BlU)1a~$!`xLCD=3cNic?zJ?2>QRYpT$SbSpCo=+TP;{V?>0-|WX=+MgsW3xsE9 zcF)Sn>VNwA#>$8JPgjTk4dG;AYh-U?_7}oQ*2E^@1kj(9{kQtm|5)Nr!s+jS(*J|6 zC{aa!VrDrB`=%@Xey{TNdmJ`c(I>xB zFE3vOd_A-^wXlNCNNvF4>}%0Qf`D_vBJmWX+~4c<{Ts=P^Cay$2e@qL( z<|5-QS=*{V^$t8TbMd+wRr1$kVNf%>R7!Rxw0v7&2|k%mhXLQX0RiXM?HiB%2<|G! zaaUEFwf7;*Q5`)0BzwPDO_I{lMR-zOqIg07+*0x~DG6Gv{)$Bf8X*}ykk%jo2yhb^a=i7^#?4_{F4`e2>SB>5JCT7I!aW&IQ;E(i!%+R z)Mjdo{C*xvUU*Tuu|`tWR5%&=RQ!iE$uUB^MZ+E@J==(VZ-uz|(b09H zDjO|g&*C6;D0T=k#1c}eAO3MHJ)^&sL{~}qtk*t(tYBM3aRnR(YCjD`Y-fmWXQ8#@ z2&!P)=Vc%+s=~H~xJ?v8qGV7#MU0!8pu9~(1Pu3jwYKRoSB3PLnJoh%kUS<++pVEZ z-tgix(g`WpjUNzY!)Z0qdBoP~vP=|jN2R_yK8>3ep<<|-Ygyz2f+#rUK~A7Fb+wM% zH^AA=oPXYU%7AtNoZkw%oF`HwN-`y=3ToBf# z_jFn1hS+i3He+iZE5=>$1$-kS_(??MFEe~oWp0G$LE_1xRkrCk<@p&g@~baFJ1M^I z2`7^6IS^U-?opjVbketZq~GPlpUDg?vzY09)Ih)03Qv!3pm*7 zQFZa$Dk@pVs^F0{aH=ad4F;Sqo=3%V7(WFnkwA!QY>K~M# zHCXhVU(NPH=^UOE6QRvGWyonu?Tiu9;)2)pIrp`Bm^Ua$@Tw>8sbHQ4D<9Ybh1;9G zc5luTHG9x?80qIdVtI0_~6oCPv=)dPl{{QpPKY5arf4Cx^(L$Z8vmw-(_=CtU zp+VIF>t*JK5~rH2BGW`ckW(Hbyg$r3?{e62*tRd%6Kr{V6=UjSA{eb4;}8>FRS8=% zkwBJ*?-U&SoX_71(w8hAD^@;3xBCP0iR)+;6_FDXp