Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions inflection/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ file(MAKE_DIRECTORY ${INFLECTION_INCLUDE_ROOT})

include(dependICU)

add_library(xml2 INTERFACE IMPORTED GLOBAL)
set_target_properties(xml2 PROPERTIES IMPORTED_LIBNAME xml2)
target_include_directories(xml2 INTERFACE ${CMAKE_OSX_SYSROOT}/usr/include/libxml2)
find_package(LibXml2 REQUIRED)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a good improvement.


# Runs Unicode Inflection unit tests: "make check"
set(DYLD_LIBRARY_PATH ${ICU_LIB_DIRECTORY}:$<TARGET_FILE_DIR:inflection>)
Expand Down
23 changes: 19 additions & 4 deletions inflection/src/inflection/dialog/DisplayValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
namespace inflection::dialog {


DisplayValue::DisplayValue(const ::std::u16string& displayString, const ::std::map<SemanticFeature, ::std::u16string>& constraintMap)
DisplayValue::DisplayValue(
const ::std::u16string& displayString,
const ::std::map<SemanticFeature, ::std::u16string>& constraintMap
)
: super()
, displayString(displayString)
, constraintMap(constraintMap)
Expand All @@ -21,11 +24,23 @@ DisplayValue::DisplayValue(const ::std::u16string& value)
{
}

DisplayValue::DisplayValue(const SpeakableString& value, const SemanticFeature& speakFeature)
: DisplayValue(value.getPrint(), {})
DisplayValue::DisplayValue(
const SpeakableString& value,
const SemanticFeature& speakFeature
)
: DisplayValue(value, speakFeature, {})
{
}

DisplayValue::DisplayValue(
const SpeakableString& value,
const SemanticFeature& speakFeature,
const ::std::map<SemanticFeature, ::std::u16string>& constraintMap
)
: DisplayValue(value.getPrint(), constraintMap)
{
if (!value.speakEqualsPrint()) {
constraintMap.emplace(speakFeature, value.getSpeak());
this->constraintMap.emplace(speakFeature, value.getSpeak());
}
}

Expand Down
7 changes: 7 additions & 0 deletions inflection/src/inflection/dialog/DisplayValue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ class INFLECTION_CLASS_API inflection::dialog::DisplayValue
* @param speakFeature The speakFeature from the SemanticFeatureModel that represents the SemanticFeature for the speak information for a SpeakableString.
*/
DisplayValue(const SpeakableString& value, const SemanticFeature& speakFeature);
/**
* Construct a display value with a SpeakableString.
* @param value A SpeakableString
* @param speakFeature The speakFeature from the SemanticFeatureModel that represents the SemanticFeature for the speak information for a SpeakableString.
* @param constraintMap The intitial constraint map.
*/
DisplayValue(const SpeakableString& value, const SemanticFeature& speakFeature, const ::std::map<SemanticFeature, ::std::u16string>& constraintMap);
/**
* The destructor
*/
Expand Down
25 changes: 25 additions & 0 deletions inflection/src/inflection/dialog/InflectableStringConcept-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@

#include <inflection/dialog/InflectableStringConcept.hpp>
#include <inflection/dialog/SemanticFeatureConcept.h>
#include <inflection/dialog/SemanticFeature.hpp>
#include <inflection/dialog/SemanticUtils.hpp>
#include <inflection/dialog/SemanticFeatureModel.hpp>
#include <inflection/exception/ClassCastException.hpp>
#include <inflection/util/ULocale.hpp>
#include <inflection/util/TypeConversionUtils.hpp>
#include <inflection/util/Validate.hpp>
#include <inflection/npc.hpp>

INFLECTION_CAPI IDSemanticFeatureConcept* iinf_toSemanticFeatureConcept(IDInflectableStringConcept* thisObject, UErrorCode*)
{
Expand Down Expand Up @@ -47,6 +51,27 @@ iinf_create(const IDSemanticFeatureModel* model, const IDSpeakableString* value,
return nullptr;
}

INFLECTION_CAPI IDInflectableStringConcept*
iinf_createWithDefaults(const IDSemanticFeatureModel* model, const IDSpeakableString* value,
const IDDisplayValue_Constraint* defaultConstraints, int32_t defaultConstraintsLen, UErrorCode* status)
{
if (status != nullptr && U_SUCCESS(*status)) {
try {
auto defaultConstraintsMap(inflection::dialog::SemanticUtils::to_constraintMap(*npc((const inflection::dialog::SemanticFeatureModel*)model), defaultConstraints, defaultConstraintsLen));

return (IDInflectableStringConcept*) new ::inflection::dialog::InflectableStringConcept(
(const ::inflection::dialog::SemanticFeatureModel*)model,
*((const ::inflection::dialog::SpeakableString*)value),
defaultConstraintsMap
);
}
catch (const ::std::exception& e) {
inflection::util::TypeConversionUtils::convert(e, status);
}
}
return nullptr;
}

INFLECTION_CAPI void
iinf_destroy(IDInflectableStringConcept* thisObject)
{
Expand Down
23 changes: 17 additions & 6 deletions inflection/src/inflection/dialog/InflectableStringConcept.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,23 @@

namespace inflection::dialog {

InflectableStringConcept::InflectableStringConcept(const SemanticFeatureModel* model, const SpeakableString& value)

InflectableStringConcept::InflectableStringConcept(
const SemanticFeatureModel* model,
const SpeakableString& value
)
: InflectableStringConcept(model, value, {})
{
}

InflectableStringConcept::InflectableStringConcept(
const SemanticFeatureModel* model,
const SpeakableString& value,
const ::std::map<SemanticFeature, ::std::u16string>& initialConstraints
)
: super(model)
, value(value)
, defaultDisplayValue(value, *npc(super::getSpeakFeature()))
, defaultDisplayValue(value, *npc(super::getSpeakFeature()), initialConstraints)
{
}

Expand Down Expand Up @@ -49,6 +62,7 @@ SpeakableString* InflectableStringConcept::getFeatureValue(const SemanticFeature
return nullptr;
}


bool InflectableStringConcept::isExists() const
{
return getDisplayValue(false).has_value();
Expand All @@ -63,10 +77,7 @@ ::std::optional<DisplayValue> InflectableStringConcept::getDisplayValue(bool all
{
auto defaultDisplayFunction = npc(getModel())->getDefaultDisplayFunction();
if (defaultDisplayFunction != nullptr && !constraints.empty()) {
::std::map<SemanticFeature, ::std::u16string> constraintMap;
if (!value.speakEqualsPrint()) {
constraintMap.emplace(*npc(getSpeakFeature()), value.getSpeak());
}
::std::map<SemanticFeature, ::std::u16string> constraintMap = defaultDisplayValue.getConstraintMap();
SemanticFeatureModel_DisplayData displayData({DisplayValue(value.getPrint(), constraintMap)});
::std::unique_ptr<DisplayValue> returnVal(npc(defaultDisplayFunction)->getDisplayValue(displayData, constraints, allowInflectionGuess));
if (returnVal != nullptr) {
Expand Down
15 changes: 14 additions & 1 deletion inflection/src/inflection/dialog/InflectableStringConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include <inflection/dialog/SpeakableString.h>
#include <inflection/dialog/SemanticFeatureConcept.h>
#include <inflection/dialog/SemanticFeatureModel.h>

#include <inflection/dialog/DisplayValue.h>
/**
* An object that provides a way to format a word with additional grammatical category values or semantic features of a word for a given language.
*/
Expand Down Expand Up @@ -34,6 +34,19 @@ INFLECTION_CAPI IDInflectableStringConcept* iinf_toInflectableStringConcept(IDSe
* This is set to a failure when a failure has occurred during execution.
*/
INFLECTION_CAPI IDInflectableStringConcept* iinf_create(const IDSemanticFeatureModel* model, const IDSpeakableString* value, UErrorCode* status);
/**
* Constructs a concept given a semantic feature model and a speakable string
*
* @param model - The semantic feature model required to initialize the concept.
* @param value - The speakable string to convert to a concept
* @param defaultConstraints - The initial defaultConstraints to apply to the concept
* @param defaultConstraintsLen - The number of semantic features and values provided
* @param status Must be a valid pointer to an error code value,
* which must not indicate a failure before the function call.
* This is set to a failure when a failure has occurred during execution.
*/
INFLECTION_CAPI IDInflectableStringConcept* iinf_createWithDefaults(const IDSemanticFeatureModel* model, const IDSpeakableString* value,
const IDDisplayValue_Constraint* defaultConstraints, int32_t defaultConstraintsLen, UErrorCode* status);
/**
* Destructor
*/
Expand Down
9 changes: 9 additions & 0 deletions inflection/src/inflection/dialog/InflectableStringConcept.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ class INFLECTION_CLASS_API inflection::dialog::InflectableStringConcept
* @param value - The speakable string to convert to a concept
*/
InflectableStringConcept(const SemanticFeatureModel* model, const SpeakableString& value);

/**
* Constructs a concept given a semantic feature model and a speakable string
*
* @param model - The semantic feature model required to initialize the concept.
* @param value - The speakable string to convert to a concept
* @param initialConstraints - The initial constraints for the map.
*/
InflectableStringConcept(const SemanticFeatureModel* model, const SpeakableString& value, const std::map<SemanticFeature, ::std::u16string>& initialConstraints);
/**
* Copy constructor
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ ::std::optional<::std::u16string> FrGrammarSynthesizer_CountLookupFunction::dete
int64_t wordGrammemes = 0;
dictionary.getCombinedBinaryType(&wordGrammemes, word);
if ((wordGrammemes & properNounProperty) == properNounProperty) {
return {{}};
return std::u16string{};
}
if (checkInvariantNouns(word, wordGrammemes)) {
return GrammemeConstants::NUMBER_SINGULAR();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ ::std::optional<::std::u16string> HiGrammarSynthesizer_HiDisplayFunction::inflec

::std::optional<::std::vector<::std::u16string>> HiGrammarSynthesizer_HiDisplayFunction::inflectSignificantWords(const std::vector<::std::u16string> &words, const ::std::map<SemanticFeature, ::std::u16string> &constraints, bool enableInflectionGuess) const {
if (words.empty()) {
return {{}};
return std::vector<std::u16string>{};
}
const auto &dictionary = dictionaryInflector.getDictionary();
int64_t adpositionIndex = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ ::std::optional<::std::vector<::std::u16string>> PtGrammarSynthesizer_PtDisplayF

::std::optional<::std::vector<::std::u16string>> PtGrammarSynthesizer_PtDisplayFunction::inflectSignificantWords(const std::vector<::std::u16string> &words, const ::std::map<::inflection::dialog::SemanticFeature, ::std::u16string> &constraints, bool enableInflectionGuess) const {
switch (words.size()) {
case 0: return {{}};
case 0: return std::vector<std::u16string>{};
case 1: {
int64_t wordType = 0;
dictionary.getCombinedBinaryType(&wordType, words[0]);
Expand Down
2 changes: 1 addition & 1 deletion inflection/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ target_link_libraries(itest
PRIVATE
inflection
Catch2
xml2
LibXml2::LibXml2
marisa_objs
ICU::uc ICU::i18n
$<$<PLATFORM_ID:Darwin>:${PERFDATA_FRAMEWORK}>
Expand Down
7 changes: 7 additions & 0 deletions inflection/test/resources/inflection/dialog/inflection/es.xml
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,11 @@
<test><source definiteness="definite">álgebra añeja</source><result>el álgebra añeja</result></test> <!-- An exception to the gender rule. -->
<test><source definiteness="definite">añeja álgebra</source><result>la añeja álgebra</result></test>
<test><source>área</source><result withDemAdj="esta área"/></test>

<!-- New Tests for stating initial grammemes -->
<test><source definiteness="definite">cometa</source><initial gender="masculine"/><result number="singular" gender="masculine">el cometa</result></test>
<test><source definiteness="definite">cometa</source><initial gender="feminine"/><result number="singular" gender="feminine">la cometa</result></test>
<test><source definiteness="definite">QQQQ</source><initial gender="masculine" number="plural"/><result number="plural" gender="masculine">los QQQQ</result></test>
<test><source definiteness="definite">QQQQ</source><initial gender="feminine" number="plural"/><result number="plural" gender="feminine">las QQQQ</result></test>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


</inflectionTest>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include <inflection/util/ULocale.hpp>
#include <inflection/util/DelimitedStringIterator.hpp>
#include "util/StringContainer.hpp"

#include <utility>
using ::util::StringContainer;

static void checkForFailure(UErrorCode* status)
Expand Down Expand Up @@ -155,6 +155,73 @@ TEST_CASE("InflectableStringConceptTest-c#testExistsAPISpanish")
iinf_destroy(inflectableConcept);
}

TEST_CASE("InflectableStringConceptTest-c#testCreateWithDefaults")
{
auto error = U_ZERO_ERROR;
auto ccfp = ilccfp_getDefaultCommonConceptFactoryProvider(&error);
REQUIRE(U_SUCCESS(error));

const auto locale = ::inflection::util::LocaleUtils::SPANISH().getName().c_str();
auto ccf = ilccfp_getCommonConceptFactory(ccfp, locale, &error);
REQUIRE(U_SUCCESS(error));

auto model = iccf_getSemanticFeatureModel(ccf, &error);
REQUIRE(U_SUCCESS(error));

const std::u16string source = u"cometa";
auto sourceString = iss_create(source.c_str(), static_cast<int32_t>(source.size()), &error);
REQUIRE(U_SUCCESS(error));

IDDisplayValue_Constraint defaultConstraints[] = {
{u"gender", u"masculine"},
};

auto inflectableConcept = iinf_createWithDefaults(model,
sourceString,
defaultConstraints,
static_cast<int32_t>(std::ssize(defaultConstraints)),
&error);
iss_destroy(sourceString);
REQUIRE(U_SUCCESS(error));
REQUIRE(inflectableConcept != nullptr);

auto semanticConcept = iinf_toSemanticFeatureConcept(inflectableConcept, &error);
REQUIRE(U_SUCCESS(error));

isfc_putConstraintByName(semanticConcept, u"definiteness", u"definite", -1, &error);
REQUIRE(U_SUCCESS(error));

auto printedValue = isfc_toSpeakableStringCopy(semanticConcept, &error);
REQUIRE(U_SUCCESS(error));
util::StringContainer<IDSpeakableString, iss_getPrint> printedContainer(printedValue);
REQUIRE(printedContainer);
CHECK(printedContainer.value == u"el cometa");
iss_destroy(printedValue);

auto genderValue = isfc_createFeatureValueByNameCopy(semanticConcept, u"gender", &error);
REQUIRE(U_SUCCESS(error));
util::StringContainer<IDSpeakableString, iss_getPrint> genderContainer(genderValue);
REQUIRE(genderContainer);
CHECK(genderContainer.value == u"masculine");
iss_destroy(genderValue);

auto numberValue = isfc_createFeatureValueByNameCopy(semanticConcept, u"number", &error);
REQUIRE(U_SUCCESS(error));
util::StringContainer<IDSpeakableString, iss_getPrint> numberContainer(numberValue);
REQUIRE(numberContainer);
CHECK(numberContainer.value == u"singular");
iss_destroy(numberValue);

auto definitenessValue = isfc_createFeatureValueByNameCopy(semanticConcept, u"definiteness", &error);
REQUIRE(U_SUCCESS(error));
util::StringContainer<IDSpeakableString, iss_getPrint> definitenessContainer(definitenessValue);
REQUIRE(definitenessContainer);
CHECK(definitenessContainer.value == u"definite");
iss_destroy(definitenessValue);

iinf_destroy(inflectableConcept);
}

TEST_CASE("InflectableStringConceptTest-c#testSpanish")
{
auto error = U_ZERO_ERROR;
Expand Down
40 changes: 34 additions & 6 deletions inflection/test/src/inflection/dialog/InflectionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <inflection/dialog/InflectableStringConcept.hpp>
#include <inflection/dialog/SemanticFeatureModel.hpp>
#include <inflection/dialog/SemanticFeature.hpp>
#include <inflection/dialog/SpeakableString.hpp>
#include <inflection/dialog/LocalizedCommonConceptFactoryProvider.hpp>
#include <inflection/exception/XMLParseException.hpp>
Expand Down Expand Up @@ -35,9 +36,26 @@ static std::string getInfoStringForTestInput(const ::inflection::dialog::Semanti
return "locale=" + model.getLocale().getName() + (source.isEmpty() ? "" : std::string(" source=") + inflection::util::StringUtils::to_string(source.toString())) + " {" + constraintsStr + "}";
}

static void compareInflection(const ::inflection::dialog::SemanticFeatureModel& model, const ::inflection::dialog::SpeakableString& expected, const ::inflection::dialog::SpeakableString& source, const std::map<std::u16string, std::u16string>& constraints, const std::map<std::u16string, std::u16string>& resultAttributes)
static void compareInflection(const ::inflection::dialog::SemanticFeatureModel& model,
const ::inflection::dialog::SpeakableString& expected,
const ::inflection::dialog::SpeakableString& source,
const std::map<std::u16string, std::u16string>& constraints,
const std::map<std::u16string, std::u16string>& resultAttributes,
const std::map<std::u16string, std::u16string>& initialAttributes)
{
inflection::dialog::InflectableStringConcept inflectableConcept(&model, source);
std::map<inflection::dialog::SemanticFeature, ::std::u16string> intitialConstraints;
for(const auto& [attrKey, attrVal] : initialAttributes) {
auto featureName = model.getFeature(attrKey);
if (featureName == nullptr) {
FAIL_CHECK(model.getLocale().getName() + std::string(": feature name is not recognized: ") + inflection::util::StringUtils::to_string(attrKey));
}
const auto& boundedValues(npc(featureName)->getBoundedValues());
if (!boundedValues.empty() && boundedValues.find(attrVal) == boundedValues.end()) {
FAIL_CHECK(model.getLocale().getName() + std::string(": feature value \"") + inflection::util::StringUtils::to_string(attrVal) + "\" is not valid for feature \"" + inflection::util::StringUtils::to_string(attrKey) + "\"");
}
intitialConstraints[*featureName] = attrVal;
}
inflection::dialog::InflectableStringConcept inflectableConcept(&model, source, intitialConstraints);
for (const auto& constraint : constraints) {
auto featureName = model.getFeature(constraint.first);
if (featureName == nullptr) {
Expand Down Expand Up @@ -171,16 +189,26 @@ TEST_CASE("InflectionTest#testInflections")
if (xmlStrEqual(sourceNode->name, (const xmlChar *) "source") == 0) {
throw ::inflection::exception::XMLParseException(u"Expecting element <source>, got <" + ::inflection::util::StringUtils::to_u16string(std::string(reinterpret_cast<const char*>(sourceNode->name))) + u">");
}
xmlNodePtr resultNode = xmlNextElementSibling(sourceNode);
if (xmlStrEqual(resultNode->name, (const xmlChar *) "result") == 0) {
throw ::inflection::exception::XMLParseException(u"Expecting element <result>, got <" + ::inflection::util::StringUtils::to_u16string(std::string(reinterpret_cast<const char*>(resultNode->name))) + u">");

// optional initial child tag
curTestChild = xmlNextElementSibling(sourceNode);
xmlNodePtr initialNode = nullptr;
if(xmlStrEqual(curTestChild->name, (const xmlChar*) "initial") != 0) {
initialNode = curTestChild;
curTestChild = xmlNextElementSibling(curTestChild);
}

if (xmlStrEqual(curTestChild->name, (const xmlChar *) "result") == 0) {
throw ::inflection::exception::XMLParseException(u"Expecting element <result>, got <" + ::inflection::util::StringUtils::to_u16string(std::string(reinterpret_cast<const char*>(curTestChild->name))) + u">");
}
xmlNodePtr resultNode = curTestChild;
auto sourceConstraints(XMLUtils::getAttributes(sourceNode));
auto resultAttributes(XMLUtils::getAttributes(resultNode));
auto initialAttributes(XMLUtils::getAttributes(initialNode));
auto sourceString(getSpeakableString(sourceNode));
auto resultString(getSpeakableString(resultNode));

compareInflection(*npc(model), resultString, sourceString, sourceConstraints, resultAttributes);
compareInflection(*npc(model), resultString, sourceString, sourceConstraints, resultAttributes, initialAttributes);
numTests++;
}
xmlFreeDoc(xmlDoc);
Expand Down
Loading
Loading