diff --git a/libwccl/ops/varsetter.h b/libwccl/ops/varsetter.h
new file mode 100644
index 0000000000000000000000000000000000000000..0dcbbcecaf6479548e5f7322d8094673b703d2c0
--- /dev/null
+++ b/libwccl/ops/varsetter.h
@@ -0,0 +1,73 @@
+#ifndef LIBWCCL_OPS_VARSETTER_H
+#define LIBWCCL_OPS_VARSETTER_H
+
+#include <libwccl/ops/predicate.h>
+#include <libwccl/ops/formatters.h>
+
+namespace Wccl {
+
+/**
+ * Operator that sets value of a variable of given type T
+ * and returns True.
+ */
+template<class T>
+class VarSetter : public Function<Bool> {
+public:
+	typedef typename boost::shared_ptr<Function<T> > ArgFunctionPtr;
+
+	VarSetter(const VariableAccesor<T>& var_acc, const ArgFunctionPtr& arg_expr)
+		: var_acc_(var_acc),
+		  arg_expr_(arg_expr)
+	{
+		BOOST_ASSERT(arg_expr_);
+	}
+	
+	/**
+	 * @returns Operator name for variable setter, "setvar"
+	 */
+	virtual const std::string raw_operator_name() const {
+		return "setvar";
+	}
+
+	/**
+	 * @returns String representation of the variable setter which is
+	 * setvar(var_repr, arg_expr_str)
+	 */
+	virtual std::string to_raw_string() const {
+		return BinaryFunctionFormatter::to_raw_string(
+			*this,
+			T::var_repr(var_acc_.get_name()),
+			*arg_expr_);
+	}
+
+	/**
+	 * @returns String representation of the variable setter which is
+	 * setvar(var_repr, arg_raw_expr_str)
+	 */
+	virtual std::string to_string(const Corpus2::Tagset& tagset) const {
+		return BinaryFunctionFormatter::to_string(
+			tagset,
+			*this, 
+			T::var_repr(var_acc_.get_name()),
+			*arg_expr_);
+	}
+protected:
+	/**
+	 * Evaluate argument expression and assign the result to underlying variable.
+	 * @returns True.
+	 */
+	virtual BaseRetValPtr apply_internal(const FunExecContext& context) const {
+		context.variables()->get_fast(var_acc_)->set_value(
+			arg_expr_->apply(context)->get_value());
+		return Predicate::True(context);
+	}
+
+private:
+	const VariableAccesor<T> var_acc_;
+	const ArgFunctionPtr arg_expr_;
+};
+
+
+} /* end ns Wccl */
+
+#endif // LIBWCCL_OPS_VARSETTER_H
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3cf261cc6696e48e319d75d9c444587bb6dde238..28ed5a8d83e6a8f5cd37382cc3f71c531e7557b1 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -17,6 +17,7 @@ add_executable(tests
 	varaccess.cpp
 	vargetter.cpp
 	variables.cpp
+	varsetter.cpp
 )
 
 target_link_libraries ( tests wccl ${Boost_LIBRARIES} antlr)
