Skip to main content

Analyze an RPG Codebase

The analyzer module sits on top of symbol resolution and produces editor-oriented artifacts:

  • a dependency graph (files, procedures/subroutines, and edges such as COPY, CALL, EXSR, prototype→implementation)
  • a sequence-diagram catalog (PlantUML per procedure / subroutine)
  • a go-to-definition catalog of navigable ReferenceByName features

Add Dependencies

repositories {
mavenLocal()
mavenCentral()
flatDir {
dirs("deps")
}
}

dependencies {
implementation(files("deps/rpgparser-2.2.0-all.jar"))
implementation(files("deps/rpgparser-symbol-resolution-2.2.0.jar"))
implementation(files("deps/rpgparser-analyzer-2.2.0.jar"))
implementation("com.strumenta.kolasu:kolasu-codebase:1.5.107")
implementation("com.strumenta.kolasu:kolasu-semantics:1.5.107")
}

Maven coordinates: com.strumenta:rpg-parser-analyzer (depends on rpg-parser-symbol-resolution).

Run the full analysis suite

The shortest path is Codebase.analyzeForEditor(), which resolves symbols and runs every analyzer pass. You can also construct RPGAnalyzer yourself when you already have an RPGSemanticsAnalysisResult.

import com.strumenta.rpgparser.analyzer.RPGAnalyzer
import com.strumenta.rpgparser.analyzer.analyzeForEditor
import com.strumenta.rpgparser.analyzer.model.DependencyKind
import com.strumenta.rpgparser.symbolresolution.rpgCodebase
import com.strumenta.rpgparser.symbolresolution.resolveSymbolsForRPG
import java.io.File

fun analyzeProject(projectDir: File, license: File) {
val codebase = rpgCodebase(projectDir, license)

// Option A — one liner
val result = codebase.analyzeForEditor()

// Option B — resolve first, then analyze
// val analysis = codebase.resolveSymbolsForRPG()
// val result = RPGAnalyzer(analysis).analyze()

println("Behaviors: ${result.dependencyGraph.behaviors.size}")
println("Edges: ${result.dependencyGraph.edges.size}")
result.dependencyGraph.edges
.filter { it.kind == DependencyKind.InvokeSubroutine }
.forEach { edge ->
println("EXSR: ${edge.from.name}${edge.to.name}")
}

result.sequenceDiagramCatalog.diagrams.take(3).forEach { diagram ->
println("--- ${diagram.subjectKind} ${diagram.subjectName} (${diagram.moduleName}) ---")
println(diagram.plantUml.take(200) + "…")
}

println("Go-to-definition features: ${result.goToDefinitionCatalog.entries.size}")
}

Dependency kinds

Edges in DependencyGraph use DependencyKind:

KindMeaning
CopyInclude/COPY or /INCLUDE between files
CallProgramCALL to an external program
CallProcedureBound / prototype procedure call
InvokeSubroutineEXSR
PrototypeImplPrototype linked to its Procedure implementation

Sequence diagrams

Each entry in sequenceDiagramCatalog carries PlantUML text for a procedure or subroutine (including the virtual main routine). Render it with any PlantUML tooling, or use it as a documentation artifact during migration scoping.

Export a LionWeb snapshot

RPGAnalyzer.exportSnapshot() packages go-to-definition, sequence diagrams, and the dependency graph as a ZIP of LionWeb .binpb chunks. This is useful for integration with other tools using LionWeb (an open standard in language engineering).

val analysis = codebase.resolveSymbolsForRPG()
val zipBytes: ByteArray = RPGAnalyzer(analysis).exportSnapshot()
File("rpg-analysis.zip").writeBytes(zipBytes)