1use logicaffeine_base::Arena;
15use crate::ast::{AspectOperator, LogicExpr, ModalVector, NounPhrase, QuantifierKind, TemporalOperator, VoiceOperator, Term, ThematicRole, Stmt, Expr, TypeExpr};
16use logicaffeine_base::Symbol;
17use crate::token::TokenType;
18
19#[derive(Clone, Copy)]
31pub struct AstContext<'a> {
32 pub exprs: &'a Arena<LogicExpr<'a>>,
34 pub terms: &'a Arena<Term<'a>>,
36 pub nps: &'a Arena<NounPhrase<'a>>,
38 pub syms: &'a Arena<Symbol>,
40 pub roles: &'a Arena<(ThematicRole, Term<'a>)>,
42 pub pps: &'a Arena<&'a LogicExpr<'a>>,
44 pub stmts: Option<&'a Arena<Stmt<'a>>>,
46 pub imperative_exprs: Option<&'a Arena<Expr<'a>>>,
48 pub type_exprs: Option<&'a Arena<TypeExpr<'a>>>,
50}
51
52impl<'a> AstContext<'a> {
53 pub fn new(
55 exprs: &'a Arena<LogicExpr<'a>>,
56 terms: &'a Arena<Term<'a>>,
57 nps: &'a Arena<NounPhrase<'a>>,
58 syms: &'a Arena<Symbol>,
59 roles: &'a Arena<(ThematicRole, Term<'a>)>,
60 pps: &'a Arena<&'a LogicExpr<'a>>,
61 ) -> Self {
62 AstContext { exprs, terms, nps, syms, roles, pps, stmts: None, imperative_exprs: None, type_exprs: None }
63 }
64
65 pub fn with_imperative(
67 exprs: &'a Arena<LogicExpr<'a>>,
68 terms: &'a Arena<Term<'a>>,
69 nps: &'a Arena<NounPhrase<'a>>,
70 syms: &'a Arena<Symbol>,
71 roles: &'a Arena<(ThematicRole, Term<'a>)>,
72 pps: &'a Arena<&'a LogicExpr<'a>>,
73 stmts: &'a Arena<Stmt<'a>>,
74 imperative_exprs: &'a Arena<Expr<'a>>,
75 ) -> Self {
76 AstContext { exprs, terms, nps, syms, roles, pps, stmts: Some(stmts), imperative_exprs: Some(imperative_exprs), type_exprs: None }
77 }
78
79 pub fn with_types(
81 exprs: &'a Arena<LogicExpr<'a>>,
82 terms: &'a Arena<Term<'a>>,
83 nps: &'a Arena<NounPhrase<'a>>,
84 syms: &'a Arena<Symbol>,
85 roles: &'a Arena<(ThematicRole, Term<'a>)>,
86 pps: &'a Arena<&'a LogicExpr<'a>>,
87 stmts: &'a Arena<Stmt<'a>>,
88 imperative_exprs: &'a Arena<Expr<'a>>,
89 type_exprs: &'a Arena<TypeExpr<'a>>,
90 ) -> Self {
91 AstContext {
92 exprs, terms, nps, syms, roles, pps,
93 stmts: Some(stmts),
94 imperative_exprs: Some(imperative_exprs),
95 type_exprs: Some(type_exprs),
96 }
97 }
98
99 pub fn alloc_stmt(&self, stmt: Stmt<'a>) -> &'a Stmt<'a> {
104 self.stmts.expect("imperative arenas not initialized").alloc(stmt)
105 }
106
107 pub fn alloc_imperative_expr(&self, expr: Expr<'a>) -> &'a Expr<'a> {
112 self.imperative_exprs.expect("imperative arenas not initialized").alloc(expr)
113 }
114
115 pub fn alloc_type_expr(&self, ty: TypeExpr<'a>) -> &'a TypeExpr<'a> {
120 self.type_exprs.expect("type_exprs arena not initialized").alloc(ty)
121 }
122
123 pub fn alloc_type_exprs<I>(&self, types: I) -> &'a [TypeExpr<'a>]
128 where
129 I: IntoIterator<Item = TypeExpr<'a>>,
130 I::IntoIter: ExactSizeIterator,
131 {
132 self.type_exprs.expect("type_exprs arena not initialized").alloc_slice(types)
133 }
134
135 pub fn alloc_expr(&self, expr: LogicExpr<'a>) -> &'a LogicExpr<'a> {
137 self.exprs.alloc(expr)
138 }
139
140 pub fn alloc_term(&self, term: Term<'a>) -> &'a Term<'a> {
142 self.terms.alloc(term)
143 }
144
145 pub fn alloc_terms<I>(&self, terms: I) -> &'a [Term<'a>]
147 where
148 I: IntoIterator<Item = Term<'a>>,
149 I::IntoIter: ExactSizeIterator,
150 {
151 self.terms.alloc_slice(terms)
152 }
153
154 pub fn alloc_np(&self, np: NounPhrase<'a>) -> &'a NounPhrase<'a> {
156 self.nps.alloc(np)
157 }
158
159 pub fn alloc_syms<I>(&self, syms: I) -> &'a [Symbol]
161 where
162 I: IntoIterator<Item = Symbol>,
163 I::IntoIter: ExactSizeIterator,
164 {
165 self.syms.alloc_slice(syms)
166 }
167
168 pub fn alloc_roles<I>(&self, roles: I) -> &'a [(ThematicRole, Term<'a>)]
170 where
171 I: IntoIterator<Item = (ThematicRole, Term<'a>)>,
172 I::IntoIter: ExactSizeIterator,
173 {
174 self.roles.alloc_slice(roles)
175 }
176
177 pub fn alloc_pps<I>(&self, pps: I) -> &'a [&'a LogicExpr<'a>]
179 where
180 I: IntoIterator<Item = &'a LogicExpr<'a>>,
181 I::IntoIter: ExactSizeIterator,
182 {
183 self.pps.alloc_slice(pps)
184 }
185
186 pub fn predicate(&self, name: Symbol, args: &'a [Term<'a>]) -> &'a LogicExpr<'a> {
188 self.exprs.alloc(LogicExpr::Predicate { name, args, world: None })
189 }
190
191 #[inline(always)]
193 pub fn binary(&self, left: &'a LogicExpr<'a>, op: TokenType, right: &'a LogicExpr<'a>) -> &'a LogicExpr<'a> {
194 self.exprs.alloc(LogicExpr::BinaryOp { left, op, right })
195 }
196
197 #[inline(always)]
199 pub fn unary(&self, op: TokenType, operand: &'a LogicExpr<'a>) -> &'a LogicExpr<'a> {
200 self.exprs.alloc(LogicExpr::UnaryOp { op, operand })
201 }
202
203 #[inline(always)]
205 pub fn quantifier(&self, kind: QuantifierKind, variable: Symbol, body: &'a LogicExpr<'a>, island_id: u32) -> &'a LogicExpr<'a> {
206 self.exprs.alloc(LogicExpr::Quantifier { kind, variable, body, island_id })
207 }
208
209 #[inline(always)]
211 pub fn temporal(&self, operator: TemporalOperator, body: &'a LogicExpr<'a>) -> &'a LogicExpr<'a> {
212 self.exprs.alloc(LogicExpr::Temporal { operator, body })
213 }
214
215 #[inline(always)]
217 pub fn aspectual(&self, operator: AspectOperator, body: &'a LogicExpr<'a>) -> &'a LogicExpr<'a> {
218 self.exprs.alloc(LogicExpr::Aspectual { operator, body })
219 }
220
221 #[inline(always)]
223 pub fn voice(&self, operator: VoiceOperator, body: &'a LogicExpr<'a>) -> &'a LogicExpr<'a> {
224 self.exprs.alloc(LogicExpr::Voice { operator, body })
225 }
226
227 #[inline(always)]
229 pub fn modal(&self, vector: ModalVector, operand: &'a LogicExpr<'a>) -> &'a LogicExpr<'a> {
230 self.exprs.alloc(LogicExpr::Modal { vector, operand })
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237 use crate::ast::{QuantifierKind, TemporalOperator, AspectOperator, ModalVector, ModalDomain};
238 use logicaffeine_base::Interner;
239 use crate::token::TokenType;
240
241 fn setup<'a>(
242 expr_arena: &'a Arena<LogicExpr<'a>>,
243 term_arena: &'a Arena<Term<'a>>,
244 np_arena: &'a Arena<NounPhrase<'a>>,
245 sym_arena: &'a Arena<Symbol>,
246 role_arena: &'a Arena<(ThematicRole, Term<'a>)>,
247 pp_arena: &'a Arena<&'a LogicExpr<'a>>,
248 ) -> AstContext<'a> {
249 AstContext::new(expr_arena, term_arena, np_arena, sym_arena, role_arena, pp_arena)
250 }
251
252 #[test]
253 fn binary_builder_creates_binary_op() {
254 let expr_arena: Arena<LogicExpr> = Arena::new();
255 let term_arena: Arena<Term> = Arena::new();
256 let np_arena: Arena<NounPhrase> = Arena::new();
257 let sym_arena: Arena<Symbol> = Arena::new();
258 let role_arena: Arena<(ThematicRole, Term)> = Arena::new();
259 let pp_arena: Arena<&LogicExpr> = Arena::new();
260 let ctx = setup(&expr_arena, &term_arena, &np_arena, &sym_arena, &role_arena, &pp_arena);
261
262 let mut interner = Interner::new();
263 let p = interner.intern("P");
264 let q = interner.intern("Q");
265
266 let left = ctx.alloc_expr(LogicExpr::Atom(p));
267 let right = ctx.alloc_expr(LogicExpr::Atom(q));
268 let result = ctx.binary(left, TokenType::And, right);
269
270 assert!(matches!(result, LogicExpr::BinaryOp { op: TokenType::And, .. }));
271 }
272
273 #[test]
274 fn unary_builder_creates_unary_op() {
275 let expr_arena: Arena<LogicExpr> = Arena::new();
276 let term_arena: Arena<Term> = Arena::new();
277 let np_arena: Arena<NounPhrase> = Arena::new();
278 let sym_arena: Arena<Symbol> = Arena::new();
279 let role_arena: Arena<(ThematicRole, Term)> = Arena::new();
280 let pp_arena: Arena<&LogicExpr> = Arena::new();
281 let ctx = setup(&expr_arena, &term_arena, &np_arena, &sym_arena, &role_arena, &pp_arena);
282
283 let mut interner = Interner::new();
284 let p = interner.intern("P");
285 let operand = ctx.alloc_expr(LogicExpr::Atom(p));
286 let result = ctx.unary(TokenType::Not, operand);
287
288 assert!(matches!(result, LogicExpr::UnaryOp { op: TokenType::Not, .. }));
289 }
290
291 #[test]
292 fn quantifier_builder_creates_quantifier() {
293 let expr_arena: Arena<LogicExpr> = Arena::new();
294 let term_arena: Arena<Term> = Arena::new();
295 let np_arena: Arena<NounPhrase> = Arena::new();
296 let sym_arena: Arena<Symbol> = Arena::new();
297 let role_arena: Arena<(ThematicRole, Term)> = Arena::new();
298 let pp_arena: Arena<&LogicExpr> = Arena::new();
299 let ctx = setup(&expr_arena, &term_arena, &np_arena, &sym_arena, &role_arena, &pp_arena);
300
301 let mut interner = Interner::new();
302 let x = interner.intern("x");
303 let p = interner.intern("P");
304 let body = ctx.alloc_expr(LogicExpr::Atom(p));
305 let result = ctx.quantifier(QuantifierKind::Universal, x, body, 0);
306
307 assert!(matches!(result, LogicExpr::Quantifier { kind: QuantifierKind::Universal, .. }));
308 }
309
310 #[test]
311 fn temporal_builder_creates_temporal() {
312 let expr_arena: Arena<LogicExpr> = Arena::new();
313 let term_arena: Arena<Term> = Arena::new();
314 let np_arena: Arena<NounPhrase> = Arena::new();
315 let sym_arena: Arena<Symbol> = Arena::new();
316 let role_arena: Arena<(ThematicRole, Term)> = Arena::new();
317 let pp_arena: Arena<&LogicExpr> = Arena::new();
318 let ctx = setup(&expr_arena, &term_arena, &np_arena, &sym_arena, &role_arena, &pp_arena);
319
320 let mut interner = Interner::new();
321 let p = interner.intern("P");
322 let body = ctx.alloc_expr(LogicExpr::Atom(p));
323 let result = ctx.temporal(TemporalOperator::Past, body);
324
325 assert!(matches!(result, LogicExpr::Temporal { operator: TemporalOperator::Past, .. }));
326 }
327
328 #[test]
329 fn aspectual_builder_creates_aspectual() {
330 let expr_arena: Arena<LogicExpr> = Arena::new();
331 let term_arena: Arena<Term> = Arena::new();
332 let np_arena: Arena<NounPhrase> = Arena::new();
333 let sym_arena: Arena<Symbol> = Arena::new();
334 let role_arena: Arena<(ThematicRole, Term)> = Arena::new();
335 let pp_arena: Arena<&LogicExpr> = Arena::new();
336 let ctx = setup(&expr_arena, &term_arena, &np_arena, &sym_arena, &role_arena, &pp_arena);
337
338 let mut interner = Interner::new();
339 let p = interner.intern("P");
340 let body = ctx.alloc_expr(LogicExpr::Atom(p));
341 let result = ctx.aspectual(AspectOperator::Progressive, body);
342
343 assert!(matches!(result, LogicExpr::Aspectual { operator: AspectOperator::Progressive, .. }));
344 }
345
346 #[test]
347 fn modal_builder_creates_modal() {
348 let expr_arena: Arena<LogicExpr> = Arena::new();
349 let term_arena: Arena<Term> = Arena::new();
350 let np_arena: Arena<NounPhrase> = Arena::new();
351 let sym_arena: Arena<Symbol> = Arena::new();
352 let role_arena: Arena<(ThematicRole, Term)> = Arena::new();
353 let pp_arena: Arena<&LogicExpr> = Arena::new();
354 let ctx = setup(&expr_arena, &term_arena, &np_arena, &sym_arena, &role_arena, &pp_arena);
355
356 let mut interner = Interner::new();
357 let p = interner.intern("P");
358 let operand = ctx.alloc_expr(LogicExpr::Atom(p));
359 let vector = ModalVector { domain: ModalDomain::Alethic, force: 1.0, flavor: crate::ast::ModalFlavor::Root };
360 let result = ctx.modal(vector, operand);
361
362 assert!(matches!(result, LogicExpr::Modal { .. }));
363 }
364}