cobol-parser 3.3.1__tar.gz → 3.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cobol_parser-3.4.0/PKG-INFO +765 -0
- cobol_parser-3.4.0/README.md +715 -0
- cobol_parser-3.4.0/cobol_parser.egg-info/PKG-INFO +765 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobol_parser.egg-info/SOURCES.txt +5 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/__init__.py +1 -1
- cobol_parser-3.4.0/cobolparser/analysis/_abend.py +25 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/_sql_whenever.py +9 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/constraints.py +523 -20
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/domains.py +19 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/field_widening.py +93 -11
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/invocation_counts.py +90 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/lint.py +281 -5
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/move_type_checker.py +6 -6
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/analyzer.py +9 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/graph.py +94 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/models.py +5 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/scanner.py +13 -2
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/recursion_risk.py +1 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/redundancy.py +19 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/xref.py +5 -0
- cobol_parser-3.4.0/cobolparser/cli/_changed_files.py +242 -0
- cobol_parser-3.4.0/cobolparser/cli/_help.py +168 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/cli/parse.py +559 -41
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/config/project.py +3 -3
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/__init__.py +7 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/copybook.py +16 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/dataset.py +48 -2
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/program_layout.py +58 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/program_fixtures.py +47 -2
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/scenarios.py +39 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/verification.py +10 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/lexer.py +78 -6
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/tools.py +5 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/control.py +4 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/data.py +14 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/display_parser.py +170 -1
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/evaluate_parser.py +40 -2
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/scan.py +9 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/pyproject.toml +1 -1
- cobol_parser-3.4.0/tests/test_readme_examples.py +156 -0
- cobol_parser-3.3.1/PKG-INFO +0 -301
- cobol_parser-3.3.1/README.md +0 -251
- cobol_parser-3.3.1/cobol_parser.egg-info/PKG-INFO +0 -301
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/LICENSE +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/MANIFEST.in +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobol_parser.egg-info/dependency_links.txt +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobol_parser.egg-info/entry_points.txt +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobol_parser.egg-info/requires.txt +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobol_parser.egg-info/top_level.txt +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/__main__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_accel.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_data_fast.c +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_data_fast.pyx +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_errors.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_facts_cache.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_lexer_fast.c +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_lexer_fast.pyx +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_lines.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_literals.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_preprocess_fast.c +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_preprocess_fast.pyx +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_source_directive.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/_storage.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/_cics.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/_files.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/_names.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/_procedures.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/_sql_flow.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/ast_diff.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/boundary_inventory.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/business_rules.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/call_interface.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/codebase.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/complexity.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/const_fold.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/crud_matrix.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/dclgen_check.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/dead_code.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/field_lineage.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/host_var_resolver.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/ims_segment_analyzer.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/io_coverage_reporter.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/io_diagnostics.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/io_logger.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/io_sequence.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/language_env_analyzer.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/lineage_graph.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/lineage_jcl.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/linkage_checker.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/condition_text.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/cycles.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/edges.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_flow/statement_text.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/program_signature.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/sarif.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/sql_cics_lint.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/technical_debt.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/unused_variables.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/analysis/value_tracker.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/batch.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/cli/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/cli/_project_config.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/cli/coverage.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/config/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/config/_yaml.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/core/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/core/ast_factory.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/core/exceptions.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/core/interfaces.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/core/registry.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/core/token_stream.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/definitions/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/definitions/_asm.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/definitions/bms.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/definitions/csd.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/definitions/ddl.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/definitions/ims.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/dialects/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/dialects/ibm_enterprise.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/dialects/le_signatures.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/copybook_data.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/bundle.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/compare.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/decoding.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/editing.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/encoding.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/errors.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/layout.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/layout_offsets.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/options.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/storage.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/values.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/data/views.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/generators/flowchart.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/jcl/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/jcl/bindings.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/jcl/models.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/jcl/parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/jcl/programs.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/claims.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/codebase_index.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/envelope.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/facts.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/hints.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/jcl_tools.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/languages.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/link_decks.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/navigation.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/prompts.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/server.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/slicing.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/sort_layout.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/mcp/workspace.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/ast_base.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/data_items.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/program.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/sql_statements.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/arithmetic.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/base.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/call.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/communication.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/io.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/legacy.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/misc.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/models/statements/report_writer.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/base.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/data.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/data_clauses.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/data_file_description.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/data_report_description.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/data_special_entries.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/environment.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/environment_sections.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/environment_select.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/factory.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/identification.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/procedure.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/procedure_boundaries.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/procedure_recovery.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/divisions/procedure_registry.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/_conditions.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/_utils.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/accept_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/allocate_free_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/arithmetic_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/call_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/close_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/communication_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/delete_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/entry_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/exception_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/go_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/ibm_exec_statements.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/if_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/initialize_inspect_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/invoke_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/legacy_verb_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/move_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/open_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/perform_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/read_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/report_writer_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/rewrite_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/search_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/set_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/simple_statement_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/sort_merge_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/start_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/stop_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/string_unstring_parsers.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/unlock_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/write_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/parsers/statements/xml_json_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/plugins/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/plugins/core.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/__init__.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/_normalize.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/copy_statement_parser.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/copybook_expander.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/models.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/path_resolver.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/replace_statement.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/preprocess/source_format.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/profiling.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/cobolparser/py.typed +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/setup.cfg +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/setup.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/tests/test_all_samples.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/tests/test_okf_claims.py +0 -0
- {cobol_parser-3.3.1 → cobol_parser-3.4.0}/tests/test_okf_staleness_map.py +0 -0
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cobol-parser
|
|
3
|
+
Version: 3.4.0
|
|
4
|
+
Summary: A comprehensive COBOL parser for Python with IBM Enterprise COBOL focus
|
|
5
|
+
Author-email: Samuel Dion <sam94dion@gmail.com>
|
|
6
|
+
License: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/Landparty/cobol-parser
|
|
8
|
+
Project-URL: Repository, https://github.com/Landparty/cobol-parser
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/Landparty/cobol-parser/issues
|
|
10
|
+
Keywords: cobol,parser,mainframe,ibm,enterprise,legacy
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Software Development :: Compilers
|
|
20
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Provides-Extra: fast
|
|
25
|
+
Requires-Dist: cython>=3.0; extra == "fast"
|
|
26
|
+
Provides-Extra: jcl
|
|
27
|
+
Requires-Dist: jcl-parser>=2.0.0; extra == "jcl"
|
|
28
|
+
Provides-Extra: pl1
|
|
29
|
+
Requires-Dist: landparty-pl1-parser>=2.0.0; extra == "pl1"
|
|
30
|
+
Provides-Extra: hlasm
|
|
31
|
+
Requires-Dist: hlasm-parser>=0.2.2; extra == "hlasm"
|
|
32
|
+
Provides-Extra: mcp
|
|
33
|
+
Requires-Dist: mcp<2,>=1.10; extra == "mcp"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: jcl-parser>=2.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: mcp<2,>=1.10; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-xdist>=3.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
41
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: mypy>=1.5.0; extra == "dev"
|
|
43
|
+
Requires-Dist: cython>=3.0; extra == "dev"
|
|
44
|
+
Provides-Extra: docs
|
|
45
|
+
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
46
|
+
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == "docs"
|
|
47
|
+
Provides-Extra: profiling
|
|
48
|
+
Requires-Dist: psutil>=5.9; extra == "profiling"
|
|
49
|
+
Dynamic: license-file
|
|
50
|
+
|
|
51
|
+
# cobol-parser
|
|
52
|
+
|
|
53
|
+
A COBOL parser for Python with an IBM Enterprise COBOL focus. It turns COBOL
|
|
54
|
+
source into a traversable AST (JSON export, error recovery, copybook
|
|
55
|
+
expansion with a source map back to the original lines), and builds static
|
|
56
|
+
analyzers, test-data generators, a z/OS JCL front end and an MCP server for AI
|
|
57
|
+
agents on top of it.
|
|
58
|
+
|
|
59
|
+
458 of the 459 NIST COBOL-85 programs in `examples/cobol/` parse cleanly (the
|
|
60
|
+
one that does not, SM101A, needs its copybooks expanded first).
|
|
61
|
+
|
|
62
|
+
[](https://www.python.org/downloads/)
|
|
63
|
+
[](https://pypi.org/project/cobol-parser/)
|
|
64
|
+
[](.okf/tests.md)
|
|
65
|
+
[](LICENSE)
|
|
66
|
+
|
|
67
|
+
## Contents
|
|
68
|
+
|
|
69
|
+
- [Install](#install)
|
|
70
|
+
- [Quick start](#quick-start)
|
|
71
|
+
- [Every command, with an example](#every-command-with-an-example)
|
|
72
|
+
- [Parse and preprocess](#parse-and-preprocess)
|
|
73
|
+
- [Lint and CI](#lint-and-ci)
|
|
74
|
+
- [Analyze one program](#analyze-one-program)
|
|
75
|
+
- [Analyze a codebase](#analyze-a-codebase)
|
|
76
|
+
- [Test data](#test-data)
|
|
77
|
+
- [Reference and integrations](#reference-and-integrations)
|
|
78
|
+
- [Exit codes](#exit-codes)
|
|
79
|
+
- [The Python API, with examples](#the-python-api-with-examples)
|
|
80
|
+
- [Language coverage](#language-coverage)
|
|
81
|
+
- [Documentation](#documentation)
|
|
82
|
+
- [Development](#development)
|
|
83
|
+
|
|
84
|
+
## Install
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install cobol-parser # the library and the cobol-parser CLI
|
|
88
|
+
pip install 'cobol-parser[mcp]' # plus the MCP server
|
|
89
|
+
pip install 'cobol-parser[jcl]' # plus JCL (through jcl-parser)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Requires Python 3.11, 3.12 or 3.13. The core library has no runtime
|
|
93
|
+
dependencies. Optional extras:
|
|
94
|
+
|
|
95
|
+
| Extra | Adds |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `mcp` | `cobol-parser mcp`, the MCP server ([docs/mcp-server.md](docs/mcp-server.md)) |
|
|
98
|
+
| `jcl` | `cobol-parser jcl`, and the JCL joins in `field-impact`, `widen-check` and the MCP server |
|
|
99
|
+
| `pl1`, `hlasm` | PL/I and assembler programs in the MCP server's call graph |
|
|
100
|
+
| `fast` | Cython, to build the optional accelerators from source |
|
|
101
|
+
| `dev`, `docs` | the test, lint and docs toolchain for working on this repo |
|
|
102
|
+
|
|
103
|
+
To get the CLI on your `PATH` without a project virtualenv:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv tool install cobol-parser
|
|
107
|
+
uv tool install --editable . # from a clone, picking up code changes
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The install is pure Python by default. The PyPI wheels also carry three
|
|
111
|
+
compiled Cython accelerators (about 3x lexer throughput), used only when
|
|
112
|
+
`COBOLPARSER_ACCEL=1` is set at run time. From a clone, the same variable at
|
|
113
|
+
build time compiles them:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pip install -e ".[fast]"
|
|
117
|
+
COBOLPARSER_ACCEL=1 python setup.py build_ext --inplace
|
|
118
|
+
export COBOLPARSER_ACCEL=1
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Quick start
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
cobol-parser parse src/ORDPOST.cbl --copybook-path copybooks -o ordpost.json
|
|
125
|
+
cobol-parser lint src/*.cbl --format text --fail-on error
|
|
126
|
+
cobol-parser --help # every command, grouped by task
|
|
127
|
+
cobol-parser lint --help # every flag of one command, with examples
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from cobolparser import parse_cobol
|
|
132
|
+
|
|
133
|
+
result = parse_cobol("src/ORDPOST.cbl") # a path, or the source text itself
|
|
134
|
+
if result.success:
|
|
135
|
+
print(result.ast.program_name) # ORDPOST
|
|
136
|
+
for error in result.errors:
|
|
137
|
+
print(error)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Every command, with an example
|
|
141
|
+
|
|
142
|
+
`cobol-parser` has <!-- okf:gen cli-subcommand-count -->41<!-- /okf:gen -->
|
|
143
|
+
subcommands, one per analyzer or generator. Every one writes JSON to stdout
|
|
144
|
+
by default (`-o FILE` writes a file, `--compact` drops the indentation), and
|
|
145
|
+
`cobol-parser <command> --help` lists all its flags with more examples. The full flag reference is the generated table in
|
|
146
|
+
[.okf/cli.md](.okf/cli.md#subcommand-reference).
|
|
147
|
+
|
|
148
|
+
The examples below are run from the root of a project laid out like this.
|
|
149
|
+
The `cobol.yml` saves passing `--copybook-path copybooks` and
|
|
150
|
+
`--proc-path proclib` to every command (a flag on the command line always
|
|
151
|
+
wins over it):
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
cobol.yml copybook_path: [copybooks], proc_path: [proclib]
|
|
155
|
+
src/ ORDEDIT.cbl ORDVAL.cbl ORDPOST.cbl POSTDOM.cbl POSTINTL.cbl ...
|
|
156
|
+
copybooks/ ORDREC.cpy HISTREC.cpy ADDRREC.cpy ...
|
|
157
|
+
jcl/ ORDNIGHT.jcl ORDMONTH.jcl
|
|
158
|
+
proclib/ ORDEDITP ORDRPTP (cataloged PROCs)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```yaml
|
|
162
|
+
# cobol.yml
|
|
163
|
+
version: 1
|
|
164
|
+
project:
|
|
165
|
+
copybook_path: [copybooks]
|
|
166
|
+
proc_path: [proclib]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
The order programs come from [tests/eval/shop/](tests/eval/shop/), and the
|
|
170
|
+
SQL, CICS, IMS and LE examples use the programs in
|
|
171
|
+
[tests/samples/enterprise/](tests/samples/enterprise/).
|
|
172
|
+
[tests/test_readme_examples.py](tests/test_readme_examples.py) builds this
|
|
173
|
+
project from them and runs every example in this section and the next.
|
|
174
|
+
|
|
175
|
+
Flags most commands share: `--copybook-path DIR` (repeatable),
|
|
176
|
+
`--define SYMBOL[=VALUE]` for `>>DEFINE`, `--source-format auto|fixed|free`,
|
|
177
|
+
`--encoding ENC`, `--program NAME` (pick one unit of a nested program),
|
|
178
|
+
`--error-recovery fail-fast|collect-all` (the CLI defaults to `collect-all`)
|
|
179
|
+
and, on any command, `--config FILE` / `--no-config`.
|
|
180
|
+
|
|
181
|
+
### Parse and preprocess
|
|
182
|
+
|
|
183
|
+
| Command | What it gives you |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `parse` | The whole program as AST JSON (`--find-type` to keep one node type, `--errors`, `--stats`) |
|
|
186
|
+
| `batch` | Many programs parsed in parallel, one JSON entry per file |
|
|
187
|
+
| `expand` | The source with every `COPY` expanded, and optionally a map back to the original lines |
|
|
188
|
+
| `preprocess` | Fixed-format source turned into free-form text (columns 8-72, continuations merged) |
|
|
189
|
+
| `tokenize` | The lexer's token stream |
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
cobol-parser parse src/ORDPOST.cbl -o ordpost.json
|
|
193
|
+
cobol-parser parse src/ORDPOST.cbl --find-type CallStatement
|
|
194
|
+
cobol-parser batch --glob 'src/*.cbl' --workers 4 -o asts.json
|
|
195
|
+
cobol-parser expand src/ORDPOST.cbl --source-map
|
|
196
|
+
cobol-parser preprocess src/ORDPOST.cbl --define DEBUG
|
|
197
|
+
cobol-parser tokenize src/ORDPOST.cbl
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
`cobol-parser src/ORDPOST.cbl`, with no command, is `parse`.
|
|
201
|
+
|
|
202
|
+
### Lint and CI
|
|
203
|
+
|
|
204
|
+
| Command | What it gives you |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `lint` | Every checker in one pass, one severity-graded finding list (`json`, `text`, `sarif`, `github`) |
|
|
207
|
+
| `scan` | Analyzers over a whole source tree, with per-file fault isolation, cross-file duplicate paragraphs and an on-disk cache |
|
|
208
|
+
| `config` | The `cobol.yml` in effect, and where it came from |
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
cobol-parser lint src/ORDPOST.cbl --format text
|
|
212
|
+
cobol-parser lint src/*.cbl --format text --min-severity warning --fail-on error
|
|
213
|
+
cobol-parser lint --glob 'src/**/*.cbl' --rule dead-code --rule move-type-check
|
|
214
|
+
cobol-parser lint --changed-since origin/main --format github --fail-on error
|
|
215
|
+
cobol-parser lint src/*.cbl --format sarif -o lint.sarif
|
|
216
|
+
cobol-parser scan --glob 'src/*.cbl' --analyzer health --clones --cache-dir .cache
|
|
217
|
+
cobol-parser scan src/*.cbl --format sarif -o scan.sarif
|
|
218
|
+
cobol-parser config
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
```text
|
|
222
|
+
$ cobol-parser lint src/ORDPOST.cbl --format text
|
|
223
|
+
src/ORDPOST.cbl:54:8: warning [dead-code] paragraph 9000-OLD-RECALC can never be reached
|
|
224
|
+
src/ORDPOST.cbl:56:8: warning [dead-code] paragraph 9100-OLD-AUDIT can never be reached
|
|
225
|
+
2 finding(s): 0 error, 2 warning, 0 info (10 rule(s) ran)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`lint` runs nine analyzers over one parse: dead code, unused variables, MOVE
|
|
229
|
+
type checks, I/O sequencing, LINKAGE checks, recursion risk, complexity,
|
|
230
|
+
DCLGEN and SQL/CICS checks, plus `line-length` (fixed-format text past
|
|
231
|
+
column 80, or a word cut at column 72, in the program and its copybooks).
|
|
232
|
+
`--rule` narrows the run, `--min-severity` the output, and `--fail-on error`
|
|
233
|
+
exits 3 when a finding at that severity was reported, so it can gate a build.
|
|
234
|
+
It takes many files at once (`FILE...`, `--glob`, `--files-from`),
|
|
235
|
+
`--changed-since REF` lints only the programs a git change touched (and those
|
|
236
|
+
that `COPY` a changed copybook), and `--format github` annotates the pull
|
|
237
|
+
request. `lint`, `scan` and `call-check` write SARIF 2.1.0 with
|
|
238
|
+
`--format sarif`, which GitHub code scanning and IDE problem panes read
|
|
239
|
+
directly. CI recipe and pre-commit hooks: [docs/ci-lint.md](docs/ci-lint.md).
|
|
240
|
+
|
|
241
|
+
`scan` runs `health` and `redundancy` by default; `--analyzer` picks others
|
|
242
|
+
(`dead-code`, `complexity`, `lint`, ...). With `--cache-dir`, a file whose
|
|
243
|
+
source, copybooks and copybook directories are unchanged reuses its report
|
|
244
|
+
from the last run.
|
|
245
|
+
|
|
246
|
+
### Analyze one program
|
|
247
|
+
|
|
248
|
+
Each command reads one program (or, for `data-items`, a bare copybook) and
|
|
249
|
+
writes one report.
|
|
250
|
+
|
|
251
|
+
| Command | What it gives you |
|
|
252
|
+
|---|---|
|
|
253
|
+
| `dead-code` | Paragraphs and sections no path reaches |
|
|
254
|
+
| `unused-variables` | Data items the PROCEDURE DIVISION never references |
|
|
255
|
+
| `program-flow` | The control-flow graph (PERFORM, GO TO, CALL, fall-through) as JSON, Mermaid or DOT |
|
|
256
|
+
| `recursion-check` | PERFORM and GO TO cycles, recursive CALLs |
|
|
257
|
+
| `complexity` | Cyclomatic complexity per paragraph and section |
|
|
258
|
+
| `health` | A composite technical-debt score with its worst offenders |
|
|
259
|
+
| `redundancy` | Dead code, unused data and duplicated paragraphs together |
|
|
260
|
+
| `io-sequence` | OPEN / READ / WRITE / CLOSE ordering mistakes |
|
|
261
|
+
| `move-type-check` | MOVEs between incompatible categories |
|
|
262
|
+
| `linkage-check` | LINKAGE items against the `USING` of the PROCEDURE DIVISION and ENTRY |
|
|
263
|
+
| `sql-cics-check` | Embedded SQL and CICS pitfalls (unchecked SQLCODE, missing RESP, ...) |
|
|
264
|
+
| `dclgen-check` | SQL host variables against their DCLGEN columns |
|
|
265
|
+
| `analyze` | The targets a dynamic `CALL identifier` can reach |
|
|
266
|
+
| `language-env` | Intrinsic functions and LE callable services the program uses |
|
|
267
|
+
| `ims-dli` | IMS DL/I calls and the segments they reference |
|
|
268
|
+
| `data-items` | Every data item's byte offset, length, USAGE, REDEFINES and level-88 values |
|
|
269
|
+
| `program-signature` | The program's calling interface, with a ready-made `CALL` |
|
|
270
|
+
| `xref` | A cross-reference of every symbol: where it is defined, read and written |
|
|
271
|
+
| `business-rules` | The decisions, validations and calculations, as rules |
|
|
272
|
+
| `lineage` | Where one field's value flows inside the program |
|
|
273
|
+
| `diff` | What changed in behavior between two versions (reformatting is no change) |
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
cobol-parser dead-code src/ORDPOST.cbl
|
|
277
|
+
cobol-parser unused-variables src/ORDPOST.cbl --exclude-copybook-variables
|
|
278
|
+
cobol-parser program-flow src/ORDPOST.cbl --format mermaid -o flow.mmd
|
|
279
|
+
cobol-parser recursion-check src/ORDPOST.cbl
|
|
280
|
+
cobol-parser complexity src/ORDPOST.cbl
|
|
281
|
+
cobol-parser health src/ORDPOST.cbl
|
|
282
|
+
cobol-parser redundancy src/ORDPOST.cbl --min-clone-statements 5
|
|
283
|
+
cobol-parser io-sequence src/ORDPOST.cbl
|
|
284
|
+
cobol-parser move-type-check src/ORDPOST.cbl
|
|
285
|
+
cobol-parser linkage-check src/POSTDOM.cbl
|
|
286
|
+
cobol-parser sql-cics-check src/DB2BATCH.cbl
|
|
287
|
+
cobol-parser dclgen-check src/DB2BATCH.cbl
|
|
288
|
+
cobol-parser analyze src/ORDPOST.cbl
|
|
289
|
+
cobol-parser language-env src/LESERV.cbl
|
|
290
|
+
cobol-parser ims-dli src/IMSMPP.cbl
|
|
291
|
+
cobol-parser data-items copybooks/ORDREC.cpy
|
|
292
|
+
cobol-parser program-signature src/POSTDOM.cbl
|
|
293
|
+
cobol-parser xref src/ORDPOST.cbl
|
|
294
|
+
cobol-parser business-rules src/ORDVAL.cbl --format text
|
|
295
|
+
cobol-parser lineage src/ORDPOST.cbl --field ORD-AMT --format text
|
|
296
|
+
cobol-parser diff old/ORDPOST.cbl src/ORDPOST.cbl --format text
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
```text
|
|
300
|
+
$ cobol-parser diff old/ORDPOST.cbl src/ORDPOST.cbl --format text
|
|
301
|
+
PROGRAM ORDPOST -> ORDPOST
|
|
302
|
+
3 changes
|
|
303
|
+
|
|
304
|
+
data:
|
|
305
|
+
~ [value-changed] WS-OLD-RATE: WS-OLD-RATE VALUE changed from 0.0150 to 0.0125
|
|
306
|
+
|
|
307
|
+
procedure:
|
|
308
|
+
~ [condition-changed] 2000-POST: IF condition changed: IF ORD-HELD OR ORD-REJECTED -> IF ORD-HELD
|
|
309
|
+
~ [paragraph-body-changed] 2000-POST: paragraph 2000-POST body changed
|
|
310
|
+
...
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Analyze a codebase
|
|
314
|
+
|
|
315
|
+
| Command | What it gives you |
|
|
316
|
+
|---|---|
|
|
317
|
+
| `codebase-graph` | The CALL / LINK / XCTL and COPY graph of a source tree (JSON, DOT, Mermaid) |
|
|
318
|
+
| `copybook-impact` | Every program a copybook change reaches, through nested `COPY` chains |
|
|
319
|
+
| `call-check` | Every `CALL` against the callee's `USING`: argument count, BY VALUE / BY REFERENCE, byte length, USAGE, `RETURNING` |
|
|
320
|
+
| `field-impact` | Where a field's value flows across programs, files, DB2 columns and JCL datasets |
|
|
321
|
+
| `widen-check` | What breaks if a field's PICTURE changes |
|
|
322
|
+
| `jcl` | Which program each JCL step runs, and each DD's dataset (needs the `[jcl]` extra) |
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
cobol-parser codebase-graph src/ --format mermaid -o graph.mmd
|
|
326
|
+
cobol-parser copybook-impact ORDREC src/
|
|
327
|
+
cobol-parser call-check src/ --format text --fail-on error
|
|
328
|
+
cobol-parser field-impact ORD-AMT src/ --jcl jcl/ --format text
|
|
329
|
+
cobol-parser field-impact --dataset PROD.ORD.HISTORY src/ --jcl jcl/ --format text
|
|
330
|
+
cobol-parser widen-check ORD-CUST-ID src/ --to '9(10)' --jcl jcl/ --format text
|
|
331
|
+
cobol-parser jcl jcl/ORDNIGHT.jcl --bindings
|
|
332
|
+
cobol-parser jcl jcl/ORDNIGHT.jcl --dd-map
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
```text
|
|
336
|
+
$ cobol-parser widen-check ORD-CUST-ID src/ --to '9(10)' --jcl jcl/ --format text
|
|
337
|
+
ORD-CUST-ID -> PIC 9(10)
|
|
338
|
+
ORDEDIT:ORD-REC.ORD-CUST-ID PIC 9(8) (8 bytes) -> PIC 9(10) (10 bytes)
|
|
339
|
+
...
|
|
340
|
+
ERROR truncation ORDPOST:HIST-REC.HIST-CUST-ID (line 48)
|
|
341
|
+
the value reaches a field holding 8 digits; the new PICTURE carries 10 digits: loses high-order digits
|
|
342
|
+
...
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
A dynamic `CALL` is followed to every target its variable can hold. When the
|
|
346
|
+
byte length changes, `widen-check` also lists the records whose later fields
|
|
347
|
+
shift, the `REDEFINES` that overlay the field, the files whose LRECL changes
|
|
348
|
+
(and the other programs reading the same dataset), and the CALL / LINKAGE
|
|
349
|
+
records on both sides.
|
|
350
|
+
|
|
351
|
+
### Test data
|
|
352
|
+
|
|
353
|
+
| Command | What it gives you |
|
|
354
|
+
|---|---|
|
|
355
|
+
| `gen-data` | Synthetic records that fit each field's PICTURE, USAGE and level-88 values, as CSV, JSON, record bytes or hex |
|
|
356
|
+
| `decode` | A record file (ASCII or EBCDIC, fixed or variable) read back through a copybook |
|
|
357
|
+
| `compare` | Two record files compared field by field, matched on a key |
|
|
358
|
+
| `gen-fixtures` | A test bundle for a whole program: one scenario per branch, the data each file, CALL, SQL or CICS boundary supplies, and what to assert |
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
cobol-parser gen-data copybooks/ORDREC.cpy --rows 100 --seed 7 -o orders.csv
|
|
362
|
+
cobol-parser gen-data copybooks/ORDREC.cpy --rows 100 --seed 7 --format record --charset ebcdic -o expected.dat
|
|
363
|
+
cobol-parser gen-data copybooks/ORDREC.cpy --rows 99 --seed 7 --format record --charset ebcdic -o actual.dat
|
|
364
|
+
cobol-parser decode expected.dat --copybook copybooks/ORDREC.cpy --charset ebcdic --max-records 5
|
|
365
|
+
cobol-parser compare expected.dat actual.dat --copybook copybooks/ORDREC.cpy --charset ebcdic --key ORD-ID
|
|
366
|
+
cobol-parser gen-fixtures src/ORDPOST.cbl --list-boundaries
|
|
367
|
+
cobol-parser gen-fixtures src/ORDPOST.cbl --scenarios all --seed 7 -o bundle.json
|
|
368
|
+
cobol-parser gen-fixtures src/ORDPOST.cbl --scenarios branches --format csv-dir -o fixtures/
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
```text
|
|
372
|
+
$ cobol-parser compare expected.dat actual.dat --copybook copybooks/ORDREC.cpy --charset ebcdic --key ORD-ID
|
|
373
|
+
compare ORD-REC (view ORD-REC), key ORD-ID, comparing values
|
|
374
|
+
expected: 100 records, actual: 99 records
|
|
375
|
+
matched 99, changed 0, missing 1, extra 0
|
|
376
|
+
...
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
A `--seed` makes `gen-data` and `gen-fixtures` output byte-identical across
|
|
380
|
+
runs. `compare` exits like `cmp`: 0 when the files match, 1 when they differ,
|
|
381
|
+
2 when the run failed. The bundle format is in
|
|
382
|
+
[docs/fixture-bundle-schema.md](docs/fixture-bundle-schema.md).
|
|
383
|
+
|
|
384
|
+
### Reference and integrations
|
|
385
|
+
|
|
386
|
+
| Command | What it gives you |
|
|
387
|
+
|---|---|
|
|
388
|
+
| `le-info` | The signature of an LE callable service or intrinsic function, from the built-in catalogue |
|
|
389
|
+
| `mcp` | A read-only MCP server that gives AI agents these analyzers (needs the `[mcp]` extra) |
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
cobol-parser le-info CEEDAYS
|
|
393
|
+
cobol-parser le-info NUMVAL-C
|
|
394
|
+
cobol-parser le-info --kind service
|
|
395
|
+
claude mcp add cobol -- cobol-parser mcp --root /path/to/checkout
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The MCP server's tools answer "what is this program", "what is this field and
|
|
399
|
+
where is it used", "who calls this", "what does a change to this copybook
|
|
400
|
+
reach" and "show me this paragraph", with a `file:line` for every fact and a
|
|
401
|
+
list of what they could not check. See [docs/mcp-server.md](docs/mcp-server.md).
|
|
402
|
+
The repo also ships a `cobol-analysis` agent skill
|
|
403
|
+
([.claude/skills/cobol-analysis/SKILL.md](.claude/skills/cobol-analysis/SKILL.md))
|
|
404
|
+
that teaches an agent which subcommand answers which question.
|
|
405
|
+
|
|
406
|
+
### Exit codes
|
|
407
|
+
|
|
408
|
+
| Code | Meaning |
|
|
409
|
+
|---|---|
|
|
410
|
+
| 0 | Success. Analyzer findings alone never fail a run |
|
|
411
|
+
| 1 | A file could not be read, parsed or written |
|
|
412
|
+
| 2 | The command line was rejected, or some input only partly parsed (the output is still written) |
|
|
413
|
+
| 3 | A gate tripped: `--fail-on` (`lint`, `call-check`, `widen-check`) or `jcl --strict` |
|
|
414
|
+
|
|
415
|
+
`compare` is the exception: 1 means "the files differ".
|
|
416
|
+
|
|
417
|
+
## The Python API, with examples
|
|
418
|
+
|
|
419
|
+
Everything the CLI does is a library call. Each block below runs on its own
|
|
420
|
+
from the project root shown above.
|
|
421
|
+
|
|
422
|
+
### Parse
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
from cobolparser import CobolParser, ErrorRecoveryMode, parse_cobol
|
|
426
|
+
|
|
427
|
+
result = parse_cobol("src/ORDVAL.cbl") # FAIL_FAST: stops at the first error
|
|
428
|
+
print(result.success, result.errors, result.warnings)
|
|
429
|
+
print(result.ast.program_name) # ORDVAL
|
|
430
|
+
print(len(result.ast.find_all_by_type("CallStatement")))
|
|
431
|
+
json_text = result.ast.to_json()
|
|
432
|
+
|
|
433
|
+
parser = CobolParser(error_recovery=ErrorRecoveryMode.COLLECT_ALL)
|
|
434
|
+
result = parser.parse(" IDENTIFICATION DIVISION.\n PROGRAM-ID. HELLO.\n")
|
|
435
|
+
print(result.ast.program_name) # HELLO
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`parse_cobol` takes a path or the source text. `ParseResult` also carries
|
|
439
|
+
`statistics` and, after copybook expansion, `expansion_source_map`.
|
|
440
|
+
|
|
441
|
+
### Copybooks, preprocessing and tokens
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from pathlib import Path
|
|
445
|
+
|
|
446
|
+
from cobolparser import (
|
|
447
|
+
expand_copybooks,
|
|
448
|
+
normalize_fixed_format,
|
|
449
|
+
parse_cobol_with_expansion,
|
|
450
|
+
tokenize_cobol,
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
source = Path("src/ORDPOST.cbl").read_text()
|
|
454
|
+
|
|
455
|
+
result = parse_cobol_with_expansion(source, "src/ORDPOST.cbl", copybook_paths=["copybooks"])
|
|
456
|
+
print(result.success)
|
|
457
|
+
|
|
458
|
+
expansion = expand_copybooks(source, ["copybooks"])
|
|
459
|
+
print(expansion.included_copybooks) # the copybook files it read
|
|
460
|
+
|
|
461
|
+
free_form = normalize_fixed_format(source) # columns 8-72, comments dropped
|
|
462
|
+
tokens = tokenize_cobol(source)
|
|
463
|
+
print(tokens[0].type.name, tokens[0].value) # IDENTIFICATION_DIVISION IDENTIFICATION
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Many files
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
from glob import glob
|
|
470
|
+
|
|
471
|
+
from cobolparser import ScanOptions, cross_file_clone_groups, parse_files, scan_files
|
|
472
|
+
|
|
473
|
+
for item in parse_files(glob("src/*.cbl"), workers=4):
|
|
474
|
+
print(item.path, item.result.success if item.result else item.read_error)
|
|
475
|
+
|
|
476
|
+
report = scan_files(
|
|
477
|
+
glob("src/*.cbl"),
|
|
478
|
+
ScanOptions(analyzers=("health", "dead-code"), copybook_paths=("copybooks",)),
|
|
479
|
+
)
|
|
480
|
+
print(len(report.ok_files), len(report.failed_files))
|
|
481
|
+
print(cross_file_clone_groups(report))
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
`cobolparser.batch.parse_files_with_copybooks(paths, copybook_paths=[...])`
|
|
485
|
+
parses many files with their copybooks expanded.
|
|
486
|
+
|
|
487
|
+
### Analyze one program
|
|
488
|
+
|
|
489
|
+
Every analyzer takes a parsed `CobolProgram` and returns a report with
|
|
490
|
+
`to_dict()`. Most are `<Analyzer>().analyze(ast)`; the checkers are
|
|
491
|
+
`.check(ast)`.
|
|
492
|
+
|
|
493
|
+
```python
|
|
494
|
+
from cobolparser import (
|
|
495
|
+
BusinessRuleExtractor,
|
|
496
|
+
ComplexityAnalyzer,
|
|
497
|
+
CRUDMatrixGenerator,
|
|
498
|
+
DclgenChecker,
|
|
499
|
+
DeadCodeAnalyzer,
|
|
500
|
+
DynamicCallAnalyzer,
|
|
501
|
+
IOLogger,
|
|
502
|
+
LanguageEnvironmentAnalyzer,
|
|
503
|
+
LintAnalyzer,
|
|
504
|
+
ProgramFlowAnalyzer,
|
|
505
|
+
RecursionRiskAnalyzer,
|
|
506
|
+
RedundancyAnalyzer,
|
|
507
|
+
TechnicalDebtAnalyzer,
|
|
508
|
+
UnusedVariableAnalyzer,
|
|
509
|
+
parse_cobol_with_expansion,
|
|
510
|
+
)
|
|
511
|
+
from cobolparser.analysis import (
|
|
512
|
+
HostVariableResolver,
|
|
513
|
+
IMSSegmentAnalyzer,
|
|
514
|
+
IOSequenceAnalyzer,
|
|
515
|
+
LinkageChecker,
|
|
516
|
+
MoveTypeChecker,
|
|
517
|
+
)
|
|
518
|
+
from cobolparser.analysis.field_lineage import FieldFlowAnalyzer
|
|
519
|
+
from cobolparser.analysis.program_signature import extract_signatures
|
|
520
|
+
from cobolparser.analysis.sql_cics_lint import SqlCicsAnalyzer
|
|
521
|
+
from cobolparser.analysis.xref import XrefAnalyzer
|
|
522
|
+
from cobolparser.generators.data.layout_offsets import compute_program_data_items
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def load(path):
|
|
526
|
+
with open(path) as f:
|
|
527
|
+
return parse_cobol_with_expansion(f.read(), path, copybook_paths=["copybooks"]).ast
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
ast = load("src/ORDPOST.cbl")
|
|
531
|
+
|
|
532
|
+
lint = LintAnalyzer().analyze(ast) # every checker below, in one pass
|
|
533
|
+
for finding in lint.findings:
|
|
534
|
+
print(finding.rule, finding.severity, finding.location, finding.message)
|
|
535
|
+
|
|
536
|
+
DeadCodeAnalyzer().analyze(ast) # dead-code
|
|
537
|
+
UnusedVariableAnalyzer().analyze(ast) # unused-variables
|
|
538
|
+
flow = ProgramFlowAnalyzer().analyze(ast) # program-flow
|
|
539
|
+
RecursionRiskAnalyzer().analyze(ast) # recursion-check
|
|
540
|
+
ComplexityAnalyzer().analyze(ast) # complexity
|
|
541
|
+
TechnicalDebtAnalyzer().analyze(ast) # health
|
|
542
|
+
RedundancyAnalyzer().analyze(ast) # redundancy
|
|
543
|
+
IOSequenceAnalyzer().analyze(ast) # io-sequence
|
|
544
|
+
MoveTypeChecker().check(ast) # move-type-check
|
|
545
|
+
XrefAnalyzer().analyze(ast) # xref
|
|
546
|
+
FieldFlowAnalyzer().analyze(ast) # lineage
|
|
547
|
+
compute_program_data_items(ast) # data-items
|
|
548
|
+
IOLogger().analyze(ast) # every file operation, in order
|
|
549
|
+
CRUDMatrixGenerator().analyze(ast) # which file or table each program creates/reads/updates/deletes
|
|
550
|
+
DynamicCallAnalyzer().analyze(ast) # analyze: annotates each CALL with its possible targets
|
|
551
|
+
|
|
552
|
+
LinkageChecker().check(load("src/POSTDOM.cbl")) # linkage-check
|
|
553
|
+
print(extract_signatures(load("src/POSTDOM.cbl"))[0].to_dict()) # program-signature
|
|
554
|
+
BusinessRuleExtractor().analyze(load("src/ORDVAL.cbl")) # business-rules
|
|
555
|
+
|
|
556
|
+
db2 = load("src/DB2BATCH.cbl")
|
|
557
|
+
SqlCicsAnalyzer().analyze(db2) # sql-cics-check
|
|
558
|
+
DclgenChecker().check(db2) # dclgen-check
|
|
559
|
+
HostVariableResolver().resolve(db2) # each SQL host variable -> its data item
|
|
560
|
+
LanguageEnvironmentAnalyzer().analyze(load("src/LESERV.cbl")) # language-env
|
|
561
|
+
IMSSegmentAnalyzer().analyze(load("src/IMSMPP.cbl")) # ims-dli
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
Flowcharts and diffs:
|
|
565
|
+
|
|
566
|
+
```python
|
|
567
|
+
from cobolparser import ProgramFlowAnalyzer, parse_cobol
|
|
568
|
+
from cobolparser.analysis.ast_diff import ProgramDiffer
|
|
569
|
+
from cobolparser.generators import DotFlowchartGenerator, MermaidFlowchartGenerator
|
|
570
|
+
|
|
571
|
+
ast = parse_cobol("src/ORDPOST.cbl").ast
|
|
572
|
+
flow = ProgramFlowAnalyzer().analyze(ast)
|
|
573
|
+
print(MermaidFlowchartGenerator().generate(flow))
|
|
574
|
+
dot = DotFlowchartGenerator().generate(flow)
|
|
575
|
+
|
|
576
|
+
diff = ProgramDiffer().diff(parse_cobol("old/ORDPOST.cbl").ast, ast)
|
|
577
|
+
print(diff.to_text())
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Analyze a codebase
|
|
581
|
+
|
|
582
|
+
```python
|
|
583
|
+
from glob import glob
|
|
584
|
+
|
|
585
|
+
from cobolparser.analysis.call_interface import CallInterfaceChecker
|
|
586
|
+
from cobolparser.analysis.codebase import CodebaseGraphBuilder, CopybookImpactAnalyzer
|
|
587
|
+
from cobolparser.analysis.field_lineage import FieldFlowAnalyzer
|
|
588
|
+
from cobolparser.analysis.field_widening import FieldWideningAnalyzer
|
|
589
|
+
from cobolparser.analysis.lineage_graph import LineageGraph
|
|
590
|
+
from cobolparser.analysis.lineage_jcl import bindings_from_jobs, load_jobs
|
|
591
|
+
from cobolparser import parse_cobol_with_expansion
|
|
592
|
+
|
|
593
|
+
programs = sorted(glob("src/*.cbl"))
|
|
594
|
+
|
|
595
|
+
graph = CodebaseGraphBuilder(copybook_paths=["copybooks"]).build(programs)
|
|
596
|
+
print(graph.callers_of("ORDVAL")) # codebase-graph
|
|
597
|
+
print(graph.to_mermaid())
|
|
598
|
+
|
|
599
|
+
impact = CopybookImpactAnalyzer(graph).analyze("ORDREC") # copybook-impact
|
|
600
|
+
print(impact.direct_programs)
|
|
601
|
+
|
|
602
|
+
calls = CallInterfaceChecker(copybook_paths=["copybooks"]).check_files(programs)
|
|
603
|
+
print(calls.to_text()) # call-check
|
|
604
|
+
|
|
605
|
+
# field-impact and widen-check: one lineage graph over every program and the JCL
|
|
606
|
+
flows = []
|
|
607
|
+
for path in programs:
|
|
608
|
+
with open(path) as f:
|
|
609
|
+
ast = parse_cobol_with_expansion(f.read(), path, copybook_paths=["copybooks"]).ast
|
|
610
|
+
flows.append(FieldFlowAnalyzer().analyze(ast))
|
|
611
|
+
jobs, errors = load_jobs(glob("jcl/*.jcl"), proc_path="proclib")
|
|
612
|
+
bindings, passthroughs = bindings_from_jobs(jobs)
|
|
613
|
+
lineage = LineageGraph(flows, bindings, passthroughs)
|
|
614
|
+
|
|
615
|
+
print(lineage.impact("ORD-AMT", direction="forward")) # field-impact
|
|
616
|
+
widen = FieldWideningAnalyzer(lineage).analyze("ORD-CUST-ID", "9(10)")
|
|
617
|
+
for finding in widen.findings: # widen-check
|
|
618
|
+
print(finding.severity, finding.kind, finding.program, finding.message)
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
### Test data
|
|
622
|
+
|
|
623
|
+
```python
|
|
624
|
+
from cobolparser.generators import (
|
|
625
|
+
Charset,
|
|
626
|
+
CopybookDataGenerator,
|
|
627
|
+
DataGeneratorOptions,
|
|
628
|
+
EncodingOptions,
|
|
629
|
+
ProgramFixtureGenerator,
|
|
630
|
+
RecordDecoder,
|
|
631
|
+
compare_files,
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
options = DataGeneratorOptions(rows=100, seed=7)
|
|
635
|
+
generator = CopybookDataGenerator(options)
|
|
636
|
+
dataset = generator.generate_from_file("copybooks/ORDREC.cpy", copybook_paths=["copybooks"])
|
|
637
|
+
dataset.write_csv("orders.csv") # gen-data
|
|
638
|
+
|
|
639
|
+
# A record image needs every byte (FILLER too): use the record-image options.
|
|
640
|
+
ebcdic = EncodingOptions(charset=Charset.EBCDIC)
|
|
641
|
+
image = CopybookDataGenerator(options.for_record_image()).generate_from_file(
|
|
642
|
+
"copybooks/ORDREC.cpy", copybook_paths=["copybooks"]
|
|
643
|
+
)
|
|
644
|
+
image.write_records("expected.dat", ebcdic) # gen-data --format record
|
|
645
|
+
|
|
646
|
+
decoder = RecordDecoder.from_copybook_file(
|
|
647
|
+
"copybooks/ORDREC.cpy", opts=ebcdic, copybook_paths=["copybooks"]
|
|
648
|
+
)
|
|
649
|
+
decoded = decoder.decode_file("expected.dat", max_records=5) # decode
|
|
650
|
+
print(decoded.to_csv())
|
|
651
|
+
|
|
652
|
+
result = compare_files(decoder, "expected.dat", "expected.dat", key=["ORD-ID"])
|
|
653
|
+
print(result.equal) # compare: True
|
|
654
|
+
|
|
655
|
+
bundle = ProgramFixtureGenerator().generate_with_scenarios_from_file(
|
|
656
|
+
"src/ORDPOST.cbl", copybook_paths=["copybooks"], mode="all", seed=7
|
|
657
|
+
) # gen-fixtures
|
|
658
|
+
print([scenario.name for scenario in bundle.scenarios])
|
|
659
|
+
bundle.write_csv_dir("fixtures/")
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### JCL, CICS, DB2 and IMS definitions
|
|
663
|
+
|
|
664
|
+
```python
|
|
665
|
+
from pathlib import Path
|
|
666
|
+
|
|
667
|
+
from cobolparser.definitions import parse_definitions
|
|
668
|
+
from cobolparser.jcl import parse_jcl, resolve_dd_bindings
|
|
669
|
+
|
|
670
|
+
jcl = parse_jcl(Path("jcl/ORDNIGHT.jcl").read_text(), filename="ORDNIGHT.jcl", proc_paths=["proclib"])
|
|
671
|
+
for binding in resolve_dd_bindings(jcl): # jcl --bindings
|
|
672
|
+
print(binding.step, binding.ddname, binding.dataset)
|
|
673
|
+
print(jcl.steps_running("ORDPOST"))
|
|
674
|
+
|
|
675
|
+
ddl = parse_definitions(Path("defs/BANKDDL.ddl").read_text()) # DB2 DDL
|
|
676
|
+
print([table.name for table in ddl.tables])
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
`parse_definitions` detects the kind itself and also reads CICS CSD
|
|
680
|
+
(`DEFINE PROGRAM/TRANSACTION/FILE ...`), BMS maps, and IMS DBD and PSB
|
|
681
|
+
sources (`parse_csd`, `parse_bms`, `parse_ddl`, `parse_dbd`, `parse_psb` for
|
|
682
|
+
one kind). The CLI has no subcommand for these; the MCP server and the
|
|
683
|
+
LegacyLens backend use them. Sample sources are in
|
|
684
|
+
[tests/samples/definitions/](tests/samples/definitions/).
|
|
685
|
+
|
|
686
|
+
### LE catalogue, SARIF and project config
|
|
687
|
+
|
|
688
|
+
```python
|
|
689
|
+
from pathlib import Path
|
|
690
|
+
|
|
691
|
+
from cobolparser import LintAnalyzer, parse_cobol
|
|
692
|
+
from cobolparser.analysis.sarif import lint_results, sarif_log
|
|
693
|
+
from cobolparser.config.project import load_project_config
|
|
694
|
+
from cobolparser.dialects.le_signatures import intrinsic_signature, le_service_signature
|
|
695
|
+
|
|
696
|
+
print(le_service_signature("CEEDAYS").to_dict()) # le-info CEEDAYS
|
|
697
|
+
print(intrinsic_signature("NUMVAL-C").to_dict())
|
|
698
|
+
|
|
699
|
+
report = LintAnalyzer().analyze(parse_cobol("src/ORDPOST.cbl").ast)
|
|
700
|
+
log = sarif_log(lint_results(report.to_dict(), "src/ORDPOST.cbl")) # lint --format sarif
|
|
701
|
+
|
|
702
|
+
config = load_project_config(Path.cwd()) # config: the cobol.yml in effect
|
|
703
|
+
print(config.source, config.copybook_path)
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
The per-module reference, with every report field, is in the OKF topic
|
|
707
|
+
files ([.okf/analysis.md](.okf/analysis.md),
|
|
708
|
+
[.okf/generators.md](.okf/generators.md), [.okf/batch.md](.okf/batch.md),
|
|
709
|
+
[.okf/jcl.md](.okf/jcl.md), [.okf/definitions.md](.okf/definitions.md)).
|
|
710
|
+
|
|
711
|
+
## Language coverage
|
|
712
|
+
|
|
713
|
+
IBM Enterprise COBOL through 6.4: fixed and free format, `COPY ... REPLACING`
|
|
714
|
+
and `REPLACE`, conditional compilation (`>>DEFINE`, `>>IF`, `>>EVALUATE`),
|
|
715
|
+
nested and contained programs, object-oriented `CLASS-ID` / `METHOD-ID`,
|
|
716
|
+
user-defined functions (`FUNCTION-ID`), DECLARATIVES, Report Writer, XML and
|
|
717
|
+
JSON statements, and `EXEC SQL`, `EXEC CICS` and `EXEC DLI` blocks. One
|
|
718
|
+
program per IBM program type (batch, VSAM, CICS, IMS, DB2, MQ, ...) runs
|
|
719
|
+
through the whole stack in the test suite; the matrix is in
|
|
720
|
+
[docs/enterprise-program-types.md](docs/enterprise-program-types.md).
|
|
721
|
+
|
|
722
|
+
## Documentation
|
|
723
|
+
|
|
724
|
+
| For | Read |
|
|
725
|
+
|---|---|
|
|
726
|
+
| Using the MCP server | [docs/mcp-server.md](docs/mcp-server.md) |
|
|
727
|
+
| The `cobol.yml` project config | [docs/project-config.md](docs/project-config.md) |
|
|
728
|
+
| Linting COBOL in CI | [docs/ci-lint.md](docs/ci-lint.md) |
|
|
729
|
+
| The `gen-fixtures` bundle format | [docs/fixture-bundle-schema.md](docs/fixture-bundle-schema.md) |
|
|
730
|
+
| Every subcommand and flag | [.okf/cli.md](.okf/cli.md) |
|
|
731
|
+
| How the library works, area by area | [.okf/index.md](.okf/index.md) |
|
|
732
|
+
| What the backend and mocky-mock rely on | [interface-contract.md](interface-contract.md) |
|
|
733
|
+
| What changed in each release | [CHANGELOG.md](CHANGELOG.md) |
|
|
734
|
+
| Everything under `docs/`, including design plans | [docs/README.md](docs/README.md) |
|
|
735
|
+
|
|
736
|
+
The `.okf/` folder is the reference documentation: one topic file per area
|
|
737
|
+
(lexer, parser, analyzers, generators, CLI, MCP, tests), written so that a
|
|
738
|
+
person or an AI agent loads only the file for the task at hand.
|
|
739
|
+
`scripts/okf_check.py` checks what those files claim against the code.
|
|
740
|
+
|
|
741
|
+
## Development
|
|
742
|
+
|
|
743
|
+
```bash
|
|
744
|
+
pip install -e ".[dev,docs]"
|
|
745
|
+
git config core.hooksPath .githooks # the OKF pre-commit check
|
|
746
|
+
|
|
747
|
+
python -m pytest tests/ -q -n 4 --no-cov # fast full run
|
|
748
|
+
python -m pytest tests/ # with the 90% coverage floor
|
|
749
|
+
COBOLPARSER_PERF=1 python -m pytest tests/performance/test_large_program.py # 40k-line perf lane
|
|
750
|
+
|
|
751
|
+
python -m ruff check .
|
|
752
|
+
python -m black .
|
|
753
|
+
python -m mypy cobolparser/
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
CI runs only on manual dispatch (`.github/workflows/ci.yml` has no push or PR
|
|
757
|
+
trigger), so run lint, types and the full suite locally before pushing. Measure coverage on
|
|
758
|
+
the pure-Python build: with `COBOLPARSER_ACCEL=1`, coverage.py cannot see the
|
|
759
|
+
code the compiled modules replace. Test layout and markers:
|
|
760
|
+
[.okf/tests.md](.okf/tests.md).
|
|
761
|
+
|
|
762
|
+
## License
|
|
763
|
+
|
|
764
|
+
GNU Affero General Public License v3.0 or later. Copyright © 2026 Samuel Dion.
|
|
765
|
+
See [LICENSE](LICENSE).
|