fetish_lib/
interpreter_state.rs

1extern crate ndarray;
2extern crate ndarray_linalg;
3
4use ndarray::*;
5use std::collections::HashMap;
6use crate::nonprimitive_term_pointer::*;
7use crate::newly_evaluated_terms::*;
8use crate::type_id::*;
9use crate::application_table::*;
10use crate::type_space::*;
11use crate::term_index::*;
12use crate::term::*;
13use crate::context::*;
14use crate::params::*;
15use crate::term_pointer::*;
16use crate::term_reference::*;
17use crate::term_application::*;
18use crate::term_application_result::*;
19use crate::primitive_term_pointer::*;
20use crate::func_impl::*;
21use topological_sort::TopologicalSort;
22
23///Represents the state of a simple interpreter for the combinatorial language
24///defined through the referenced [`Context`], with the given [`TypeId`]-indexed
25///[`TypeSpace`]s and [`ApplicationTable`]s memoizing all known non-primitive terms
26///and results of term evaluations, respectively. 
27pub struct InterpreterState<'a> {
28    pub application_tables : HashMap::<TypeId, ApplicationTable<'a>>,
29    pub type_spaces : HashMap::<TypeId, TypeSpace>,
30    pub ctxt : &'a Context
31}
32
33impl <'a> InterpreterState<'a> {
34    ///Gets the [`Context`] that this [`InterpreterState`] operates within.
35    pub fn get_context(&self) -> &Context {
36        self.ctxt
37    }
38
39    ///Stores the given [`PartiallyAppliedTerm`] in the [`TypeSpace`] for the
40    ///given [`TypeId`], if it wasn't already present. Returns a
41    ///[`NonPrimitiveTermPointer`] referencing where it was stored
42    ///in this [`InterpreterState`].
43    pub fn store_term(&mut self, type_id : TypeId, term : PartiallyAppliedTerm) -> NonPrimitiveTermPointer {
44        let type_space : &mut TypeSpace = self.type_spaces.get_mut(&type_id).unwrap();
45        let result = type_space.add(term);
46        result
47    }
48
49    ///Given a [`TermPointer`], yields the [`PartiallyAppliedTerm`] which
50    ///is stored at that location within this [`InterpreterState`] (or, 
51    ///in the case of a primitive, within the containing `Context`)
52    pub fn get(&self, term_ptr : TermPointer) -> PartiallyAppliedTerm {
53        match (term_ptr.index) {
54            TermIndex::Primitive(index) => {
55                let primitive_ptr = PrimitiveTermPointer {
56                    type_id : term_ptr.type_id,
57                    index : index
58                };
59                let result = PartiallyAppliedTerm::new(primitive_ptr);
60                result
61            },
62            TermIndex::NonPrimitive(index) => {
63                self.type_spaces.get(&term_ptr.type_id).unwrap().get(index).clone()
64            }
65        }
66    }
67
68    ///Given a [`NonPrimitiveTermPointer`], yields the [`PartiallyAppliedTerm`]
69    ///which is stored at that location within this [`InterpreterState`].
70    pub fn get_nonprimitive(&self, term_ptr : NonPrimitiveTermPointer) -> &PartiallyAppliedTerm {
71        self.type_spaces.get(&term_ptr.type_id).unwrap().get(term_ptr.index)
72    }
73
74    ///Gets all currently-known [`TermApplicationResult`]s which use the given [`TermReference`] argument.
75    pub fn get_app_results_with_arg(&self, arg : &TermReference) -> Vec<TermApplicationResult> {
76        let mut result : Vec<TermApplicationResult> = Vec::new();
77        for table in self.application_tables.values() {
78            let mut temp = table.get_app_results_with_arg(arg);
79            result.append(&mut temp);
80        }
81        result
82    }
83
84    ///Gets all currently-known [`TermApplicationResult`]s which involve the function
85    ///that the given [`TermPointer`] points to.
86    pub fn get_app_results_with_func(&self, func : TermPointer) -> Vec<TermApplicationResult> {
87        let mut result : Vec<TermApplicationResult> = Vec::new();
88        for table in self.application_tables.values() {
89            let mut temp = table.get_app_results_with_func(func);
90            result.append(&mut temp);
91        }
92        result
93    }
94
95    ///Gets all currently-known [`TermApplicationResult`]s which had the given [`TermReference`]
96    ///result.
97    pub fn get_app_results_with_result(&self, result_term : &TermReference) -> Vec<TermApplicationResult> {
98        let mut result : Vec<TermApplicationResult> = Vec::new();
99        for table in self.application_tables.values() {
100            let mut temp = table.get_app_results_with_result(result_term);
101            result.append(&mut temp);
102        }
103        result
104    }
105
106    ///Evaluates the given [`TermApplication`] against this [`InterpreterState`], assuming
107    ///that the function pointed to in the [`TermApplication`] is a primitive. Yields
108    ///a [`TermReference`] to the result of the evaluation, and a list of [`NewlyEvaluatedTerms`]
109    ///for this [`InterpreterState`] which resulted from evaluating the application.
110    pub fn evaluate(&mut self, term_app : &TermApplication) -> (TermReference, NewlyEvaluatedTerms) {
111        let func_type_id : TypeId = term_app.get_func_type();
112
113        let func_term : PartiallyAppliedTerm = self.get(term_app.func_ptr);
114        let arg_ref : TermReference = term_app.arg_ref.clone();
115
116        let func_impl = self.ctxt.get_primitive(func_term.func_ptr);
117        let mut args_copy = func_term.args.clone();
118
119        args_copy.push(arg_ref);
120
121        let mut newly_evaluated_terms = NewlyEvaluatedTerms::new();
122
123        let result_ref : TermReference = if (func_impl.ready_to_evaluate(&args_copy)) {
124            let (ret_ref, more_evaluated_terms) = func_impl.evaluate(self, args_copy);
125            newly_evaluated_terms.merge(more_evaluated_terms);
126            ret_ref
127        } else {
128            let result = PartiallyAppliedTerm {
129                func_ptr : func_term.func_ptr.clone(),
130                args : args_copy
131            };
132            let ret_type_id : TypeId = term_app.get_ret_type(self.ctxt);
133            let ret_ptr = self.store_term(ret_type_id, result);
134
135            newly_evaluated_terms.add_term(ret_ptr);
136
137            let ret_ref = TermReference::FuncRef(TermPointer::from(ret_ptr));
138            ret_ref
139        };
140        let application_table : &mut ApplicationTable = self.application_tables.get_mut(&func_type_id).unwrap();
141
142        let term_app_result = TermApplicationResult {
143            term_app : term_app.clone(),
144            result_ref : result_ref.clone()
145        };
146
147        newly_evaluated_terms.add_term_app_result(term_app_result);
148
149        application_table.link(term_app.clone(), result_ref.clone());
150        (result_ref, newly_evaluated_terms)
151    }
152
153    ///Convenience method that ensures that every type has at least one term, assuming
154    ///that this [`InterpreterState`] was just-initialized. Returns [`NewlyEvaluatedTerms`]
155    ///for evaluations that were performed as a result of this operation.
156    pub fn ensure_every_type_has_a_term_on_init(&mut self) -> NewlyEvaluatedTerms {
157	let mut type_to_term = HashMap::<TypeId, TermReference>::new();
158        //Initial population
159        for i in 0..self.ctxt.get_total_num_types() {
160            let type_id = i as TypeId;
161            let kind = self.ctxt.get_type(type_id);
162            match (kind) {
163                Type::VecType(n) => {
164                    type_to_term.insert(type_id, TermReference::VecRef(type_id, Array::zeros((n,))));
165                },
166                Type::FuncType(_, _) => {
167                    let primitive_space = self.ctxt.primitive_directory.primitive_type_spaces.get(&type_id).unwrap();
168                    
169                    if (primitive_space.terms.len() > 0) {
170                        let func_ptr = TermPointer {
171                            type_id : type_id,
172                            index : TermIndex::Primitive(0)
173                        };
174                        type_to_term.insert(type_id, TermReference::FuncRef(func_ptr));
175                    }
176                }
177            }
178        }
179        let mut newly_evaluated_terms = NewlyEvaluatedTerms::new();
180        loop {
181            let mut found_something = false;
182            for i in 0..self.ctxt.get_total_num_types() {
183                let func_type_id = i as TypeId;
184
185                if let Option::Some(func_term) = type_to_term.get(&func_type_id) {
186                    if let Type::FuncType(arg_type_id, ret_type_id) = self.ctxt.get_type(func_type_id) {
187                        if let Option::Some(arg_ref) = type_to_term.get(&arg_type_id) {
188                            if (!type_to_term.contains_key(&ret_type_id)) {
189                                if let TermReference::FuncRef(func_ptr) = func_term {
190                                    let application = TermApplication {
191                                        func_ptr : func_ptr.clone(),
192                                        arg_ref : arg_ref.clone()
193                                    };
194                                    let (result_ref, more_evaluated_terms) = self.evaluate(&application);
195                                    newly_evaluated_terms.merge(more_evaluated_terms);
196                                    type_to_term.insert(ret_type_id, result_ref);
197
198                                    found_something = true;
199                                }
200                            }
201                        }
202                    }
203                }
204            }
205            if (!found_something) {
206                break;
207            }
208        }
209        newly_evaluated_terms
210    }
211
212    ///Constructs a fresh [`InterpreterState`] operating within the given [`Context`].
213    pub fn new(ctxt : &'a Context) -> InterpreterState<'a> {
214        //Initialize hashmaps for each type in the global type table 
215        let mut application_tables = HashMap::<TypeId, ApplicationTable>::new();
216        let mut type_spaces = HashMap::<TypeId, TypeSpace>::new();
217
218        for type_id in 0..ctxt.get_total_num_types() {
219            if (!ctxt.is_vector_type(type_id)) {
220                application_tables.insert(type_id, ApplicationTable::new(type_id, ctxt));
221                type_spaces.insert(type_id, TypeSpace::new(type_id));
222            }
223        }
224
225        let result = InterpreterState {
226            application_tables,
227            type_spaces,
228            ctxt
229        };
230
231        result
232    }
233}