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}