diff --git a/tests/varsetter.cpp b/tests/varsetter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b6e8018334bb62441f139c0bad96ca77912054bd
--- /dev/null
+++ b/tests/varsetter.cpp
@@ -0,0 +1,272 @@
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+
+#include <libcorpus2/tagsetmanager.h>
+
+#include <libwccl/ops/varsetter.h>
+#include <libwccl/values/bool.h>
+#include <libwccl/values/tset.h>
+#include <libwccl/values/strset.h>
+#include <libwccl/ops/constant.h>
+
+using namespace Wccl;
+
+BOOST_AUTO_TEST_SUITE(varsetter)
+
+struct VarSetFix
+{
+	VarSetFix()
+		: sc(boost::make_shared<Corpus2::Sentence>()),
+		  cx(sc, boost::make_shared<Variables>()),
+		  tagset(Corpus2::get_named_tagset("kipi"))
+	{
+	}
+	SentenceContext sc;
+	FunExecContext cx;
+	Corpus2::Tagset tagset;
+};
+
+struct VarSetBoolFix : public VarSetFix
+{
+	VarSetBoolFix() 
+		: VarSetFix(),
+		  true_value(true),
+		  false_value(false),
+		  true_constant(new Constant<Bool>(true_value)),
+		  false_constant(new Constant<Bool>(false_value))
+	{
+		cx.variables()->put("True_bool", true_value);
+		cx.variables()->put("False_bool", false_value);
+	}
+	Bool true_value;
+	Bool false_value;
+	boost::shared_ptr<Function<Bool> > true_constant;
+	boost::shared_ptr<Function<Bool> > false_constant;
+};
+
+BOOST_FIXTURE_TEST_CASE(bool_apply, VarSetBoolFix)
+{
+	VariableAccesor<Bool> acc_t = cx.variables()->create_accesor<Bool>("True_bool");
+	VarSetter<Bool> var_setter(acc_t, false_constant);
+	BOOST_CHECK(cx.variables()->get<Bool>("True_bool")->get_value());
+	BOOST_CHECK(var_setter.apply(cx)->get_value());
+	BOOST_CHECK(!false_constant->apply(cx)->get_value());
+	BOOST_CHECK(!cx.variables()->get<Bool>("True_bool")->get_value());
+	VarSetter<Bool> var_setter_2(acc_t, true_constant);
+	BOOST_CHECK(var_setter_2.apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<Bool>("True_bool")->get_value());
+}
+
+BOOST_FIXTURE_TEST_CASE(bool_apply_acc_destruct, VarSetBoolFix)
+{
+	boost::shared_ptr<VarSetter<Bool> > var_setter;
+	{
+		VariableAccesor<Bool> acc_f = cx.variables()->create_accesor<Bool>("False_bool");
+		var_setter.reset(new VarSetter<Bool>(acc_f, true_constant));
+	}
+	BOOST_CHECK(var_setter->apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<Bool>("False_bool")->get_value());
+}
+
+struct VarSetPositionFix : public VarSetFix
+{
+	VarSetPositionFix()
+		: VarSetFix(),
+		  pos_69(69),
+		  nowhere(Position::Nowhere),
+		  pos_69_constant(new Constant<Position>(pos_69)),
+		  nowhere_constant(new Constant<Position>(nowhere))
+	{
+		cx.variables()->put("Nowhere", nowhere);
+		cx.variables()->put("End", Position(Position::End));
+		cx.variables()->put("Pos_69", pos_69);
+	}
+
+	Position pos_69;
+	Position nowhere;
+	boost::shared_ptr<Function<Position> > pos_69_constant;
+	boost::shared_ptr<Function<Position> > nowhere_constant;
+};
+
+BOOST_FIXTURE_TEST_CASE(set_position, VarSetPositionFix)
+{
+	VariableAccesor<Position> acc = cx.variables()->create_accesor<Position>("Nowhere");
+	VarSetter<Position> var_setter(acc, pos_69_constant);
+	BOOST_CHECK(cx.variables()->get<Position>("Nowhere")->equals(nowhere));
+	BOOST_CHECK(var_setter.apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<Position>("Nowhere")->equals(pos_69));
+}
+
+BOOST_FIXTURE_TEST_CASE(set_position_destruct, VarSetPositionFix)
+{
+	boost::shared_ptr<VarSetter<Position> > var_setter;
+	{
+		VariableAccesor<Position> acc = cx.variables()->create_accesor<Position>("Pos_69");
+		var_setter.reset(new VarSetter<Position>(acc, nowhere_constant));
+	}
+	BOOST_CHECK(cx.variables()->get<Position>("Pos_69")->equals(pos_69));
+	BOOST_CHECK(var_setter->apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<Position>("Pos_69")->equals(nowhere));
+}
+
+struct VarSetStrSetFix : public VarSetFix
+{
+	VarSetStrSetFix()
+		: VarSetFix(),
+		  one_elem_set(),
+		  empty_set(),
+		  one_elem_set_constant(),
+		  empty_set_constant(new Constant<StrSet>(empty_set))
+	{
+		one_elem_set.insert_utf8("ThereCanBeOnly1");
+		one_elem_set_constant.reset(new Constant<StrSet>(one_elem_set));
+		cx.variables()->put("OneElemSet", one_elem_set);
+		cx.variables()->put("EmptySet", empty_set);
+	}
+
+	StrSet one_elem_set;
+	StrSet empty_set;
+	boost::shared_ptr<Function<StrSet> > one_elem_set_constant;
+	boost::shared_ptr<Function<StrSet> > empty_set_constant;
+};
+
+BOOST_FIXTURE_TEST_CASE(set_strset, VarSetStrSetFix)
+{
+	VariableAccesor<StrSet> acc = cx.variables()->create_accesor<StrSet>("EmptySet");
+	VarSetter<StrSet> var_setter(acc, one_elem_set_constant);
+	BOOST_CHECK(cx.variables()->get<StrSet>("EmptySet")->equals(empty_set));
+	BOOST_CHECK(var_setter.apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<StrSet>("EmptySet")->equals(one_elem_set));
+}
+
+BOOST_FIXTURE_TEST_CASE(set_strset_destruct, VarSetStrSetFix)
+{
+	boost::shared_ptr<VarSetter<StrSet> > var_setter;
+	{
+		VariableAccesor<StrSet> acc = cx.variables()->create_accesor<StrSet>("OneElemSet");
+		var_setter.reset(new VarSetter<StrSet>(acc, empty_set_constant));
+	}
+	BOOST_CHECK(cx.variables()->get<StrSet>("OneElemSet")->equals(one_elem_set));
+	BOOST_CHECK(var_setter->apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<StrSet>("OneElemSet")->equals(empty_set));
+}
+
+struct VarSetTSetFix : public VarSetFix
+{
+	VarSetTSetFix()
+		: VarSetFix(),
+		  empty_tset(),
+		  subst_pl_tag(),
+		  empty_tset_constant(new Constant<TSet>(empty_tset)),
+		  subst_pl_tag_constant()
+	{
+		subst_pl_tag.insert_symbol(tagset, "subst");
+		subst_pl_tag.insert_symbol(tagset, "pl");
+		subst_pl_tag_constant.reset(new Constant<TSet>(subst_pl_tag));
+		cx.variables()->put("EmptyTag", empty_tset);
+		cx.variables()->put("SubstPl", subst_pl_tag);
+	}
+	
+	TSet empty_tset;
+	TSet subst_pl_tag;
+	boost::shared_ptr<Function<TSet> > empty_tset_constant;
+	boost::shared_ptr<Function<TSet> > subst_pl_tag_constant;
+};
+
+BOOST_FIXTURE_TEST_CASE(set_tset, VarSetTSetFix)
+{
+	VariableAccesor<TSet> acc = cx.variables()->create_accesor<TSet>("EmptyTag");
+	VarSetter<TSet> var_setter(acc, subst_pl_tag_constant);
+	BOOST_CHECK(cx.variables()->get<TSet>("EmptyTag")->equals(empty_tset));
+	BOOST_CHECK(var_setter.apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<TSet>("EmptyTag")->equals(subst_pl_tag));
+}
+
+BOOST_FIXTURE_TEST_CASE(set_TSet_destruct, VarSetTSetFix)
+{
+	boost::shared_ptr<VarSetter<TSet> > var_setter;
+	{
+		VariableAccesor<TSet> acc = cx.variables()->create_accesor<TSet>("SubstPl");
+		var_setter.reset(new VarSetter<TSet>(acc, empty_tset_constant));
+	}
+	BOOST_CHECK(cx.variables()->get<TSet>("SubstPl")->equals(subst_pl_tag));
+	BOOST_CHECK(var_setter->apply(cx)->get_value());
+	BOOST_CHECK(cx.variables()->get<TSet>("SubstPl")->equals(empty_tset));
+}
+
+//----  To String -----
+
+BOOST_FIXTURE_TEST_CASE(bool_varset_to_string, VarSetBoolFix)
+{
+	VariableAccesor<Bool> acc_t = cx.variables()->create_accesor<Bool>("True_bool");
+	VarSetter<Bool> var_setter_t(acc_t, false_constant);
+	std::string expected =
+		"setvar(" + Bool::var_repr("True_bool") + ", False)";
+	BOOST_CHECK_EQUAL(expected, var_setter_t.to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(bool_varset_to_raw_string, VarSetBoolFix)
+{
+	VariableAccesor<Bool> acc_t = cx.variables()->create_accesor<Bool>("True_bool");
+	VarSetter<Bool> var_setter_t(acc_t, false_constant);
+	std::string expected =
+		"setvar(" + Bool::var_repr("True_bool") + ", False)";
+	BOOST_CHECK_EQUAL(expected, var_setter_t.to_raw_string());
+}
+
+BOOST_FIXTURE_TEST_CASE(position_varset_to_string, VarSetPositionFix)
+{
+	VariableAccesor<Position> acc_t = cx.variables()->create_accesor<Position>("Nowhere");
+	VarSetter<Position> var_setter_t(acc_t, pos_69_constant);
+	std::string expected =
+		"setvar(" + Position::var_repr("Nowhere") + ", 69)";
+	BOOST_CHECK_EQUAL(expected, var_setter_t.to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(position_varset_to_raw_string, VarSetPositionFix)
+{
+	VariableAccesor<Position> acc_t = cx.variables()->create_accesor<Position>("End");
+	VarSetter<Position> var_setter_t(acc_t, nowhere_constant);
+	std::string expected =
+		"setvar(" + Position::var_repr("End") + ", nowhere)";
+	BOOST_CHECK_EQUAL(expected, var_setter_t.to_raw_string());
+}
+
+BOOST_FIXTURE_TEST_CASE(StrSet_varset_to_string, VarSetStrSetFix)
+{
+	VariableAccesor<StrSet> acc = cx.variables()->create_accesor<StrSet>("EmptySet");
+	VarSetter<StrSet> var_setter_t(acc, one_elem_set_constant);
+	std::string expected =
+		"setvar(" + StrSet::var_repr("EmptySet") + ", [\"ThereCanBeOnly1\"])";
+	BOOST_CHECK_EQUAL(expected, var_setter_t.to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(StrSet_varset_to_raw_string, VarSetStrSetFix)
+{
+	VariableAccesor<StrSet> acc = cx.variables()->create_accesor<StrSet>("EmptySet");
+	VarSetter<StrSet> var_setter(acc, one_elem_set_constant);
+	std::string expected =
+		"setvar(" + StrSet::var_repr("EmptySet") + ", [\"ThereCanBeOnly1\"])";
+	BOOST_CHECK_EQUAL(expected, var_setter.to_raw_string());
+}
+
+BOOST_FIXTURE_TEST_CASE(tset_varset_to_string, VarSetTSetFix)
+{
+	VariableAccesor<TSet> acc = cx.variables()->create_accesor<TSet>("SubstPl");
+	VarSetter<TSet> var_setter(acc, subst_pl_tag_constant);
+	std::string expected =
+		"setvar(" + TSet::var_repr("SubstPl") + ", " + subst_pl_tag_constant->to_string(tagset) + ")";
+	BOOST_CHECK_EQUAL(expected, var_setter.to_string(tagset));
+}
+
+BOOST_FIXTURE_TEST_CASE(tset_varset_to_raw_string, VarSetTSetFix)
+{
+	VariableAccesor<TSet> acc = cx.variables()->create_accesor<TSet>("SubstPl");
+	VarSetter<TSet> var_setter(acc, subst_pl_tag_constant);
+	std::string expected =
+		"setvar(" + TSet::var_repr("SubstPl") + ", " + subst_pl_tag_constant->to_raw_string() + ")";
+	BOOST_CHECK_EQUAL(expected, var_setter.to_raw_string());
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()