Skip to content

Commit 96a85ae

Browse files
committed
Clean initial commit: only source, no large files
0 parents  commit 96a85ae

File tree

7 files changed

+1496
-0
lines changed

7 files changed

+1496
-0
lines changed

.gitignore

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Rust build artifacts
2+
/target/
3+
**/target/
4+
Cargo.lock
5+
6+
# Go build artifacts
7+
*.exe
8+
*.out
9+
*.test
10+
*.log
11+
*.mod
12+
*.sum
13+
14+
# Python cache
15+
__pycache__/
16+
*.pyc
17+
*.pyo
18+
*.pyd
19+
*.egg-info/
20+
21+
# VSCode and editor files
22+
.vscode/
23+
*.swp
24+
*.swo
25+
.DS_Store
26+
Thumbs.db
27+
28+
# Ignore all COBOL and JCL files in test-cobol/
29+
test-cobol/**/*.cobol
30+
test-cobol/**/*.cbl
31+
test-cobol/**/*.jcl
32+
test-cobol/**/*.CBL
33+
test-cobol/**/*.JCL
34+
35+
# Optionally keep a couple of demo files (uncomment if you want to keep these)
36+
#!test-cobol/HELLO.cobol
37+
#!test-cobol/HELLO.jcl
38+
39+
# Ignore all courseware and large datasets
40+
test-cobol/cobol-programming-course-master/
41+
42+
# Ignore binaries
43+
*.exe
44+
*.dll
45+
*.so
46+
*.dylib
47+
*.pdb
48+
*.obj
49+
*.o
50+
*.a
51+
*.lib
52+
*.exp
53+
*.bin
54+
*.class
55+
*.jar
56+
*.war
57+
*.ear
58+
59+
# Ignore data files
60+
test-cobol/data
61+
test-cobol/xdata

