Skip to content

Commit 7a2c651

Browse files
authored
Merge pull request #885 from vsbogd/fix-complex-queries
Fix complex queries issue #884
2 parents 8a24582 + b3a3388 commit 7a2c651

File tree

3 files changed

+69
-36
lines changed

3 files changed

+69
-36
lines changed

lib/src/space/grounding/mod.rs

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
33
pub mod index;
44

5-
use crate::*;
65
use super::*;
76
use crate::atom::*;
8-
use crate::atom::subexpr::split_expr;
97

108
use std::fmt::Debug;
119
use std::collections::HashSet;
@@ -15,9 +13,6 @@ pub use index::{ALLOW_DUPLICATION, NO_DUPLICATION};
1513

1614
// Grounding space
1715

18-
/// Symbol to concatenate queries to space.
19-
pub const COMMA_SYMBOL : Atom = sym!(",");
20-
2116
/// In-memory space which can contain grounded atoms.
2217
// TODO: Clone is required by C API
2318
#[derive(Clone)]
@@ -75,7 +70,7 @@ impl<D: DuplicationStrategy> GroundingSpace<D> {
7570
/// assert_eq!(space.query(&sym!("C")), BindingsSet::empty());
7671
/// ```
7772
pub fn add(&mut self, atom: Atom) {
78-
//log::debug!("GroundingSpace::add(): self: {:?}, atom: {:?}", self as *const GroundingSpace, atom);
73+
log::debug!("GroundingSpace::add: {}, atom: {}", self, atom);
7974
self.index.insert(atom.clone());
8075
self.common.notify_all_observers(&SpaceEvent::Add(atom));
8176
}
@@ -97,7 +92,7 @@ impl<D: DuplicationStrategy> GroundingSpace<D> {
9792
/// assert_eq!(space.query(&sym!("A")), BindingsSet::empty());
9893
/// ```
9994
pub fn remove(&mut self, atom: &Atom) -> bool {
100-
//log::debug!("GroundingSpace::remove(): self: {:?}, atom: {:?}", self as *const GroundingSpace, atom);
95+
log::debug!("GroundingSpace::remove: {}, atom: {}", self, atom);
10196
let is_removed = self.index.remove(atom);
10297
if is_removed {
10398
self.common.notify_all_observers(&SpaceEvent::Remove(atom.clone()));
@@ -152,42 +147,20 @@ impl<D: DuplicationStrategy> GroundingSpace<D> {
152147
/// assert_eq!(result, bind_set![{x: sym!("B")}]);
153148
/// ```
154149
pub fn query(&self, query: &Atom) -> BindingsSet {
155-
match split_expr(query) {
156-
// Cannot match with COMMA_SYMBOL here, because Rust allows
157-
// it only when Atom has PartialEq and Eq derived.
158-
Some((sym @ Atom::Symbol(_), args)) if *sym == COMMA_SYMBOL => {
159-
args.fold(BindingsSet::single(),
160-
|mut acc, query| {
161-
let result = if acc.is_empty() {
162-
acc
163-
} else {
164-
acc.drain(0..).flat_map(|prev| -> BindingsSet {
165-
let query = matcher::apply_bindings_to_atom_move(query.clone(), &prev);
166-
let mut res = self.query(&query);
167-
res.drain(0..)
168-
.flat_map(|next| next.merge(&prev))
169-
.collect()
170-
}).collect()
171-
};
172-
log::debug!("query: current result: {:?}", result);
173-
result
174-
})
175-
},
176-
_ => self.single_query(query),
177-
}
150+
complex_query(query, |query| self.single_query(query))
178151
}
179152

180153
/// Executes simple `query` without sub-queries on the space.
181154
fn single_query(&self, query: &Atom) -> BindingsSet {
182-
log::debug!("single_query: query: {}", query);
155+
log::debug!("GroundingSpace::single_query: {} query: {}", self, query);
183156
let mut result = BindingsSet::empty();
184157
let query_vars: HashSet<&VariableAtom> = query.iter().filter_type::<&VariableAtom>().collect();
185158
for bindings in self.index.query(query) {
186159
let bindings = bindings.narrow_vars(&query_vars);
187160
log::trace!("single_query: push result: {}", bindings);
188161
result.push(bindings);
189162
}
190-
log::debug!("single_query: result: {:?}", result);
163+
log::debug!("GroundinSpace::single_query: {} result: {}", self, result);
191164
result
192165
}
193166

@@ -249,7 +222,7 @@ impl PartialEq for GroundingSpace {
249222
}
250223
}
251224

252-
impl Debug for GroundingSpace {
225+
impl<D: DuplicationStrategy> Debug for GroundingSpace<D> {
253226
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254227
match &self.name {
255228
Some(name) => write!(f, "GroundingSpace-{name} ({self:p})"),
@@ -258,7 +231,7 @@ impl Debug for GroundingSpace {
258231
}
259232
}
260233

261-
impl Display for GroundingSpace {
234+
impl<D: DuplicationStrategy> Display for GroundingSpace<D> {
262235
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263236
match &self.name {
264237
Some(name) => write!(f, "GroundingSpace-{name}"),

lib/src/space/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ use std::rc::{Rc, Weak};
99
use std::cell::{RefCell, Ref, RefMut};
1010
use std::borrow::Cow;
1111

12+
use crate::*;
1213
use crate::common::FlexRef;
1314
use crate::atom::*;
1415
use crate::atom::matcher::{BindingsSet, apply_bindings_to_atom_move};
16+
use crate::atom::subexpr::split_expr;
17+
18+
/// Symbol to concatenate queries to space.
19+
pub const COMMA_SYMBOL : Atom = sym!(",");
1520

1621
/// Contains information about space modification event.
1722
#[derive(Clone, Debug, PartialEq)]
@@ -397,3 +402,32 @@ impl<T: Space> Space for &T {
397402
}
398403
}
399404

405+
fn complex_query<F>(query: &Atom, single_query: F) -> BindingsSet
406+
where
407+
F: Fn(&Atom) -> BindingsSet,
408+
{
409+
log::debug!("complex_query: query: {}", query);
410+
match split_expr(query) {
411+
// Cannot match with COMMA_SYMBOL here, because Rust allows
412+
// it only when Atom has PartialEq and Eq derived.
413+
Some((sym @ Atom::Symbol(_), args)) if *sym == COMMA_SYMBOL => {
414+
args.fold(BindingsSet::single(),
415+
|mut acc, query| {
416+
let result = if acc.is_empty() {
417+
acc
418+
} else {
419+
acc.drain(0..).flat_map(|prev| -> BindingsSet {
420+
let query = matcher::apply_bindings_to_atom_move(query.clone(), &prev);
421+
let mut res = single_query(&query);
422+
res.drain(0..)
423+
.flat_map(|next| next.merge(&prev))
424+
.collect()
425+
}).collect()
426+
};
427+
log::debug!("ModuleSpace::query: current result: {}", result);
428+
result
429+
})
430+
},
431+
_ => single_query(query),
432+
}
433+
}

lib/src/space/module.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ impl ModuleSpace {
2525
}
2626

2727
pub fn query(&self, query: &Atom) -> BindingsSet {
28-
log::debug!("ModuleSpace::query: {}", query);
28+
complex_query(query, |query| self.single_query(query))
29+
}
30+
31+
fn single_query(&self, query: &Atom) -> BindingsSet {
32+
log::debug!("ModuleSpace::query: {} {}", self, query);
2933
let mut results = self.main.query(query);
3034
for dep in &self.deps {
3135
if let Some(space) = dep.borrow().as_any() {
@@ -42,7 +46,7 @@ impl ModuleSpace {
4246
}
4347

4448
fn query_no_deps(&self, query: &Atom) -> BindingsSet {
45-
log::debug!("ModuleSpace::query_no_deps: {}", query);
49+
log::debug!("ModuleSpace::query_no_deps: {} {}", self, query);
4650
self.main.query(query)
4751
}
4852

@@ -91,3 +95,25 @@ impl SpaceMut for ModuleSpace {
9195
}
9296
}
9397

98+
#[cfg(test)]
99+
mod test {
100+
use crate::*;
101+
use crate::space::grounding::*;
102+
use super::*;
103+
104+
#[test]
105+
fn complex_query_two_subspaces() {
106+
let mut a = GroundingSpace::new();
107+
a.add(expr!("a" "b"));
108+
let mut b = GroundingSpace::new();
109+
b.add(expr!("b" "c"));
110+
111+
let mut main = ModuleSpace::new(GroundingSpace::new());
112+
main.add_dep(DynSpace::new(ModuleSpace::new(a)));
113+
main.add_dep(DynSpace::new(ModuleSpace::new(b)));
114+
115+
assert_eq_no_order!(main.query(&expr!("," (a "b") ("b" c))), vec![bind!{ a: sym!("a"), c: sym!("c") }]);
116+
assert_eq_no_order!(main.query(&expr!("," ("a" b) (b "c"))), vec![bind!{ b: sym!("b") }]);
117+
}
118+
}
119+

0 commit comments

Comments
 (0)