diff --git a/libwccl/CMakeLists.txt b/libwccl/CMakeLists.txt index 67043e6687af132c66f3f37d391db5786ce4aa93..662d94d5bdb1c125433b1b425db3824a48f24477 100644 --- a/libwccl/CMakeLists.txt +++ b/libwccl/CMakeLists.txt @@ -35,6 +35,7 @@ SET(libwccl_STAT_SRC ops/or.cpp ops/predicate.cpp ops/regex.cpp + ops/relativeposition.cpp ops/tolower.cpp ops/toupper.cpp parser/Parser.cpp diff --git a/libwccl/ops/relativeposition.cpp b/libwccl/ops/relativeposition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a0d73d000886ea93740905d01a2f1cd7b71461f --- /dev/null +++ b/libwccl/ops/relativeposition.cpp @@ -0,0 +1,43 @@ +#include <libwccl/ops/relativeposition.h> +#include <sstream> +#include <libwccl/ops/constant.h> + +namespace Wccl { + +RelativePosition::BaseRetValPtr RelativePosition::apply_internal( + const FunExecContext &context) const +{ + static const Constant<Position> nowhere((Position(Position::Nowhere))); + const RetValPtr& orig_pos = pos_expr_->apply(context); + if(orig_pos->get_value() == Position::Nowhere) { + return nowhere.apply(context); + } + const SentenceContext& sc = context.sentence_context(); + return RetValPtr(new Position(offset_ + sc.get_rel_position(*orig_pos))); +} + +std::string RelativePosition::to_string(const Corpus2::Tagset &tagset) const +{ + std::stringstream ss; + ss << pos_expr_->to_string(tagset); + if(offset_ >= 0) { + ss << " + " << offset_; + } else { + ss << " - " << -offset_; + } + return ss.str(); +} + +std::string RelativePosition::to_raw_string() const +{ + std::stringstream ss; + ss << pos_expr_->to_raw_string(); + if(offset_ >= 0) { + ss << " + " << offset_; + } else { + ss << " - " << -offset_; + } + return ss.str(); +} + +} /* end ns Wccl */ diff --git a/libwccl/ops/relativeposition.h b/libwccl/ops/relativeposition.h new file mode 100644 index 0000000000000000000000000000000000000000..2fb9961b4bf416a0784bb441a44eef0bcdf9dc11 --- /dev/null +++ b/libwccl/ops/relativeposition.h @@ -0,0 +1,57 @@ +#ifndef LIBWCCL_OPS_RELATIVEPOSITION_H +#define LIBWCCL_OPS_RELATIVEPOSITION_H + +#include <libwccl/ops/functions.h> +#include <libwccl/ops/formatters.h> +#include <libwccl/values/position.h> + +namespace Wccl { + +/** + * Operator that takes a Position and an offset and returns relative + * Position, shifted by the offset from the original one. + */ +class RelativePosition : public Function<Position> { +public: + typedef boost::shared_ptr<Function<Position> > PosFunctionPtr; + + RelativePosition(const PosFunctionPtr& pos_expr, int offset) + : pos_expr_(pos_expr), + offset_(offset) + { + BOOST_ASSERT(pos_expr_); + } + + virtual std::string to_string(const Corpus2::Tagset& tagset) const; + + virtual std::string to_raw_string() const; + + virtual const std::string raw_operator_name() const { + return "+"; + } + +protected: + const PosFunctionPtr pos_expr_; + const int offset_; + + /** + * Takes the value of a Position from argument expression, and returns + * a Position relative to it, shifted by the offset that this + * RelativePosition object is representing. + * The result is not being trimmed to boundaries of the current + * sentence (a Position pointing outside of a sentence is still + * a valid Position). + * If "nowhere" is given, "nowhere" is returned (shifted "nowhere" + * still points to "nowhere"). + * If "begin" or "end" are given, they are first represented as a normal + * Position Value (i.e. a Position relative to the current Position + * in the SentenceContext acted upon) which is then shifted normally. + * @returns Position that is shifted by the represented offset relative + * to the Position being passed as argument to Operator. + */ + virtual BaseRetValPtr apply_internal(const FunExecContext& context) const; +}; + +} /* end ns Wccl */ + +#endif // LIBWCCL_OPS_RELATIVEPOSITION_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6b6035e7ce2cdef86b634fc107b50d91af4ad47f..d965a98803a0f21a4e099c2827cc7792dc86b1ff 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(tests position.cpp positionpredicates.cpp regex.cpp + relativeposition.cpp strsetfunctions.cpp values.cpp varaccess.cpp diff --git a/tests/relativeposition.cpp b/tests/relativeposition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00d70a454d0ef3abe2366774230ab4cd46147212 --- /dev/null +++ b/tests/relativeposition.cpp @@ -0,0 +1,164 @@ +#include <boost/test/unit_test.hpp> +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <libcorpus2/sentence.h> + +#include <libwccl/ops/constant.h> +#include <libwccl/ops/relativeposition.h> + +using namespace Wccl; + +BOOST_AUTO_TEST_SUITE(relative_position) + +struct PosPredFix +{ + PosPredFix() + : s(boost::make_shared<Corpus2::Sentence>()), + sc(s), + tagset(), + cx(sc, boost::make_shared<Variables>()), + pos_one(1), + pos_minus_one(-1), + nowhere(Position::Nowhere), + begin(Position::Begin), + end(Position::End), + pos_one_constant(new Constant<Position>(pos_one)), + pos_minus_one_constant(new Constant<Position>(pos_minus_one)), + nowhere_constant(new Constant<Position>(nowhere)), + begin_constant(new Constant<Position>(begin)), + end_constant(new Constant<Position>(end)) + { + Corpus2::Token* the_token = new Corpus2::Token("ZZ", PwrNlp::Whitespace::ManySpaces); + Corpus2::Tag t1(Corpus2::mask_t(0)); + Corpus2::Lexeme l1("aaa", t1); + Corpus2::Lexeme l2("bbb", t1); + the_token->add_lexeme(l1); + the_token->add_lexeme(l2); + s->append(the_token); + s->append(the_token->clone()); + } + + boost::shared_ptr<Corpus2::Sentence> s; + SentenceContext sc; + Corpus2::Tagset tagset; + + FunExecContext cx; + Position pos_one; + Position pos_minus_one; + Position nowhere; + Position begin; + Position end; + boost::shared_ptr<Function<Position> > pos_one_constant; + boost::shared_ptr<Function<Position> > pos_minus_one_constant; + boost::shared_ptr<Function<Position> > nowhere_constant; + boost::shared_ptr<Function<Position> > begin_constant; + boost::shared_ptr<Function<Position> > end_constant; + +}; + +BOOST_FIXTURE_TEST_CASE(rel_nowhere, PosPredFix) +{ + for(int offset = -2; offset < 3; offset++) + { + RelativePosition relpos(nowhere_constant, offset); + BOOST_CHECK_EQUAL( + Position::Nowhere, + relpos.apply(cx)->get_value()); + sc.advance(); + BOOST_CHECK_EQUAL( + Position::Nowhere, + relpos.apply(cx)->get_value()); + sc.advance(); + BOOST_CHECK_EQUAL( + Position::Nowhere, + relpos.apply(cx)->get_value()); + sc.goto_start(); + } +} + +BOOST_FIXTURE_TEST_CASE(rel_begin, PosPredFix) +{ + for(int offset = -2; offset < 3; offset++) + { + RelativePosition relpos(begin_constant, offset); + BOOST_CHECK_EQUAL( + offset, + cx.sentence_context().get_abs_position(*relpos.apply(cx))); + sc.advance(); + BOOST_CHECK_EQUAL( + offset, + cx.sentence_context().get_abs_position(*relpos.apply(cx))); + sc.advance(); + BOOST_CHECK_EQUAL( + offset, + cx.sentence_context().get_abs_position(*relpos.apply(cx))); + sc.goto_start(); + } +} + +BOOST_FIXTURE_TEST_CASE(rel_end, PosPredFix) +{ + for(int i = -2; i < 3; i++) + { + RelativePosition relpos(end_constant, i); + BOOST_CHECK_EQUAL( + sc.size() - 1 + i, + cx.sentence_context().get_abs_position(*relpos.apply(cx))); + sc.advance(); + BOOST_CHECK_EQUAL( + sc.size() - 1 + i, + cx.sentence_context().get_abs_position(*relpos.apply(cx))); + sc.advance(); + BOOST_CHECK_EQUAL( + sc.size() - 1 + i, + cx.sentence_context().get_abs_position(*relpos.apply(cx))); + sc.goto_start(); + } +} + +BOOST_FIXTURE_TEST_CASE(rel_normal_pos, PosPredFix) +{ + for(int offset = -2; offset < 3; offset++) + { + for(int pos = -2; pos < 3; pos++) + { + boost::shared_ptr<Constant<Position> > position(new Constant<Position>(Position(pos))); + RelativePosition relpos(position, offset); + BOOST_CHECK_EQUAL( + offset + pos, + relpos.apply(cx)->get_value()); + sc.advance(); + BOOST_CHECK_EQUAL( + offset + pos, + relpos.apply(cx)->get_value()); + sc.advance(); + BOOST_CHECK_EQUAL( + offset + pos, + relpos.apply(cx)->get_value()); + sc.goto_start(); + } + } +} + +//------ to_string test cases ------- + +BOOST_FIXTURE_TEST_CASE(relpos_to_string, PosPredFix) +{ + RelativePosition relpos(begin_constant, 4); + BOOST_CHECK_EQUAL("begin + 4", relpos.to_string(tagset)); + RelativePosition relpos_min1(pos_minus_one_constant, -1); + BOOST_CHECK_EQUAL("-1 - 1", relpos_min1.to_string(tagset)); + RelativePosition relpos_zero(end_constant, 0); + BOOST_CHECK_EQUAL("end + 0", relpos_zero.to_string(tagset)); +} + +BOOST_FIXTURE_TEST_CASE(relpos_to_raw_string, PosPredFix) +{ + RelativePosition relpos(nowhere_constant, 42); + BOOST_CHECK_EQUAL("nowhere + 42", relpos.to_raw_string()); + RelativePosition relpos_min1(pos_one_constant, -1); + BOOST_CHECK_EQUAL("1 - 1", relpos_min1.to_raw_string()); + RelativePosition relpos_zero(end_constant, 0); + BOOST_CHECK_EQUAL("end + 0", relpos_zero.to_raw_string()); +} +BOOST_AUTO_TEST_SUITE_END()