Skip to content

Commit

Permalink
Diagnostic context extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
ty1824 committed Oct 18, 2023
1 parent c8a5d98 commit b4bfc65
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@ package dev.dialector.diagnostic
import dev.dialector.syntax.Node
import dev.dialector.syntax.NodePredicate

public interface DiagnosticSeverity {
public object Error : DiagnosticSeverity
public object Warning : DiagnosticSeverity
public object Info : DiagnosticSeverity
public object Hint : DiagnosticSeverity
}

public interface DiagnosticContext {
/**
* Registers a diagnostic for the given node.
*/
public fun diagnostic(message: String, node: Node)
public fun diagnostic(message: String, node: Node, severity: DiagnosticSeverity = DiagnosticSeverity.Error)
}

/**
* A rule that produces diagnostics for nodes matching a [NodePredicate]
*/
public interface DiagnosticRule<T : Node, C : DiagnosticContext> {
public interface DiagnosticRule<T : Node, C> {
public val isValidFor: NodePredicate<T, C>
public val diagnostics: C.(node: T) -> Unit
public val diagnostics: context(DiagnosticContext) C.(node: T) -> Unit

public operator fun invoke(node: Node, context: C) {
public operator fun invoke(node: Node, context: C, diagnosticContext: DiagnosticContext) {
@Suppress("UNCHECKED_CAST")
if (isValidFor(node, context)) context.diagnostics(node as T)
if (isValidFor(node, context)) diagnostics(diagnosticContext, context, node as T)
}
}

Expand All @@ -29,10 +36,10 @@ public interface DiagnosticRule<T : Node, C : DiagnosticContext> {
* @param T The node type being checked.
* @param C The [DiagnosticContext] type
*/
public infix fun <T : Node, C : DiagnosticContext> NodePredicate<T, C>.check(
check: C.(node: T) -> Unit,
public infix fun <T : Node, C> NodePredicate<T, C>.check(
check: context(DiagnosticContext) C.(node: T) -> Unit,
): DiagnosticRule<T, C> =
object : DiagnosticRule<T, C> {
override val isValidFor: NodePredicate<T, C> = this@check
override val diagnostics: C.(node: T) -> Unit = check
override val diagnostics: context(DiagnosticContext) C.(node: T) -> Unit = check
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,42 @@ class DiagnosticRuleTest {

class TestContext : DiagnosticContext {
var lastDiagnostic: Pair<String, Node>? = null
override fun diagnostic(message: String, node: Node) {
override fun diagnostic(message: String, node: Node, severity: DiagnosticSeverity) {
lastDiagnostic = message to node
}
}

@Test
fun testDiagnosticRule() {
with(TestContext()) {
rule1(B(5), this)
rule1(B(5), this, this)
assertNull(lastDiagnostic)
}

with(TestContext()) {
rule1(B(-1), this)
rule1(B(-1), this, this)
val result = assertNotNull(lastDiagnostic)
assertEquals(bFail, result.first)
}

with(TestContext()) {
rule1(A(), this)
rule1(A(), this, this)
assertNull(lastDiagnostic)
}

with(TestContext()) {
rule2(B(5), this)
rule2(B(5), this, this)
assertNull(lastDiagnostic)
}

with(TestContext()) {
rule2(B(15), this)
rule2(B(15), this, this)
val result = assertNotNull(lastDiagnostic)
assertEquals(bSubFail, result.first)
}

with(TestContext()) {
rule2(A(), this)
rule2(A(), this, this)
val result = assertNotNull(lastDiagnostic)
assertEquals(aFail, result.first)
}
Expand Down

0 comments on commit b4bfc65

Please sign in to comment.