Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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