Package simplenlg.syntax.english

Source Code of simplenlg.syntax.english.ClauseHelper

/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is "Simplenlg".
*
* The Initial Developer of the Original Code is Ehud Reiter, Albert Gatt and Dave Westwater.
* Portions created by Ehud Reiter, Albert Gatt and Dave Westwater are Copyright (C) 2010-11 The University of Aberdeen. All Rights Reserved.
*
* Contributor(s): Ehud Reiter, Albert Gatt, Dave Wewstwater, Roman Kutlak, Margaret Mitchell.
*/
package simplenlg.syntax.english;

import java.util.List;

import simplenlg.features.ClauseStatus;
import simplenlg.features.DiscourseFunction;
import simplenlg.features.Feature;
import simplenlg.features.Form;
import simplenlg.features.InternalFeature;
import simplenlg.features.InterrogativeType;
import simplenlg.features.NumberAgreement;
import simplenlg.features.Person;
import simplenlg.features.Tense;
import simplenlg.framework.CoordinatedPhraseElement;
import simplenlg.framework.LexicalCategory;
import simplenlg.framework.ListElement;
import simplenlg.framework.NLGElement;
import simplenlg.framework.NLGFactory;
import simplenlg.framework.PhraseCategory;
import simplenlg.framework.PhraseElement;
import simplenlg.phrasespec.VPPhraseSpec;

/**
* <p>
* This is a helper class containing the main methods for realising the syntax
* of clauses. It is used exclusively by the <code>SyntaxProcessor</code>.
* </p>
*
* @author D. Westwater, University of Aberdeen.
* @version 4.0
*
*/
abstract class ClauseHelper {