README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# CodeSleuth
2+
3+
**CodeSleuth** is a modern, multi-language code intelligence CLI tool focused on COBOL analysis. It combines a fast Rust parser, a Go CLI, and a Python Markdown summarizer to provide actionable, human-friendly reports for legacy codebases.
4+
5+
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6+
7+
---
8+
9+
## Features
10+
- **COBOL Parsing:** Extracts program structure, data division, procedure logic, call/control flow, and I/O.
11+
- **Markdown Summaries:** Generates clear, sectioned Markdown reports with Mermaid diagrams for call and control flow.
12+
- **Dead Code Detection:** Lists unused paragraphs and variables.
13+
- **Extensible Pipeline:** Modular Rust, Go, and Python components.
14+
- **Modern CLI:** Easy to use, with verbose/debug options.
15+
16+
---
17+
18+
## Quickstart
19+
20+
### 1. Clone the Repo
21+
```sh
22+
git clone https://github.com/Cod-e-Codes/codesleuth.git
23+
cd codesleuth
24+
```
25+
26+
### 2. Install Requirements
27+
- **Rust** (for the parser): https://rustup.rs/
28+
- **Go** (for the CLI): https://golang.org/dl/
29+
- **Python 3.8+** (for the summarizer): https://python.org/
30+
- (Optional) [Graphviz](https://graphviz.gitlab.io/) for advanced graph rendering
31+
32+
Install Python dependencies:
33+
```sh
34+
pip install -r requirements.txt # (if you add one)
35+
```
36+
37+
### 3. Build the Rust Parser
38+
```sh
39+
cd parser
40+
cargo build --release
41+
cd ..
42+
```
43+
44+
### 4. Build the Go CLI
45+
```sh
46+
cd cmd
47+
go build -o codesleuth.exe
48+
cd ..
49+
```
50+
51+
### 5. Run CodeSleuth
52+
```sh
53+
./cmd/codesleuth.exe analyze --verbose path/to/your/cobol/files
54+
```
55+
56+
---
57+
58+
## Usage
59+
- Analyze a COBOL directory:
60+
```sh
61+
./cmd/codesleuth.exe analyze --verbose test-cobol/
62+
```
63+
- The tool will print Markdown summaries to the console.
64+
- You can redirect output to a file:
65+
```sh
66+
./cmd/codesleuth.exe analyze test-cobol/ > summary.md
67+
```
68+
69+
---
70+
71+
## Contributing
72+
Pull requests, issues, and suggestions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
73+
74+
---
75+
76+
## License
77+
MIT License. See [LICENSE](LICENSE).
78+
79+
---
80+
81+
## Links
82+
- [GitHub Repo](https://github.com/Cod-e-Codes/codesleuth)
83+
- [Rust](https://www.rust-lang.org/)
84+
- [Go](https://golang.org/)
85+
- [Python](https://python.org/)

cmd/main.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
"strings"
10+
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var verbose bool
15+
16+
func init() {
17+
analyzeCmd.Flags().BoolVar(&verbose, "verbose", false, "Enable verbose debug output")
18+
}
19+
20+
func main() {
21+
rootCmd := &cobra.Command{
22+
Use: "codesleuth",
23+
Short: "CodeSleuth is a multi-language code intelligence CLI tool",
24+
}
25+
26+
rootCmd.AddCommand(analyzeCmd)
27+
28+
if err := rootCmd.Execute(); err != nil {
29+
fmt.Println(err)
30+
os.Exit(1)
31+
}
32+
}
33+
34+
var analyzeCmd = &cobra.Command{
35+
Use: "analyze [path]",
36+
Short: "Analyze legacy code in the specified path",
37+
Args: cobra.MinimumNArgs(1),
38+
Run: func(cmd *cobra.Command, args []string) {
39+
root := args[0]
40+
var files []string
41+
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
42+
if err != nil {
43+
return err
44+
}
45+
ext := strings.ToLower(filepath.Ext(path))
46+
if !info.IsDir() && (ext == ".cob" || ext == ".cbl" || ext == ".cobol") {
47+
files = append(files, path)
48+
}
49+
return nil
50+
})
51+
if err != nil {
52+
fmt.Printf("Error walking the path %q: %v\n", root, err)
53+
return
54+
}
55+
fmt.Printf("Found %d COBOL files:\n", len(files))
56+
for _, f := range files {
57+
fmt.Println(f)
58+
parserArgs := []string{"..\\parser\\target\\release\\parser", f}
59+
if verbose {
60+
parserArgs = append(parserArgs, "--verbose")
61+
}
62+
cmd := exec.Command(parserArgs[0], parserArgs[1:]...)
63+
output, err := cmd.Output()
64+
if err != nil {
65+
fmt.Printf("Error running parser on %s: %v\n", f, err)
66+
continue
67+
}
68+
var ir struct {
69+
ProgramName string `json:"program_name"`
70+
SourceFile string `json:"source_file"`
71+
}
72+
if err := json.Unmarshal(output, &ir); err != nil {
73+
fmt.Printf("Error parsing IR JSON for %s: %v\n", f, err)
74+
continue
75+
}
76+
fmt.Printf("Parsed: %s (program_name: %s)\n", ir.SourceFile, ir.ProgramName)
77+
78+
// Call Python summary script
79+
pyCmd := exec.Command("python", "..\\pytools\\summary.py")
80+
pyIn, err := pyCmd.StdinPipe()
81+
if err != nil {
82+
fmt.Printf("Error getting stdin pipe for Python summary for %s: %v\n", f, err)
83+
continue
84+
}
85+
go func() {
86+
pyIn.Write(output)
87+
pyIn.Close()
88+
}()
89+
summary, err := pyCmd.CombinedOutput()
90+
if err != nil {
91+
fmt.Printf("Python summary script failed for %s: %v\n", f, err)
92+
}
93+
fmt.Println(string(summary))
94+
}
95+
// TODO: Call Rust parser and Python pipeline here
96+
},
97+
}

parser/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "parser"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
authors = ["Cody Marsengill <[email protected]>"]
7+
description = "COBOL parser for CodeSleuth, outputs IR as JSON."
8+
9+
[dependencies]
10+
serde = { version = "1.0", features = ["derive"] }
11+
serde_json = "1.0"
12+
clap = { version = "4.0", features = ["derive"] }
13+
chrono = "0.4"
14+
regex = "1.10"
15+
once_cell = "1.17"

parser/ir_schema.json

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
{
2+
"program_name": "string",
3+
"source_file": "string",
4+
"identification_division": {
5+
"author": "string",
6+
"date_written": "string",
7+
"comments": ["string"]
8+
},
9+
"environment_division": {
10+
"input_output_section": {
11+
"files": [
12+
{
13+
"name": "string",
14+
"type": "input|output|i-o|extend",
15+
"description": "string"
16+
}
17+
]
18+
}
19+
},
20+
"data_division": {
21+
"working_storage": [
22+
{
23+
"name": "string",
24+
"type": "string",
25+
"level": "integer",
26+
"picture": "string",
27+
"value": "string|number|null",
28+
"children": []
29+
}
30+
],
31+
"file_section": [
32+
{
33+
"name": "string",
34+
"fields": [
35+
{
36+
"name": "string",
37+
"type": "string",
38+
"picture": "string",
39+
"children": []
40+
}
41+
]
42+
}
43+
]
44+
},
45+
"paragraphs": [
46+
{
47+
"name": "string",
48+
"section": "string",
49+
"kind": "paragraph",
50+
"line": 123,
51+
"source_location": "myfile.cbl:123",
52+
"statements": [
53+
{
54+
"type": "PERFORM|CALL|MOVE|IF|DISPLAY|...",
55+
"operands": ["string"],
56+
"raw": "string",
57+
"line": 123,
58+
"source_location": "myfile.cbl:123"
59+
}
60+
]
61+
}
62+
],
63+
"procedure_division": {
64+
"sections": [
65+
{
66+
"name": "string",
67+
"paragraphs": ["string"]
68+
}
69+
]
70+
},
71+
"call_graph": [
72+
{
73+
"from": "string",
74+
"to": "string",
75+
"type": "CALL|PERFORM|GOTO|PERFORM VARYING",
76+
"kind": "edge",
77+
"line": 123,
78+
"section": "string",
79+
"source_location": "myfile.cbl:123"
80+
}
81+
]
82+
}

0 commit comments

Comments
 (0)