Skip to main content

graphforge_core/
bind_error.rs

1//! Binder diagnostics shared with the facade.
2use crate::{Span, UnsupportedCypherFeature};
3
4/// The kind of a binder error.
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum BindErrorKind {
7    /// A recognized construct has no executable implementation.
8    UnsupportedFeature(UnsupportedCypherFeature),
9    /// A label name was not found in the ontology (strict mode).
10    UnknownLabel,
11    /// A relation type name was not found in the ontology (strict mode).
12    UnknownRelationType,
13    /// A property name was not found in the ontology (strict mode).
14    UnknownProperty,
15    /// A variable was referenced before it was introduced by a MATCH pattern.
16    UndeclaredVariable,
17    /// The same variable was introduced more than once in a conflicting way.
18    DuplicateVariable,
19    /// A property name is ambiguous across multiple owner labels.
20    AmbiguousProperty,
21    /// A clause is recognized by the parser but not yet implemented by the
22    /// binder/executor (SET/REMOVE/CALL). Surfaced as an error instead
23    /// of a silent no-op (#724).
24    UnsupportedClause,
25    /// A `DELETE` target was not a plain bound variable (e.g. `DELETE n.prop`
26    /// or `DELETE n + 1`). Only `DELETE <var>` is supported (#740).
27    InvalidDeleteTarget,
28    /// A variable is used with two incompatible kinds — e.g. a relationship
29    /// variable reused as a node pattern (`MATCH ()-[r]-() MATCH (r)`).
30    /// openCypher rejects this as a compile-time `VariableTypeConflict` (#956).
31    VariableKindConflict,
32    /// An already-bound variable is re-declared by a CREATE/MERGE pattern
33    /// (`MATCH (a) CREATE (a)`, a reused relationship variable, a bound node
34    /// given new labels/properties). openCypher `VariableAlreadyBound` (#956).
35    VariableAlreadyBound,
36    /// A clause or function argument is semantically invalid — a non-integer
37    /// `range()`/`SKIP`/`LIMIT` argument, an aggregate in `WHERE`, a CREATE
38    /// relationship with no/var-length/undirected type, a UNION column
39    /// mismatch, etc. Covers openCypher's `ArgumentError` / `InvalidAggregation`
40    /// / `NoSingleRelationshipType` / … — the harness checks the phase, not the
41    /// sub-code, so one kind with a descriptive message suffices (#956).
42    InvalidArgument,
43    /// A composed ontology symbol has multiple valid candidates.
44    AmbiguousComposedSymbol,
45    /// A composed ontology qualifier or bridge path is invalid/conflicting.
46    CompositionConflict,
47}
48
49/// A semantic error or warning produced by the binder.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct BindError {
52    /// The kind of error.
53    pub kind: BindErrorKind,
54    /// Source location of the offending token.
55    pub span: Span,
56    /// Human-readable message.
57    pub message: String,
58}
59
60impl BindError {
61    /// Construct a typed binder diagnostic.
62    #[must_use]
63    pub fn new(kind: BindErrorKind, span: Span, message: impl Into<String>) -> Self {
64        Self {
65            kind,
66            span,
67            message: message.into(),
68        }
69    }
70}