  /**
   * The main method for controlling the syntax realisation of clauses.
   *
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that called this
   *            method.
   * @param phrase
   *            the <code>PhraseElement</code> representation of the clause.
   * @return the <code>NLGElement</code> representing the realised clause.
   */
  static NLGElement realise(SyntaxProcessor parent, PhraseElement phrase) {
    ListElement realisedElement = null;
    NLGFactory phraseFactory = phrase.getFactory();
    NLGElement splitVerb = null;
    boolean interrogObj = false;

    if (phrase != null) {
      realisedElement = new ListElement();
      NLGElement verbElement = phrase
          .getFeatureAsElement(InternalFeature.VERB_PHRASE);

      if (verbElement == null) {
        verbElement = phrase.getHead();
      }

      checkSubjectNumberPerson(phrase, verbElement);
      checkDiscourseFunction(phrase);
      copyFrontModifiers(phrase, verbElement);
      addComplementiser(phrase, parent, realisedElement);
      addCuePhrase(phrase, parent, realisedElement);

      if (phrase.hasFeature(Feature.INTERROGATIVE_TYPE)) {
        Object inter = phrase.getFeature(Feature.INTERROGATIVE_TYPE);
        interrogObj = InterrogativeType.WHAT_OBJECT.equals(inter)
            || InterrogativeType.WHO_OBJECT.equals(inter);
        splitVerb = realiseInterrogative(phrase, parent,
            realisedElement, phraseFactory, verbElement);
      } else {
        PhraseHelper
            .realiseList(
                parent,
                realisedElement,
                phrase
                    .getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS),
                DiscourseFunction.FRONT_MODIFIER);
      }

      addSubjectsToFront(phrase, parent, realisedElement, splitVerb);

      NLGElement passiveSplitVerb = addPassiveComplementsNumberPerson(
          phrase, parent, realisedElement, verbElement);

      if (passiveSplitVerb != null) {
        splitVerb = passiveSplitVerb;
      }

      // realise verb needs to know if clause is object interrogative
      realiseVerb(phrase, parent, realisedElement, splitVerb,
          verbElement, interrogObj);
      addPassiveSubjects(phrase, parent, realisedElement, phraseFactory);
      addInterrogativeFrontModifiers(phrase, parent, realisedElement);
      addEndingTo(phrase, parent, realisedElement, phraseFactory);
    }
    return realisedElement;
  }

  /**
   * Adds <em>to</em> to the end of interrogatives concerning indirect
   * objects. For example, <em>who did John give the flower <b>to</b></em>.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   */
  private static void addEndingTo(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement,
      NLGFactory phraseFactory) {

    if (InterrogativeType.WHO_INDIRECT_OBJECT.equals(phrase
        .getFeature(Feature.INTERROGATIVE_TYPE))) {
      NLGElement word = phraseFactory.createWord(
          "to", LexicalCategory.PREPOSITION); //$NON-NLS-1$
      realisedElement.addComponent(parent.realise(word));
    }
  }

  /**
   * Adds the front modifiers to the end of the clause when dealing with
   * interrogatives.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   */
  private static void addInterrogativeFrontModifiers(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement) {
    NLGElement currentElement = null;
    if (phrase.hasFeature(Feature.INTERROGATIVE_TYPE)) {
      for (NLGElement subject : phrase
          .getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS)) {
        currentElement = parent.realise(subject);
        if (currentElement != null) {
          currentElement.setFeature(
              InternalFeature.DISCOURSE_FUNCTION,
              DiscourseFunction.FRONT_MODIFIER);

          realisedElement.addComponent(currentElement);
        }
      }
    }
  }

  /**
   * Realises the subjects of a passive clause.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   */
  private static void addPassiveSubjects(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement,
      NLGFactory phraseFactory) {
    NLGElement currentElement = null;

    if (phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()) {
      List<NLGElement> allSubjects = phrase
          .getFeatureAsElementList(InternalFeature.SUBJECTS);

      if (allSubjects.size() > 0
          || phrase.hasFeature(Feature.INTERROGATIVE_TYPE)) {
        realisedElement.addComponent(parent.realise(phraseFactory
            .createPrepositionPhrase("by"))); //$NON-NLS-1$
      }

      for (NLGElement subject : allSubjects) {

        subject.setFeature(Feature.PASSIVE, true);
        if (subject.isA(PhraseCategory.NOUN_PHRASE)
            || subject instanceof CoordinatedPhraseElement) {
          currentElement = parent.realise(subject);
          if (currentElement != null) {
            currentElement.setFeature(
                InternalFeature.DISCOURSE_FUNCTION,
                DiscourseFunction.SUBJECT);
            realisedElement.addComponent(currentElement);
          }
        }
      }
    }
  }

  /**
   * Realises the verb part of the clause.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param splitVerb
   *            an <code>NLGElement</code> representing the subjects that
   *            should split the verb
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   * @param whObj
   *            whether the VP is part of an object WH-interrogative
   */
  private static void realiseVerb(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement,
      NLGElement splitVerb, NLGElement verbElement, boolean whObj) {

    setVerbFeatures(phrase, verbElement);

    NLGElement currentElement = parent.realise(verbElement);
    if (currentElement != null) {
      if (splitVerb == null) {
        currentElement.setFeature(InternalFeature.DISCOURSE_FUNCTION,
            DiscourseFunction.VERB_PHRASE);

        realisedElement.addComponent(currentElement);

      } else {
        if (currentElement instanceof ListElement) {
          List<NLGElement> children = currentElement.getChildren();
          currentElement = children.get(0);
          currentElement.setFeature(
              InternalFeature.DISCOURSE_FUNCTION,
              DiscourseFunction.VERB_PHRASE);
          realisedElement.addComponent(currentElement);
          realisedElement.addComponent(splitVerb);

          for (int eachChild = 1; eachChild < children.size(); eachChild++) {
            currentElement = children.get(eachChild);
            currentElement.setFeature(
                InternalFeature.DISCOURSE_FUNCTION,
                DiscourseFunction.VERB_PHRASE);
            realisedElement.addComponent(currentElement);
          }
        } else {
          currentElement.setFeature(
              InternalFeature.DISCOURSE_FUNCTION,
              DiscourseFunction.VERB_PHRASE);

          if (whObj) {
            realisedElement.addComponent(currentElement);
            realisedElement.addComponent(splitVerb);
          } else {
            realisedElement.addComponent(splitVerb);
            realisedElement.addComponent(currentElement);
          }
        }
      }
    }
  }

  /**
   * Ensures that the verb inherits the features from the clause.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   */
  private static void setVerbFeatures(PhraseElement phrase,
      NLGElement verbElement) {
    // this routine copies features from the clause to the VP.
    // it is disabled, as this copying is now done automatically
    // when features are set in SPhraseSpec
    // if (verbElement != null) {
    // verbElement.setFeature(Feature.INTERROGATIVE_TYPE, phrase
    // .getFeature(Feature.INTERROGATIVE_TYPE));
    // verbElement.setFeature(InternalFeature.COMPLEMENTS, phrase
    // .getFeature(InternalFeature.COMPLEMENTS));
    // verbElement.setFeature(InternalFeature.PREMODIFIERS, phrase
    // .getFeature(InternalFeature.PREMODIFIERS));
    // verbElement.setFeature(Feature.FORM, phrase
    // .getFeature(Feature.FORM));
    // verbElement.setFeature(Feature.MODAL, phrase
    // .getFeature(Feature.MODAL));
    // verbElement.setNegated(phrase.isNegated());
    // verbElement.setFeature(Feature.PASSIVE, phrase
    // .getFeature(Feature.PASSIVE));
    // verbElement.setFeature(Feature.PERFECT, phrase
    // .getFeature(Feature.PERFECT));
    // verbElement.setFeature(Feature.PROGRESSIVE, phrase
    // .getFeature(Feature.PROGRESSIVE));
    // verbElement.setTense(phrase.getTense());
    // verbElement.setFeature(Feature.FORM, phrase
    // .getFeature(Feature.FORM));
    // verbElement.setFeature(LexicalFeature.GENDER, phrase
    // .getFeature(LexicalFeature.GENDER));
    // }
  }

  /**
   * Realises the complements of passive clauses; also sets number, person for
   * passive
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   */
  private static NLGElement addPassiveComplementsNumberPerson(
      PhraseElement phrase, SyntaxProcessor parent,
      ListElement realisedElement, NLGElement verbElement) {
    Object passiveNumber = null;
    Object passivePerson = null;
    NLGElement currentElement = null;
    NLGElement splitVerb = null;
    NLGElement verbPhrase = phrase
        .getFeatureAsElement(InternalFeature.VERB_PHRASE);

    if (phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()
        && verbPhrase != null
        && !InterrogativeType.WHAT_OBJECT.equals(phrase
            .getFeature(Feature.INTERROGATIVE_TYPE))) {

      // complements of a clause are stored in the VPPhraseSpec
      for (NLGElement subject : verbPhrase
          .getFeatureAsElementList(InternalFeature.COMPLEMENTS)) {

        // AG: complement needn't be an NP
        // subject.isA(PhraseCategory.NOUN_PHRASE) &&
        if (DiscourseFunction.OBJECT.equals(subject
            .getFeature(InternalFeature.DISCOURSE_FUNCTION))) {
          subject.setFeature(Feature.PASSIVE, true);
          currentElement = parent.realise(subject);

          if (currentElement != null) {
            currentElement.setFeature(
                InternalFeature.DISCOURSE_FUNCTION,
                DiscourseFunction.OBJECT);

            if (phrase.hasFeature(Feature.INTERROGATIVE_TYPE)) {
              splitVerb = currentElement;
            } else {
              realisedElement.addComponent(currentElement);
            }
          }

          if (passiveNumber == null) {
            passiveNumber = subject.getFeature(Feature.NUMBER);
          } else {
            passiveNumber = NumberAgreement.PLURAL;
          }

          if (Person.FIRST.equals(subject.getFeature(Feature.PERSON))) {
            passivePerson = Person.FIRST;
          } else if (Person.SECOND.equals(subject
              .getFeature(Feature.PERSON))
              && !Person.FIRST.equals(passivePerson)) {
            passivePerson = Person.SECOND;
          } else if (passivePerson == null) {
            passivePerson = Person.THIRD;
          }

          if (Form.GERUND.equals(phrase.getFeature(Feature.FORM))
              && !phrase.getFeatureAsBoolean(
                  Feature.SUPPRESS_GENITIVE_IN_GERUND)
                  .booleanValue()) {
            subject.setFeature(Feature.POSSESSIVE, true);
          }
        }
      }
    }

    if (verbElement != null) {
      if (passivePerson != null) {
        verbElement.setFeature(Feature.PERSON, passivePerson);
        // below commented out. for non-passive, number and person set
        // by checkSubjectNumberPerson
        // } else {
        // verbElement.setFeature(Feature.PERSON, phrase
        // .getFeature(Feature.PERSON));
      }
      if (passiveNumber != null) {
        verbElement.setFeature(Feature.NUMBER, passiveNumber);
      }
    }
    return splitVerb;
  }

  /**
   * Adds the subjects to the beginning of the clause unless the clause is
   * infinitive, imperative or passive, or the subjects split the verb.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param splitVerb
   *            an <code>NLGElement</code> representing the subjects that
   *            should split the verb
   */
  private static void addSubjectsToFront(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement,
      NLGElement splitVerb) {
    if (!Form.INFINITIVE.equals(phrase.getFeature(Feature.FORM))
        && !Form.IMPERATIVE.equals(phrase.getFeature(Feature.FORM))
        && !phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()
        && splitVerb == null) {
      realisedElement.addComponents(realiseSubjects(phrase, parent)
          .getChildren());
    }
  }

  /**
   * Realises the subjects for the clause.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   */
  private static ListElement realiseSubjects(PhraseElement phrase,
      SyntaxProcessor parent) {

    NLGElement currentElement = null;
    ListElement realisedElement = new ListElement();

    for (NLGElement subject : phrase
        .getFeatureAsElementList(InternalFeature.SUBJECTS)) {

      subject.setFeature(InternalFeature.DISCOURSE_FUNCTION,
          DiscourseFunction.SUBJECT);
      if (Form.GERUND.equals(phrase.getFeature(Feature.FORM))
          && !phrase.getFeatureAsBoolean(
              Feature.SUPPRESS_GENITIVE_IN_GERUND).booleanValue()) {
        subject.setFeature(Feature.POSSESSIVE, true);
      }
      currentElement = parent.realise(subject);
      if (currentElement != null) {
        realisedElement.addComponent(currentElement);
      }
    }
    return realisedElement;
  }

  /**
   * This is the main controlling method for handling interrogative clauses.
   * The actual steps taken are dependent on the type of question being asked.
   * The method also determines if there is a subject that will split the verb
   * group of the clause. For example, the clause
   * <em>the man <b>should give</b> the woman the flower</em> has the verb
   * group indicated in <b>bold</b>. The phrase is rearranged as yes/no
   * question as
   * <em><b>should</b> the man <b>give</b> the woman the flower</em> with the
   * subject <em>the man</em> splitting the verb group.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   * @return an <code>NLGElement</code> representing a subject that should
   *         split the verb
   */
  private static NLGElement realiseInterrogative(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement,
      NLGFactory phraseFactory, NLGElement verbElement) {
    NLGElement splitVerb = null;

    if (phrase.getParent() != null) {
      phrase.getParent().setFeature(InternalFeature.INTERROGATIVE, true);
    }

    Object type = phrase.getFeature(Feature.INTERROGATIVE_TYPE);

    if (type instanceof InterrogativeType) {
      switch ((InterrogativeType) type) {
      case YES_NO:
        splitVerb = realiseYesNo(phrase, parent, verbElement,
            phraseFactory, realisedElement);
        break;

      case WHO_SUBJECT:
        realiseInterrogativeKeyWord(
            "who", LexicalCategory.PRONOUN, parent, realisedElement, //$NON-NLS-1$
            phraseFactory);
        phrase.removeFeature(InternalFeature.SUBJECTS);
        break;

      case WHAT_SUBJECT:
        realiseInterrogativeKeyWord("what", LexicalCategory.PRONOUN, parent, realisedElement, //$NON-NLS-1$
            phraseFactory);
        phrase.removeFeature(InternalFeature.SUBJECTS);
        break;

      case HOW:
      case WHY:
      case WHERE:
        realiseInterrogativeKeyWord(type.toString().toLowerCase(), LexicalCategory.PRONOUN,
            parent, realisedElement, //$NON-NLS-1$
            phraseFactory);
        splitVerb = realiseYesNo(phrase, parent, verbElement,
            phraseFactory, realisedElement);
        break;

      case HOW_MANY:
        realiseInterrogativeKeyWord("how", LexicalCategory.PRONOUN, parent, realisedElement, //$NON-NLS-1$
            phraseFactory);
        realiseInterrogativeKeyWord("many", LexicalCategory.ADVERB, parent, realisedElement, //$NON-NLS-1$
            phraseFactory);
        break;

      case WHO_OBJECT:
      case WHO_INDIRECT_OBJECT:
        //        realiseInterrogativeKeyWord("who", parent, realisedElement, //$NON-NLS-1$
        // phraseFactory);
        splitVerb = realiseObjectWHInterrogative("who", phrase, parent,
            realisedElement, phraseFactory);

        // if (!hasAuxiliary(phrase)) {
        // addDoAuxiliary(phrase, parent, phraseFactory,
        // realisedElement);
        // }
        break;

      case WHAT_OBJECT:
        splitVerb = realiseObjectWHInterrogative("what", phrase,
            parent, realisedElement, phraseFactory);
        break;

      default:
        break;
      }
    }

    return splitVerb;
  }

  /*
   * Check if a sentence has an auxiliary (needed to relise questions
   * correctly)
   */
  private static boolean hasAuxiliary(PhraseElement phrase) {
    return phrase.hasFeature(Feature.MODAL)
        || phrase.getFeatureAsBoolean(Feature.PERFECT).booleanValue()
        || phrase.getFeatureAsBoolean(Feature.PROGRESSIVE)
            .booleanValue()
        || Tense.FUTURE.equals(phrase.getFeature(Feature.TENSE));
  }

  /**
   * Controls the realisation of <em>wh</em> object questions.
   *
   * @param keyword
   *            the wh word
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   * @param subjects
   *            the <code>List</code> of subjects in the clause.
   * @return an <code>NLGElement</code> representing a subject that should
   *         split the verb
   */
  private static NLGElement realiseObjectWHInterrogative(String keyword,
      PhraseElement phrase, SyntaxProcessor parent,
      ListElement realisedElement, NLGFactory phraseFactory) {
    NLGElement splitVerb = null;
    realiseInterrogativeKeyWord(keyword, LexicalCategory.PRONOUN, parent, realisedElement, //$NON-NLS-1$
        phraseFactory);

    // if (!Tense.FUTURE.equals(phrase.getFeature(Feature.TENSE)) &&
    // !copular) {
    if (!hasAuxiliary(phrase) && !VerbPhraseHelper.isCopular(phrase)) {
      addDoAuxiliary(phrase, parent, phraseFactory, realisedElement);

    } else if (!phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()) {
      splitVerb = realiseSubjects(phrase, parent);
    }

    return splitVerb;
  }

  /**
   * Adds a <em>do</em> verb to the realisation of this clause.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   */
  private static void addDoAuxiliary(PhraseElement phrase,
      SyntaxProcessor parent, NLGFactory phraseFactory,
      ListElement realisedElement) {

    PhraseElement doPhrase = phraseFactory.createVerbPhrase("do"); //$NON-NLS-1$
    doPhrase.setFeature(Feature.TENSE, phrase.getFeature(Feature.TENSE));
    doPhrase.setFeature(Feature.PERSON, phrase.getFeature(Feature.PERSON));
    doPhrase.setFeature(Feature.NUMBER, phrase.getFeature(Feature.NUMBER));
    realisedElement.addComponent(parent.realise(doPhrase));
  }

  /**
   * Realises the key word of the interrogative. For example, <em>who</em>,
   * <em>what</em>
   *
   * @param keyWord
   *            the key word of the interrogative.
   * @param cat
   *            the category (usually pronoun, but not in the case of
   *            "how many")
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   */
  private static void realiseInterrogativeKeyWord(String keyWord,
      LexicalCategory cat, SyntaxProcessor parent,
      ListElement realisedElement, NLGFactory phraseFactory) {

    if (keyWord != null) {
      NLGElement question = phraseFactory.createWord(keyWord, cat);
      NLGElement currentElement = parent.realise(question);

      if (currentElement != null) {
        realisedElement.addComponent(currentElement);
      }
    }
  }

  /**
   * Performs the realisation for YES/NO types of questions. This may involve
   * adding an optional <em>do</em> auxiliary verb to the beginning of the
   * clause. The method also determines if there is a subject that will split
   * the verb group of the clause. For example, the clause
   * <em>the man <b>should give</b> the woman the flower</em> has the verb
   * group indicated in <b>bold</b>. The phrase is rearranged as yes/no
   * question as
   * <em><b>should</b> the man <b>give</b> the woman the flower</em> with the
   * subject <em>the man</em> splitting the verb group.
   *
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   * @param phraseFactory
   *            the phrase factory to be used.
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   * @param subjects
   *            the <code>List</code> of subjects in the clause.
   * @return an <code>NLGElement</code> representing a subject that should
   *         split the verb
   */
  private static NLGElement realiseYesNo(PhraseElement phrase,
      SyntaxProcessor parent, NLGElement verbElement,
      NLGFactory phraseFactory, ListElement realisedElement) {

    NLGElement splitVerb = null;

    if (!(verbElement instanceof VPPhraseSpec && VerbPhraseHelper
        .isCopular(((VPPhraseSpec) verbElement).getVerb()))
        && !phrase.getFeatureAsBoolean(Feature.PROGRESSIVE)
            .booleanValue()
        && !phrase.hasFeature(Feature.MODAL)
        && !Tense.FUTURE.equals(phrase.getFeature(Feature.TENSE))
        && !phrase.getFeatureAsBoolean(Feature.NEGATED).booleanValue()
        && !phrase.getFeatureAsBoolean(Feature.PASSIVE).booleanValue()) {
      addDoAuxiliary(phrase, parent, phraseFactory, realisedElement);
    } else {
      splitVerb = realiseSubjects(phrase, parent);
    }
    return splitVerb;
  }

  /**
   * Realises the cue phrase for the clause if it exists.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   */
  private static void addCuePhrase(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement) {

    NLGElement currentElement = parent.realise(phrase
        .getFeatureAsElement(Feature.CUE_PHRASE));

    if (currentElement != null) {
      currentElement.setFeature(InternalFeature.DISCOURSE_FUNCTION,
          DiscourseFunction.CUE_PHRASE);
      realisedElement.addComponent(currentElement);
    }
  }

  /**
   * Checks to see if this clause is a subordinate clause. If it is then the
   * complementiser is added as a component to the realised element
   * <b>unless</b> the complementiser has been suppressed.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param parent
   *            the parent <code>SyntaxProcessor</code> that will do the
   *            realisation of the complementiser.
   * @param realisedElement
   *            the current realisation of the clause.
   */
  private static void addComplementiser(PhraseElement phrase,
      SyntaxProcessor parent, ListElement realisedElement) {

    NLGElement currentElement;

    if (ClauseStatus.SUBORDINATE.equals(phrase
        .getFeature(InternalFeature.CLAUSE_STATUS))
        && !phrase
            .getFeatureAsBoolean(Feature.SUPRESSED_COMPLEMENTISER)
            .booleanValue()) {

      currentElement = parent.realise(phrase
          .getFeatureAsElement(Feature.COMPLEMENTISER));

      if (currentElement != null) {
        realisedElement.addComponent(currentElement);
      }
    }
  }

  /**
   * Copies the front modifiers of the clause to the list of post-modifiers of
   * the verb only if the phrase has infinitive form.
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   */
  private static void copyFrontModifiers(PhraseElement phrase,
      NLGElement verbElement) {
    List<NLGElement> frontModifiers = phrase
        .getFeatureAsElementList(InternalFeature.FRONT_MODIFIERS);
    Object clauseForm = phrase.getFeature(Feature.FORM);

    // bug fix by Chris Howell (Agfa) -- do not overwrite existing post-mods
    // in the VP
    if (verbElement != null) {
      List<NLGElement> phrasePostModifiers = phrase
          .getFeatureAsElementList(InternalFeature.POSTMODIFIERS);

      if (verbElement instanceof PhraseElement) {
        List<NLGElement> verbPostModifiers = verbElement
            .getFeatureAsElementList(InternalFeature.POSTMODIFIERS);

        for (NLGElement eachModifier : phrasePostModifiers) {

          // need to check that VP doesn't already contain the
          // post-modifier
          // this only happens if the phrase has already been realised
          // and later modified, with realiser called again. In that
          // case, postmods will be copied over twice
          if (!verbPostModifiers.contains(eachModifier)) {
            ((PhraseElement) verbElement)
                .addPostModifier(eachModifier);
          }
        }
      }
    }

    // if (verbElement != null) {
    // verbElement.setFeature(InternalFeature.POSTMODIFIERS, phrase
    // .getFeature(InternalFeature.POSTMODIFIERS));
    // }

    if (Form.INFINITIVE.equals(clauseForm)) {
      phrase.setFeature(Feature.SUPRESSED_COMPLEMENTISER, true);

      for (NLGElement eachModifier : frontModifiers) {
        if (verbElement instanceof PhraseElement) {
          ((PhraseElement) verbElement).addPostModifier(eachModifier);
        }
      }
      phrase.removeFeature(InternalFeature.FRONT_MODIFIERS);
      if (verbElement != null) {
        verbElement.setFeature(InternalFeature.NON_MORPH, true);
      }
    }
  }

  /**
   * Checks the discourse function of the clause and alters the form of the
   * clause as necessary. The following algorithm is used: <br>
   *
   * <pre>
   * If the clause represents a direct or indirect object then
   *      If form is currently Imperative then
   *           Set form to Infinitive
   *           Suppress the complementiser
   *      If form is currently Gerund and there are no subjects
   *         Suppress the complementiser
   * If the clause represents a subject then
   *      Set the form to be Gerund
   *      Suppress the complementiser
   * </pre>
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   */
  private static void checkDiscourseFunction(PhraseElement phrase) {
    List<NLGElement> subjects = phrase
        .getFeatureAsElementList(InternalFeature.SUBJECTS);
    Object clauseForm = phrase.getFeature(Feature.FORM);
    Object discourseValue = phrase
        .getFeature(InternalFeature.DISCOURSE_FUNCTION);

    if (DiscourseFunction.OBJECT.equals(discourseValue)
        || DiscourseFunction.INDIRECT_OBJECT.equals(discourseValue)) {

      if (Form.IMPERATIVE.equals(clauseForm)) {
        phrase.setFeature(Feature.SUPRESSED_COMPLEMENTISER, true);
        phrase.setFeature(Feature.FORM, Form.INFINITIVE);
      } else if (Form.GERUND.equals(clauseForm) && subjects.size() == 0) {
        phrase.setFeature(Feature.SUPRESSED_COMPLEMENTISER, true);
      }
    } else if (DiscourseFunction.SUBJECT.equals(discourseValue)) {
      phrase.setFeature(Feature.FORM, Form.GERUND);
      phrase.setFeature(Feature.SUPRESSED_COMPLEMENTISER, true);
    }
  }

  /**
   * Checks the subjects of the phrase to determine if there is more than one
   * subject. This ensures that the verb phrase is correctly set. Also set
   * person correctly
   *
   * @param phrase
   *            the <code>PhraseElement</code> representing this clause.
   * @param verbElement
   *            the <code>NLGElement</code> representing the verb phrase for
   *            this clause.
   */
  private static void checkSubjectNumberPerson(PhraseElement phrase,
      NLGElement verbElement) {
    NLGElement currentElement = null;
    List<NLGElement> subjects = phrase
        .getFeatureAsElementList(InternalFeature.SUBJECTS);
    boolean pluralSubjects = false;
    Person person = null;

    if (subjects != null) {
      switch (subjects.size()) {
      case 0:
        break;

      case 1:
        currentElement = subjects.get(0);
        // coordinated NP with "and" are plural (not coordinated NP with
        // "or")
        if (currentElement instanceof CoordinatedPhraseElement
            && ((CoordinatedPhraseElement) currentElement)
                .checkIfPlural())
          pluralSubjects = true;
        else if (currentElement.getFeature(Feature.NUMBER) == NumberAgreement.PLURAL)
          pluralSubjects = true;
        else if (currentElement.isA(PhraseCategory.NOUN_PHRASE)) {
          NLGElement currentHead = currentElement
              .getFeatureAsElement(InternalFeature.HEAD);
          person = (Person) currentElement.getFeature(Feature.PERSON);
          if ((currentHead.getFeature(Feature.NUMBER) == NumberAgreement.PLURAL))
            pluralSubjects = true;
          else if (currentHead instanceof ListElement) {
            pluralSubjects = true;
            /*
             * } else if (currentElement instanceof
             * CoordinatedPhraseElement &&
             * "and".equals(currentElement.getFeatureAsString(
             * //$NON-NLS-1$ Feature.CONJUNCTION))) { pluralSubjects
             * = true;
             */
          }
        }
        break;

      default:
        pluralSubjects = true;
        break;
      }
    }
    if (verbElement != null) {
      verbElement.setFeature(Feature.NUMBER,
          pluralSubjects ? NumberAgreement.PLURAL : phrase
              .getFeature(Feature.NUMBER));
      if (person != null)
        verbElement.setFeature(Feature.PERSON, person);
    }
  }
}
TOP

Related Classes of simplenlg.syntax.english.ClauseHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.