0,0 → 1,216 |
|
#ifndef __patterns_h__ |
#define __patterns_h__ |
|
/// \file |
/// Pattern matching code. |
/// |
/// General idea: have a class that can match function parameters |
/// to a pattern, check for predicates on the arguments, and return |
/// whether there was a match. |
/// |
/// First the pattern is mapped onto the arguments. Then local variables |
/// are set. Then the predicates are called. If they all return true, |
/// Then the pattern matches, and the locals can stay (the body is expected |
/// to use these variables). |
|
|
#include "yacasbase.h" |
#include "lisptype.h" |
#include "grower.h" |
#include "lispenvironment.h" |
|
|
/// Abstract class for matching one argument to a pattern. |
class YacasParamMatcherBase : public YacasBase |
{ |
public: |
/// Destructor. |
/// This function contains no code. |
virtual ~YacasParamMatcherBase(); |
|
/// Check whether some expression matches to the pattern. |
/// \param aEnvironment the underlying Lisp environment. |
/// \param aExpression the expression to test. |
/// \param arguments (input/output) actual values of the pattern |
/// variables for \a aExpression. |
virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
LispPtr& aExpression, |
LispPtr* arguments)=0; |
}; |
|
/// Class for matching an expression to a given atom. |
class MatchAtom : public YacasParamMatcherBase |
{ |
public: |
MatchAtom(LispString * aString); |
virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
LispPtr& aExpression, |
LispPtr* arguments); |
protected: |
LispString * iString; |
}; |
|
/// Class for matching an expression to a given number. |
class MatchNumber : public YacasParamMatcherBase |
{ |
public: |
MatchNumber(BigNumber* aNumber); |
virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
LispPtr& aExpression, |
LispPtr* arguments); |
protected: |
RefPtr<BigNumber> iNumber; |
}; |
|
/// Class for matching against a list of YacasParamMatcherBase objects. |
class MatchSubList : public YacasParamMatcherBase |
{ |
public: |
MatchSubList(YacasParamMatcherBase** aMatchers, LispInt aNrMatchers); |
~MatchSubList(); |
virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
LispPtr& aExpression, |
LispPtr* arguments); |
private: |
MatchSubList(const MatchSubList& aOther) : iMatchers(NULL),iNrMatchers(0) |
{ |
// copy constructor not written yet, hence the assert |
LISPASSERT(0); |
} |
MatchSubList& operator=(const MatchSubList& aOther) |
{ |
// copy constructor not written yet, hence the assert |
LISPASSERT(0); |
return *this; |
} |
protected: |
YacasParamMatcherBase** iMatchers; |
LispInt iNrMatchers; |
}; |
|
/// Class for matching against a pattern variable. |
class MatchVariable : public YacasParamMatcherBase |
{ |
public: |
MatchVariable(LispInt aVarIndex); |
|
/// Matches an expression against the pattern variable. |
/// \param aEnvironment the underlying Lisp environment. |
/// \param aExpression the expression to test. |
/// \param arguments (input/output) actual values of the pattern |
/// variables for \a aExpression. |
/// |
/// If entry #iVarIndex in \a arguments is still empty, the |
/// pattern matches and \a aExpression is stored in this |
/// entry. Otherwise, the pattern only matches if the entry equals |
/// \a aExpression. |
virtual LispBoolean ArgumentMatches(LispEnvironment& aEnvironment, |
LispPtr& aExpression, |
LispPtr* arguments); |
protected: |
/// Index of variable in YacasPatternPredicateBase::iVariables. |
LispInt iVarIndex; |
}; |
|
|
/// Class that matches function arguments to a pattern. |
/// This class (specifically, the Matches() member function) can match |
/// function parameters to a pattern, check for predicates on the |
/// arguments, and return whether there was a match. |
|
class YacasPatternPredicateBase : public YacasBase |
{ |
public: |
/// Constructor. |
/// \param aEnvironment the underlying Lisp environment |
/// \param aPattern Lisp expression containing the pattern |
/// \param aPostPredicate Lisp expression containing the |
/// postpredicate |
/// |
/// The function MakePatternMatcher() is called for every argument |
/// in \a aPattern, and the resulting pattern matchers are |
/// collected in #iParamMatchers. Additionally, \a aPostPredicate |
/// is copied, and the copy is added to #iPredicates. |
YacasPatternPredicateBase(LispEnvironment& aEnvironment, |
LispPtr& aPattern, |
LispPtr& aPostPredicate); |
|
/// Destructor. |
/// This function contains no code. |
~YacasPatternPredicateBase(); |
|
/// Try to match the pattern against \a aArguments. |
/// First, every argument in \a aArguments is matched against the |
/// corresponding YacasParamMatcherBase in #iParamMatches. If any |
/// match fails, Matches() returns false. Otherwise, a temporary |
/// LispLocalFrame is constructed, then SetPatternVariables() and |
/// CheckPredicates() are called, and then the LispLocalFrame is |
/// immediately deleted. If CheckPredicates() returns false, this |
/// function also returns false. Otherwise, SetPatternVariables() |
/// is called again, but now in the current LispLocalFrame, and |
/// this function returns true. |
LispBoolean Matches(LispEnvironment& aEnvironment, |
LispPtr& aArguments); |
|
/// Try to match the pattern against \a aArguments. |
/// This function does the same as Matches(LispEnvironment&,LispPtr&), |
/// but differs in the type of the arguments. |
LispBoolean Matches(LispEnvironment& aEnvironment, |
LispPtr* aArguments); |
|
protected: |
/// Construct a pattern matcher out of a Lisp expression. |
/// The result of this function depends on the value of \a aPattern: |
/// - If \a aPattern is a number, the corresponding MatchNumber is |
/// constructed and returned. |
/// - If \a aPattern is an atom, the corresponding MatchAtom is |
/// constructed and returned. |
/// - If \a aPattern is a list of the form <tt>( _ var )<tt>, |
/// where \c var is an atom, LookUp() is called on \c var. Then |
/// the correspoding MatchVariable is constructed and returned. |
/// - If \a aPattern is a list of the form <tt>( _ var expr )<tt>, |
/// where \c var is an atom, LookUp() is called on \c var. Then, |
/// \a expr is appended to #iPredicates. Finally, the |
/// correspoding MatchVariable is constructed and returned. |
/// - If \a aPattern is a list of another form, this function |
/// calls itself on any of the entries in this list. The |
/// resulting YacasParamMatcherBase objects are collected in a |
/// MatchSubList, which is returned. |
/// - Otherwise, this function returns #NULL. |
YacasParamMatcherBase* MakeParamMatcher(LispEnvironment& aEnvironment, LispObject* aPattern); |
|
/// Look up a variable name in #iVariables |
/// \returns index in #iVariables array where \a aVariable |
/// appears. |
/// |
/// If \a aVariable is not in #iVariables, it is added. |
LispInt LookUp(LispString * aVariable); |
|
protected: |
/// Set local variables corresponding to the pattern variables. |
/// This function goes through the #iVariables array. A local |
/// variable is made for every entry in the array, and the |
/// corresponding argument is assigned to it. |
void SetPatternVariables(LispEnvironment& aEnvironment, LispPtr* arguments); |
|
/// Check whether all predicates are true. |
/// This function goes through all predicates in #iPredicates, and |
/// evaluates them. It returns #LispFalse if at least one |
/// of these results IsFalse(). An error is raised if any result |
/// neither IsTrue() nor IsFalse(). |
LispBoolean CheckPredicates(LispEnvironment& aEnvironment); |
|
protected: |
/// List of parameter matches, one for every parameter. |
CDeletingArrayGrower<YacasParamMatcherBase*, ArrOpsDeletingPtr<YacasParamMatcherBase> > iParamMatchers; |
|
/// List of variables appearing in the pattern. |
CArrayGrower<LispString *, ArrOpsCustomPtr<LispString> > iVariables; |
|
/// List of predicates which need to be true for a match. |
CArrayGrower<LispPtr, ArrOpsCustomObj<LispPtr> > iPredicates; |
}; |
|
|
#endif |