From 80a044cea7d518ddbba73c7912dd0fbf43d3910b Mon Sep 17 00:00:00 2001
From: Adam Wardynski <award@.(B-4.4.46a)>
Date: Tue, 11 Jan 2011 17:56:46 +0100
Subject: [PATCH] Groundwork for WCCL rules: Rule, Action, ActionExecContext.
 Rule - user-level class encapsulating WCCL rule. Action - internal class for
 Rule's actions ActionExecContext - helper class for execution of actions.

---
 libwccl/ops/action.h            |  33 +++++
 libwccl/ops/actionexeccontext.h |  46 ++++++
 libwccl/ops/rule.cpp            |  58 ++++++++
 libwccl/ops/rule.h              | 250 ++++++++++++++++++++++++++++++++
 4 files changed, 387 insertions(+)
 create mode 100644 libwccl/ops/action.h
 create mode 100644 libwccl/ops/actionexeccontext.h
 create mode 100644 libwccl/ops/rule.cpp
 create mode 100644 libwccl/ops/rule.h

diff --git a/libwccl/ops/action.h b/libwccl/ops/action.h
new file mode 100644
index 0000000..666030c
--- /dev/null
+++ b/libwccl/ops/action.h
@@ -0,0 +1,33 @@
+#ifndef LIBWCCL_OPS_ACTION_H
+#define LIBWCCL_OPS_ACTION_H
+
+#include <boost/shared_ptr.hpp>
+#include <boost/assert.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_base_of.hpp>
+
+#include <libwccl/ops/expression.h>
+#include <libwccl/values/value.h>
+#include <libwccl/ops/actionexeccontext.h>
+
+namespace Wccl {
+
+/**
+ * Abstract base class for actions in WCCL rules
+ */
+class Action : public Expression
+{
+public:
+	/**
+	 * @returns Name of the action.
+	 */
+	virtual std::string name(const Corpus2::Tagset&) const = 0;
+	/**
+	 * Executes the action for the given execution context.
+	 */
+	virtual Bool execute(const ActionExecContext& context) const = 0;
+};
+
+} /* end ns Wccl */
+
+#endif // LIBWCCL_OPS_ACTION_H
diff --git a/libwccl/ops/actionexeccontext.h b/libwccl/ops/actionexeccontext.h
new file mode 100644
index 0000000..27115e5
--- /dev/null
+++ b/libwccl/ops/actionexeccontext.h
@@ -0,0 +1,46 @@
+#ifndef LIBWCCL_OPS_ACTIONEXECCONTEXT_H
+#define LIBWCCL_OPS_ACTIONEXECCONTEXT_H
+
+#include <boost/noncopyable.hpp>
+#include <libwccl/variables.h>
+#include <libwccl/sentencecontext.h>
+
+namespace Wccl {
+
+/**
+ * Class holding execution context of an action
+ * i.e. state that the action should operate on.
+ */
+class ActionExecContext : boost::noncopyable {
+public:
+	ActionExecContext(
+			SentenceContext& sentence_context,
+			const boost::shared_ptr<Variables>& vars)
+		: sentence_context_(sentence_context), vars_(vars)
+	{
+	}
+
+	/**
+	 * @returns Context of a sentence the action is executed on.
+	 */
+	SentenceContext& sentence_context() const {
+		return sentence_context_;
+	}
+
+	/**
+	 * @returns Pointer to variables the operator should operate with.
+	 * @note Variables should be accesible to modifications, but overall
+	 * object should not get replaced, hence the const pointer.
+	 */
+	const boost::shared_ptr<Variables>& variables() const {
+		return vars_;
+	}
+
+private:
+	SentenceContext& sentence_context_;
+	const boost::shared_ptr<Variables> vars_;
+};
+
+} /* end ns Wccl */
+
+#endif // LIBWCCL_OPS_ACTIONEXECCONTEXT_H
diff --git a/libwccl/ops/rule.cpp b/libwccl/ops/rule.cpp
new file mode 100644
index 0000000..0ff6262
--- /dev/null
+++ b/libwccl/ops/rule.cpp
@@ -0,0 +1,58 @@
+#include <libwccl/ops/rule.h>
+#include <sstream>
+
+namespace Wccl {
+
+Bool Rule::execute(SentenceContext &sentence_context)
+{
+	if(sentence_context.size() == 0) {
+		throw InvalidArgument(
+				"sentence_context",
+				"Received an empty sentence.");
+	}
+	if(!sentence_context.is_current_inside()) {
+		throw InvalidArgument(
+				"sentence_context",
+				"Current position is outside boundaries of the sentence.");
+	}
+	Bool changed(false);
+	if(condition_->apply(FunExecContext(sentence_context, variables_))->get_value()) {
+		ActionExecContext aec(sentence_context, variables_);
+		foreach(const boost::shared_ptr<Action>& action, *actions_) {
+			if(action->execute(aec).get_value()) {
+				changed.set_value(true);
+			}
+		}
+	}
+	return changed;
+}
+
+const boost::shared_ptr<const Function<Bool> > Rule::TrueCondition()
+{
+	static boost::shared_ptr<const Function<Bool> > true_constant(
+			new Constant<Bool>(Bool(true)));
+	return true_constant;
+}
+
+
+std::string Rule::to_string(const Corpus2::Tagset &tagset) const
+{
+	std::ostringstream os;
+	os << "rule(\"" << name_ << "\", " << condition_->to_string(tagset);
+	foreach(const boost::shared_ptr<Action>& action, *actions_) {
+		os << ", " << action->to_string(tagset);
+	}
+	os << ")";
+	return os.str();
+}
+
+std::ostream& Rule::write_to(std::ostream& os) const {
+	os << "rule(\"" << name_ << "\", " << *condition_;
+	foreach(const boost::shared_ptr<Action>& action, *actions_) {
+		os << ", " << *action;
+	}
+	os << ")";
+	return os;
+}
+
+} /* end ns Wccl */
diff --git a/libwccl/ops/rule.h b/libwccl/ops/rule.h
new file mode 100644
index 0000000..6b7a242
--- /dev/null
+++ b/libwccl/ops/rule.h
@@ -0,0 +1,250 @@
+#ifndef LIBWCCL_OPS_RULE_H
+#define LIBWCCL_OPS_RULE_H
+
+#include <boost/scoped_ptr.hpp>
+
+#include <libwccl/ops/parsedexpression.h>
+#include <libwccl/ops/functions/constant.h>
+#include <libwccl/ops/action.h>
+
+namespace Wccl {
+
+/**
+ * Represents a parsed WCCL Rule that executes some actions.
+ * @note The class methods are not thread-safe, but you can use clone method
+ * to acquire a separate copy of the Rule, and the copy can be used concurrently.
+ */
+class Rule : public ParsedExpression
+{
+public:
+	Rule(
+		const std::string& name,
+		const Variables& variables,
+		const boost::shared_ptr<const std::vector<boost::shared_ptr<Action> > >& actions,
+		const boost::shared_ptr<const Function<Bool> >& condition = TrueCondition());
+
+	/**
+	 * Evaluates condition and if it is true, executes the actions sequentially. Does
+	 * not execute any of the rules if condition is false.
+	 * @returns True if any of the actions made a change, False otherwise.
+	 * @param sentence_context SentenceContext of the Sentence to execute the Rule on.
+	 * @see execute() - equivalent method; the \link operator()() operator() \endlink allows
+	 * more convenient functional notation, however if you only have a pointer
+	 * you might prefer the apply method as shown below. The choice is yours.
+	 * \code
+	 * Bool res;
+	 * res = rule(sc);
+	 * // versus
+	 * res = rule.execute(sc);
+	 * // or if you have a pointer...
+	 * res = (*rule_ptr)(sc);
+	 * // versus
+	 * res = rule_ptr->apply(sc);
+	 * \endcode
+	 */
+	Bool operator()(SentenceContext& sentence_context);
+
+	/**
+	 * Evaluates condition and if it is true, executes the actions sequentially. Does
+	 * not execute any of the rules if condition is false.
+	 * @returns True if any of the actions made a change, False otherwise.
+	 * @param sentence_context SentenceContext of the Sentence to execute the Rule on.
+	 * @note The result is conciously marked as const, so a copy of Rule data
+	 * is not created unless necessary.
+	 * @see \link operator()() operator() \endlink - an equivalent of this method that allows
+	 * functional notation, treating Rule directly as a function
+	 */
+	Bool execute(SentenceContext& sentence_context);
+
+	/**
+	 * @returns Name of the Rule.
+	 */
+	std::string name() const;
+
+	/**
+	 * Makes a copy of the Rule, having its own space for Variables.
+	 * This allows the copy to be run concurrently (otherwise methods
+	 * of this class are not thread-safe; concurrent executions
+	 * on the same object would share Variables so don't do that).
+	 * @returns A copy of the Rule, including copy of Variables' values.
+	 * @note The values of the Variables are copied as they are, which is
+	 * a usable feature. If that is not what you want, use clone_clean()
+	 * or call clean() when you need it.
+	 * @see clone_clean - a convenience version that returns a copy with
+	 * all Variables set to their default values.
+	 * @see clone_ptr - a version that returns a copy wrapped in a shared
+	 * pointer
+	 * @see clone_clean_ptr - a version that returns a copy wrapped
+	 * in a shared pointer, and also having its Variables cleaned.
+	 * @see \link Rule(const Rule&, bool) copy constructor \endlink -
+	 * another way to create a copy
+	 * @see \link operator=(const Rule&) operator= \endlink - assignment
+	 * Rule, yet another way to create a copy.
+	 */
+	Rule clone() const;
+
+	/**
+	 * Makes a copy of the Rule, having its own space for Variables.
+	 * This allows the copy to be run concurrently (otherwise methods
+	 * of this class are not thread-safe; concurrent executions
+	 * on the same object would share Variables so don't do that).
+	 * All the Variables in the copy will have default values.
+	 * @returns A copy of the Rule with Variables that have default
+	 * values.
+	 * @see clone - a version that returns a copy without cleaning Variables.
+	 * @see clone_ptr - a version that returns a copy wrapped in a shared
+	 * pointer
+	 * @see clone_clean_ptr - a version that returns a copy wrapped
+	 * in a shared pointer, and also having its Variables cleaned.
+	 */
+	Rule clone_clean() const;
+
+	/**
+	 * @returns A copy of the expression, with values of the variables
+	 * copied as well.
+	 * @see clone_clean_ptr - convenience version that returns clean copy.
+	 */
+	boost::shared_ptr<Rule> clone_ptr() const;
+
+	/**
+	 * @returns A copy of the expression, with values of the variables
+	 * set to their defaults.
+	 * @see clone_ptr - a version that keeps values of the variables.
+	 */
+	boost::shared_ptr<Rule> clone_clean_ptr() const;
+
+	/**
+	 * Copy constructor, creates a copy with new set of values for
+	 * variables, allowing concurrent run of semantically same Rule
+	 * (running same physical Rule object is inherently not thread safe).
+	 * @param other - the Rule to copy.
+	 * @param clean - true if copy needs to have its variables
+	 * set to default values, false to keep the values; false is default
+	 */
+	Rule(const Rule& other, bool clean = false);
+
+	/**
+	 * Default constructor. Produces Rule that returns False.
+	 */
+	Rule();
+	/**
+	 * Assignment operator to create a workable copy of other Rule
+	 * (workable means it has a new set of values for variables, allowing
+	 * concurrent run of semantically same Rule; running same physical
+	 * Rule object is inherently not thread safe).
+	 * @note The values for variables are kept as in the original Rule.
+	 * @param other - Rule to copy
+	 * @returns A reference to the current object, after assignment.
+	 */
+	Rule& operator=(const Rule& other);
+
+	std::string to_string(const Corpus2::Tagset& tagset) const;
+
+protected:
+	Rule* clone_internal() const;
+	std::ostream& write_to(std::ostream& ostream) const;
+
+private:
+	static const boost::shared_ptr<const Function<Bool> > TrueCondition();
+	boost::shared_ptr<const std::vector<boost::shared_ptr<Action> > > actions_;
+	boost::shared_ptr<const Function<Bool> > condition_;
+	std::string name_;
+};
+
+
+
+//
+//--- implementation details ---
+//
+inline
+Rule::Rule(
+		const std::string& name,
+		const Variables& variables,
+		const boost::shared_ptr<const std::vector<boost::shared_ptr<Action> > >& actions,
+		const boost::shared_ptr<const Function<Bool> >& condition)
+	: ParsedExpression(variables),
+	  actions_(actions),
+	  condition_(condition),
+	  name_(name) {
+	BOOST_ASSERT(actions_);
+	BOOST_ASSERT(condition_);
+}
+
+inline
+Bool Rule::operator()(SentenceContext& sc) {
+	return execute(sc);
+}
+
+inline
+std::string Rule::name() const {
+	return name_;
+}
+
+inline
+Rule* Rule::clone_internal() const {
+	return new Rule(name_, *variables_, actions_, condition_);
+}
+
+inline
+Rule::Rule(const Rule &other, bool clean)
+	: ParsedExpression(*other.variables_),
+	  actions_(other.actions_),
+	  condition_(other.condition_),
+	  name_(other.name_)
+{
+	BOOST_ASSERT(actions_);
+	BOOST_ASSERT(condition_);
+	if(clean) {
+		this->clean();
+	}
+}
+
+inline
+Rule Rule::clone() const {
+	return *this;
+}
+
+inline
+Rule Rule::clone_clean() const {
+	return Rule(*this, true);
+}
+
+inline
+Rule& Rule::operator=(const Rule& other) {
+	BOOST_ASSERT(other.actions_);
+	BOOST_ASSERT(other.condition_);
+	actions_ = other.actions_;
+	condition_ = other.condition_;
+	name_ = other.name_;
+	variables_.reset(other.variables_->clone());
+	return *this;
+}
+
+inline
+Rule::Rule()
+	: ParsedExpression((Variables())),
+	  actions_(boost::make_shared<std::vector<boost::shared_ptr<Action> > >()),
+	  condition_(detail::DefaultFunction<Bool>()),
+	  name_()
+
+{
+	BOOST_ASSERT(actions_);
+	BOOST_ASSERT(condition_);
+}
+
+inline
+boost::shared_ptr<Rule> Rule::clone_ptr() const {
+	return boost::shared_ptr<Rule>(clone_internal());
+}
+
+inline
+boost::shared_ptr<Rule> Rule::clone_clean_ptr() const {
+	boost::shared_ptr<Rule> copy(clone_internal());
+	BOOST_ASSERT(copy);
+	copy->clean();
+	return copy;
+}
+
+} /* end ns Wccl */
+
+#endif // LIBWCCL_OPS_RULE_H
-- 
GitLab