Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | |
2 | #define __patterns_h__ |
||
3 | |||
4 | |||
5 | /// Pattern matching code. |
||
6 | /// |
||
7 | /// General idea: have a class that can match function parameters |
||
8 | /// to a pattern, check for predicates on the arguments, and return |
||
9 | /// whether there was a match. |
||
10 | /// |
||
11 | /// First the pattern is mapped onto the arguments. Then local variables |
||
12 | /// are set. Then the predicates are called. If they all return true, |
||
13 | /// Then the pattern matches, and the locals can stay (the body is expected |
||
14 | /// to use these variables). |
||
15 | |||
16 | |||
17 | |||
18 | #include "lisptype.h" |
||
19 | #include "grower.h" |
||
20 | #include "lispenvironment.h" |
||
21 | |||
22 | |||
23 | |||
24 | class YacasParamMatcherBase : public YacasBase |
||
25 | { |
||
26 | public: |
||
27 | /// Destructor. |
||
28 | /// This function contains no code. |
||
29 | virtual ~YacasParamMatcherBase(); |
||
30 | |||
31 | |||
32 | /// \param aEnvironment the underlying Lisp environment. |
||
33 | /// \param aExpression the expression to test. |
||
34 | /// \param arguments (input/output) actual values of the pattern |
||
35 | /// variables for \a aExpression. |
||
36 | virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
||
37 | LispPtr& aExpression, |
||
38 | LispPtr* arguments)=0; |
||
39 | }; |
||
40 | |||
41 | |||
42 | class MatchAtom : public YacasParamMatcherBase |
||
43 | { |
||
44 | public: |
||
45 | MatchAtom(LispString * aString); |
||
46 | virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
||
47 | LispPtr& aExpression, |
||
48 | LispPtr* arguments); |
||
49 | protected: |
||
50 | LispString * iString; |
||
51 | }; |
||
52 | |||
53 | |||
54 | class MatchNumber : public YacasParamMatcherBase |
||
55 | { |
||
56 | public: |
||
57 | MatchNumber(BigNumber* aNumber); |
||
58 | virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
||
59 | LispPtr& aExpression, |
||
60 | LispPtr* arguments); |
||
61 | protected: |
||
62 | RefPtr |
||
63 | }; |
||
64 | |||
65 | |||
66 | class MatchSubList : public YacasParamMatcherBase |
||
67 | { |
||
68 | public: |
||
69 | MatchSubList(YacasParamMatcherBase** aMatchers, LispInt aNrMatchers); |
||
70 | ~MatchSubList(); |
||
71 | virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
||
72 | LispPtr& aExpression, |
||
73 | LispPtr* arguments); |
||
74 | private: |
||
75 | MatchSubList(const MatchSubList& aOther) : iMatchers(NULL),iNrMatchers(0) |
||
76 | { |
||
77 | // copy constructor not written yet, hence the assert |
||
78 | LISPASSERT(0); |
||
79 | } |
||
80 | MatchSubList& operator=(const MatchSubList& aOther) |
||
81 | { |
||
82 | // copy constructor not written yet, hence the assert |
||
83 | LISPASSERT(0); |
||
84 | return *this; |
||
85 | } |
||
86 | protected: |
||
87 | YacasParamMatcherBase** iMatchers; |
||
88 | LispInt iNrMatchers; |
||
89 | }; |
||
90 | |||
91 | |||
92 | class MatchVariable : public YacasParamMatcherBase |
||
93 | { |
||
94 | public: |
||
95 | MatchVariable(LispInt aVarIndex); |
||
96 | |||
97 | |||
98 | /// \param aEnvironment the underlying Lisp environment. |
||
99 | /// \param aExpression the expression to test. |
||
100 | /// \param arguments (input/output) actual values of the pattern |
||
101 | /// variables for \a aExpression. |
||
102 | /// |
||
103 | /// If entry #iVarIndex in \a arguments is still empty, the |
||
104 | /// pattern matches and \a aExpression is stored in this |
||
105 | /// entry. Otherwise, the pattern only matches if the entry equals |
||
106 | /// \a aExpression. |
||
107 | virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
||
108 | LispPtr& aExpression, |
||
109 | LispPtr* arguments); |
||
110 | protected: |
||
111 | /// Index of variable in YacasPatternPredicateBase::iVariables. |
||
112 | LispInt iVarIndex; |
||
113 | }; |
||
114 | |||
115 | |||
116 | |||
117 | /// This class (specifically, the Matches() member function) can match |
||
118 | /// function parameters to a pattern, check for predicates on the |
||
119 | /// arguments, and return whether there was a match. |
||
120 | |||
121 | |||
122 | { |
||
123 | public: |
||
124 | /// Constructor. |
||
125 | /// \param aEnvironment the underlying Lisp environment |
||
126 | /// \param aPattern Lisp expression containing the pattern |
||
127 | /// \param aPostPredicate Lisp expression containing the |
||
128 | /// postpredicate |
||
129 | /// |
||
130 | /// The function MakePatternMatcher() is called for every argument |
||
131 | /// in \a aPattern, and the resulting pattern matchers are |
||
132 | /// collected in #iParamMatchers. Additionally, \a aPostPredicate |
||
133 | /// is copied, and the copy is added to #iPredicates. |
||
134 | YacasPatternPredicateBase(LispEnvironment& aEnvironment, |
||
135 | LispPtr& aPattern, |
||
136 | LispPtr& aPostPredicate); |
||
137 | |||
138 | |||
139 | /// This function contains no code. |
||
140 | ~YacasPatternPredicateBase(); |
||
141 | |||
142 | |||
143 | /// First, every argument in \a aArguments is matched against the |
||
144 | /// corresponding YacasParamMatcherBase in #iParamMatches. If any |
||
145 | /// match fails, Matches() returns false. Otherwise, a temporary |
||
146 | /// LispLocalFrame is constructed, then SetPatternVariables() and |
||
147 | /// CheckPredicates() are called, and then the LispLocalFrame is |
||
148 | /// immediately deleted. If CheckPredicates() returns false, this |
||
149 | /// function also returns false. Otherwise, SetPatternVariables() |
||
150 | /// is called again, but now in the current LispLocalFrame, and |
||
151 | /// this function returns true. |
||
152 | LispBoolean Matches(LispEnvironment& aEnvironment, |
||
153 | LispPtr& aArguments); |
||
154 | |||
155 | |||
156 | /// This function does the same as Matches(LispEnvironment&,LispPtr&), |
||
157 | /// but differs in the type of the arguments. |
||
158 | LispBoolean Matches(LispEnvironment& aEnvironment, |
||
159 | LispPtr* aArguments); |
||
160 | |||
161 | |||
162 | /// Construct a pattern matcher out of a Lisp expression. |
||
163 | /// The result of this function depends on the value of \a aPattern: |
||
164 | /// - If \a aPattern is a number, the corresponding MatchNumber is |
||
165 | /// constructed and returned. |
||
166 | /// - If \a aPattern is an atom, the corresponding MatchAtom is |
||
167 | /// constructed and returned. |
||
168 | /// - If \a aPattern is a list of the form ( _ var ), |
||
169 | /// where \c var is an atom, LookUp() is called on \c var. Then |
||
170 | /// the correspoding MatchVariable is constructed and returned. |
||
171 | /// - If \a aPattern is a list of the form ( _ var expr ), |
||
172 | /// where \c var is an atom, LookUp() is called on \c var. Then, |
||
173 | /// \a expr is appended to #iPredicates. Finally, the |
||
174 | /// correspoding MatchVariable is constructed and returned. |
||
175 | /// - If \a aPattern is a list of another form, this function |
||
176 | /// calls itself on any of the entries in this list. The |
||
177 | /// resulting YacasParamMatcherBase objects are collected in a |
||
178 | /// MatchSubList, which is returned. |
||
179 | /// - Otherwise, this function returns #NULL. |
||
180 | YacasParamMatcherBase* MakeParamMatcher(LispEnvironment& aEnvironment, LispObject* aPattern); |
||
181 | |||
182 | |||
183 | /// \returns index in #iVariables array where \a aVariable |
||
184 | /// appears. |
||
185 | /// |
||
186 | /// If \a aVariable is not in #iVariables, it is added. |
||
187 | LispInt LookUp(LispString * aVariable); |
||
188 | |||
189 | |||
190 | /// Set local variables corresponding to the pattern variables. |
||
191 | /// This function goes through the #iVariables array. A local |
||
192 | /// variable is made for every entry in the array, and the |
||
193 | /// corresponding argument is assigned to it. |
||
194 | void SetPatternVariables(LispEnvironment& aEnvironment, LispPtr* arguments); |
||
195 | |||
196 | |||
197 | /// This function goes through all predicates in #iPredicates, and |
||
198 | /// evaluates them. It returns #LispFalse if at least one |
||
199 | /// of these results IsFalse(). An error is raised if any result |
||
200 | /// neither IsTrue() nor IsFalse(). |
||
201 | LispBoolean CheckPredicates(LispEnvironment& aEnvironment); |
||
202 | |||
203 | |||
204 | /// List of parameter matches, one for every parameter. |
||
205 | CDeletingArrayGrower |
||
206 | |||
207 | |||
208 | CArrayGrower |
||
209 | |||
210 | |||
211 | CArrayGrower |
||
212 | }; |
||
213 | |||
214 | |||
215 | |||
216 |