Skip to main content
Version: 1.6.5

Handle Parsing Issues

Real SAS codebases are large, macro-heavy, and occasionally syntactically invalid. A robust tool must inspect ParsingResult.issues, decide what severity levels matter, and often continue with a partial AST rather than aborting.

Add Dependencies

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

dependencies {
implementation(files("deps/sas-parser-with-dependencies-1.6.5-all.jar"))
}

Report issues by severity

Every parse returns a ParsingResult with a isCorrect flag and a list of Issue objects. Print them grouped by severity so operators can tell errors from warnings.

import com.strumenta.kolasu.model.IssueSeverity
import com.strumenta.kolasu.commercial.LicenseManager
import com.strumenta.sas.parser.SASLanguage
import java.io.File

fun parseWithReporting(sasFile: File, license: File) {
LicenseManager.registerLicense(license)
val sas = SASLanguage()
sas.parseNativeSQL = true
val result = sas.parse(sasFile)

if (result.isCorrect) {
println("Parsed ${sasFile.name} with no issues.")
} else {
println("Parsed ${sasFile.name} with ${result.issues.size} issue(s).")
}

result.issues.forEach { issue ->
val location = issue.position?.let { " @ $it" } ?: ""
when (issue.severity) {
IssueSeverity.INFO -> println("INFO: ${issue.message}$location")
IssueSeverity.WARNING -> System.err.println("WARNING: ${issue.message}$location")
IssueSeverity.ERROR -> System.err.println("ERROR: ${issue.message}$location")
}
}

val root = result.root
if (root == null) {
println("No AST produced — cannot continue analysis.")
return
}
println("AST root: ${root.statementsAndDeclarations.size} top-level element(s)")
}

Continue with a partial AST

Warnings and even some errors do not always prevent building an AST. Batch analyzers typically:

  1. Log all issues.
  2. Skip the file only when root is null.
  3. Optionally ignore specific severities for downstream passes.
fun shouldAnalyze(result: com.strumenta.kolasu.parsing.ParsingResult<*>): Boolean {
if (result.root == null) return false
val blocking = result.issues.any { it.severity == IssueSeverity.ERROR }
if (blocking) {
println("File has errors but AST is available — proceeding with best-effort analysis.")
}
return true
}

Error nodes in the AST

When error reporting is enabled (the default), unparsed fragments may appear as ErrorNode instances inside the tree. Count them with a filtered walk — the same walkDescendants / walkDescendantsBreadthFirst utilities used elsewhere:

import com.strumenta.kolasu.model.ErrorNode
import com.strumenta.kolasu.traversing.walkDescendants

fun countErrorNodes(root: com.strumenta.kolasu.model.Node): Int =
root.walkDescendants(ErrorNode::class).count()

Treat ErrorNode counts as a quality signal: a high count often means lineage or inventory output will be incomplete for that region of the file.