@@ -9,43 +9,32 @@ use crate::{
9
9
resolver:: { QuerySolution , QuerySolver } ,
10
10
types:: InterpretingError ,
11
11
} ;
12
+ pub trait SolutionHandler {
13
+ fn handle_solution ( & self , solution : Option < & QuerySolution > ) -> bool ;
14
+ }
12
15
16
+ #[ derive( Default ) ]
13
17
pub struct Interpreter {
14
18
clauses : Vec < ( Predicate , Vec < Predicate > ) > ,
15
19
operator_definitions : HashMap < String , OperatorDefinition > ,
16
-
17
- on_solution : Option < Box < dyn Fn ( & QuerySolution ) -> bool > > ,
18
20
}
19
21
20
22
impl Interpreter {
21
- pub fn new ( ) -> Self {
22
- Interpreter {
23
- clauses : Vec :: new ( ) ,
24
- operator_definitions : HashMap :: new ( ) ,
25
- on_solution : None ,
26
- }
27
- }
28
-
29
- pub fn on_solution < F > ( & mut self , f : F )
30
- where
31
- F : Fn ( & QuerySolution ) -> bool + ' static ,
32
- {
33
- self . on_solution = Some ( Box :: new ( f) ) ;
34
- }
35
-
36
- pub fn eval ( & mut self , input : & str ) -> Result < ( ) , InterpretingError > {
23
+ pub fn eval (
24
+ & mut self ,
25
+ input : & str ,
26
+ handler : Option < & dyn SolutionHandler > ,
27
+ ) -> Result < ( ) , InterpretingError > {
37
28
let program = parse ( input) . map_err ( InterpretingError :: ParseError ) ?;
38
29
for clause in program. 0 {
39
30
let ret = match clause {
40
31
Clause :: Directive ( directive) => self . handle_directive ( directive) ,
41
- Clause :: Query ( query) => self . handle_query ( query) ,
32
+ Clause :: Query ( query) => self . handle_query ( query, handler ) ,
42
33
Clause :: Fact ( fact) => self . handle_fact ( fact) ,
43
34
Clause :: Rule ( rule_head, rule_body) => self . handle_rule ( rule_head, rule_body) ,
44
35
} ;
45
36
46
- if let Err ( e) = ret {
47
- return Err ( e) ;
48
- }
37
+ ret?
49
38
}
50
39
51
40
Ok ( ( ) )
@@ -65,21 +54,27 @@ impl Interpreter {
65
54
Ok ( ( ) )
66
55
}
67
56
68
- fn handle_query ( & mut self , query : Query ) -> Result < ( ) , InterpretingError > {
69
- log:: trace!( "handle query resolved: {:?}" , query) ;
70
- let mut query_solver = QuerySolver :: new ( self . clauses . clone ( ) , query) ;
71
- if let Some ( ref on_solution) = self . on_solution {
72
- while let Some ( solution) = query_solver. next ( ) {
73
- if !on_solution ( & solution) {
74
- break ;
75
- }
76
- }
77
- } else {
78
- for solution in query_solver {
79
- println ! ( "solution: {:?}" , solution) ;
57
+ fn handle_query (
58
+ & mut self ,
59
+ query : Query ,
60
+ handler : Option < & dyn SolutionHandler > ,
61
+ ) -> Result < ( ) , InterpretingError > {
62
+ log:: trace!( "handle query: {:?}" , query) ;
63
+ let handler = handler. unwrap_or ( & PrintSolutionHandler ) ;
64
+ let query_solver = QuerySolver :: new ( self . clauses . clone ( ) , query) ;
65
+
66
+ let mut has_solution = false ;
67
+ for solution in query_solver {
68
+ has_solution = true ;
69
+ if !handler. handle_solution ( Some ( & solution) ) {
70
+ break ;
80
71
}
81
72
}
82
73
74
+ if !has_solution {
75
+ handler. handle_solution ( None ) ;
76
+ }
77
+
83
78
Ok ( ( ) )
84
79
}
85
80
@@ -100,74 +95,139 @@ impl Interpreter {
100
95
}
101
96
}
102
97
98
+ pub struct PrintSolutionHandler ;
99
+
100
+ impl SolutionHandler for PrintSolutionHandler {
101
+ fn handle_solution ( & self , solution : Option < & QuerySolution > ) -> bool {
102
+ println ! ( "solution: {:?}" , solution) ;
103
+ true // Continue processing
104
+ }
105
+ }
106
+
103
107
#[ cfg( test) ]
104
108
mod tests {
109
+ use std:: cell:: RefCell ;
110
+
111
+ use crate :: environment:: Environment ;
112
+
105
113
use super :: * ;
114
+ use rulog_core:: types:: ast:: Term ;
106
115
use rulog_test_util:: setup_logger;
116
+ struct TestSolutionHandler {
117
+ expected_solutions : Vec < Option < QuerySolution > > ,
118
+ index : RefCell < usize > ,
119
+ }
120
+
121
+ impl TestSolutionHandler {
122
+ fn new ( expected_solutions : Vec < Option < QuerySolution > > ) -> Self {
123
+ Self {
124
+ expected_solutions,
125
+ index : RefCell :: new ( 0 ) ,
126
+ }
127
+ }
128
+ }
129
+
130
+ impl SolutionHandler for TestSolutionHandler {
131
+ fn handle_solution ( & self , solution : Option < & QuerySolution > ) -> bool {
132
+ let size = self . index . borrow ( ) . clone ( ) ;
133
+ if size < self . expected_solutions . len ( ) {
134
+ assert_eq ! (
135
+ solution,
136
+ self . expected_solutions[ size] . as_ref( ) ,
137
+ "expected solution: {:?}, actual solution: {:?}" ,
138
+ self . expected_solutions[ size] ,
139
+ solution
140
+ ) ;
141
+ self . index . replace ( size + 1 ) ;
142
+ true
143
+ } else {
144
+ false
145
+ }
146
+ }
147
+ }
107
148
108
149
#[ test]
109
150
fn test_parent_true ( ) {
110
151
setup_logger ( ) ;
111
- let mut vm = Interpreter :: new ( ) ;
152
+ let mut vm = Interpreter :: default ( ) ;
112
153
let ret = vm. eval (
113
154
r#"
114
155
parent(tom, liz).
115
156
?- parent(tom, liz).
116
157
"# ,
158
+ Some ( & TestSolutionHandler :: new ( vec ! [ Some (
159
+ QuerySolution :: default ( ) ,
160
+ ) ] ) ) ,
117
161
) ;
118
162
assert ! ( ret. is_ok( ) , "{:?}" , ret) ;
119
163
}
120
164
121
165
#[ test]
122
166
fn test_parent_false ( ) {
123
167
setup_logger ( ) ;
124
- let mut vm = Interpreter :: new ( ) ;
168
+ let mut vm = Interpreter :: default ( ) ;
125
169
let ret = vm. eval (
126
170
r#"
127
171
parent(tom, liz).
128
172
?- parent(liz, tom).
173
+ ?- parent(tom, liz).
129
174
"# ,
175
+ Some ( & TestSolutionHandler :: new ( vec ! [
176
+ None ,
177
+ Some ( QuerySolution :: default ( ) ) ,
178
+ ] ) ) ,
130
179
) ;
131
180
assert ! ( ret. is_ok( ) , "{:?}" , ret) ;
132
181
}
133
182
134
183
#[ test]
135
184
fn test_parent_var ( ) {
136
185
setup_logger ( ) ;
137
- let mut vm = Interpreter :: new ( ) ;
186
+ let mut vm = Interpreter :: default ( ) ;
138
187
let ret = vm. eval (
139
188
r#"
140
189
parent(tom, liz).
141
190
?- parent(X, liz).
142
191
"# ,
192
+ Some ( & TestSolutionHandler :: new ( vec ! [ Some ( QuerySolution {
193
+ env: Environment :: default ( ) . extend( "X" . to_string( ) , Term :: Atom ( "tom" . to_string( ) ) ) ,
194
+ } ) ] ) ) ,
143
195
) ;
144
196
assert ! ( ret. is_ok( ) , "{:?}" , ret) ;
145
197
}
146
198
147
199
#[ test]
148
200
fn test_parent_var_multiple ( ) {
149
201
setup_logger ( ) ;
150
- let mut vm = Interpreter :: new ( ) ;
202
+ let mut vm = Interpreter :: default ( ) ;
151
203
let ret = vm. eval (
152
204
r#"
153
205
parent(tom, liz).
154
206
parent(tom, bob).
155
207
?- parent(X, liz).
156
208
"# ,
209
+ Some ( & TestSolutionHandler :: new ( vec ! [ Some ( QuerySolution {
210
+ env: Environment :: default ( ) . extend( "X" . to_string( ) , Term :: Atom ( "tom" . to_string( ) ) ) ,
211
+ } ) ] ) ) ,
157
212
) ;
158
213
assert ! ( ret. is_ok( ) , "{:?}" , ret) ;
159
214
}
160
215
161
216
#[ test]
162
217
fn test_parent_var_multiple_children ( ) {
163
218
setup_logger ( ) ;
164
- let mut vm = Interpreter :: new ( ) ;
219
+ let mut vm = Interpreter :: default ( ) ;
165
220
let ret = vm. eval (
166
221
r#"
167
222
parent(tom, liz).
168
223
parent(tom, bob).
169
224
?- parent(tom, X).
170
225
"# ,
226
+ Some ( & TestSolutionHandler :: new ( vec ! [ Some ( QuerySolution {
227
+ env: Environment :: default ( )
228
+ . extend( "X" . to_string( ) , Term :: Atom ( "bob" . to_string( ) ) )
229
+ . extend( "X" . to_string( ) , Term :: Atom ( "liz" . to_string( ) ) ) ,
230
+ } ) ] ) ) ,
171
231
) ;
172
232
assert ! ( ret. is_ok( ) , "{:?}" , ret) ;
173
233
}
0 commit comments