/*!
 * \param[in,out] sel    Selection element to initialize.
 * \param[in]     method Selection method to set.
 * \param[in]     scanner Scanner data structure.
 *
 * Makes a copy of \p method and stores it in \p sel->u.expr.method,
 * and calls _gmx_selelem_init_method_params();
 */
void
_gmx_selelem_set_method(const gmx::SelectionTreeElementPointer &sel,
                        gmx_ana_selmethod_t                    *method,
                        yyscan_t                                scanner)
{
    _gmx_selelem_set_vtype(sel, method->type);
    sel->setName(method->name);
    snew(sel->u.expr.method, 1);
    memcpy(sel->u.expr.method, method, sizeof(gmx_ana_selmethod_t));
    _gmx_selelem_init_method_params(sel, scanner);
}
/*!
 * \param         sel   Selection to append (can be NULL, in which
 *   case nothing is done).
 * \param         last  Last selection, or NULL if not present or not known.
 * \param         scanner  Scanner data structure.
 * \returns       The last selection after the append.
 *
 * Appends \p sel after the last root element, and returns either \p sel
 * (if it was non-NULL) or the last element (if \p sel was NULL).
 */
SelectionTreeElementPointer
_gmx_sel_append_selection(const gmx::SelectionTreeElementPointer &sel,
                          gmx::SelectionTreeElementPointer        last,
                          yyscan_t                                scanner)
{
    gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);

    /* Append sel after last, or the last element of sc if last is NULL */
    if (last)
    {
        last->next = sel;
    }
    else
    {
        if (sc->root)
        {
            last = sc->root;
            while (last->next)
            {
                last = last->next;
            }
            last->next = sel;
        }
        else
        {
            sc->root = sel;
        }
    }
    /* Initialize a selection object if necessary */
    if (sel)
    {
        last = sel;
        /* Add the new selection to the collection if it is not a variable. */
        if (sel->child->type != SEL_SUBEXPR)
        {
            gmx::SelectionDataPointer selPtr(
                    new gmx::internal::SelectionData(
                            sel.get(), _gmx_sel_lexer_pselstr(scanner)));
            sc->sel.push_back(gmx::move(selPtr));
        }
    }
    /* Clear the selection string now that we've saved it */
    _gmx_sel_lexer_clear_pselstr(scanner);
    return last;
}
/*!
 * \param[in,out] sel  Value of the variable.
 * \returns       The created selection element that references \p sel.
 *
 * The reference count of \p sel is updated, but no other modifications are
 * made.
 */
SelectionTreeElementPointer
_gmx_sel_init_variable_ref(const gmx::SelectionTreeElementPointer &sel)
{
    SelectionTreeElementPointer ref;

    if (sel->v.type == POS_VALUE && sel->type == SEL_CONST)
    {
        ref = sel;
    }
    else
    {
        ref.reset(new SelectionTreeElement(SEL_SUBEXPRREF));
        _gmx_selelem_set_vtype(ref, sel->v.type);
        ref->setName(sel->name());
        ref->child = sel;
    }
    return ref;
}
Esempio n. 4
0
/*!
 * \param     pparams List of parameters from the selection parser.
 * \param[in] nparam  Number of parameters in \p params.
 * \param     params  Array of parameters to parse.
 * \param     root    Selection element to which child expressions are added.
 * \param[in] scanner Scanner data structure.
 *
 * Initializes the \p params array based on the parameters in \p pparams.
 * See the documentation of \c gmx_ana_selparam_t for different options
 * available for parsing.
 *
 * The list \p pparams and any associated values are freed after the parameters
 * have been processed, no matter is there was an error or not.
 */
void
_gmx_sel_parse_params(const gmx::SelectionParserParameterList &pparams,
                      int nparam, gmx_ana_selparam_t *params,
                      const gmx::SelectionTreeElementPointer &root,
                      void *scanner)
{
    ExceptionInitializer errors("");
    /* Check that the value pointers of SPAR_VARNUM parameters are NULL and
     * that they are not NULL for other parameters */
    for (int i = 0; i < nparam; ++i)
    {
        if (params[i].val.type != POS_VALUE
            && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
        {
            GMX_RELEASE_ASSERT(params[i].val.u.ptr == NULL,
                               "value pointer is not NULL "
                               "although it should be for SPAR_VARNUM "
                               "and SPAR_ATOMVAL parameters");
            GMX_RELEASE_ASSERT(!((params[i].flags & SPAR_VARNUM)
                                 && (params[i].flags & SPAR_DYNAMIC))
                               || params[i].nvalptr != NULL,
                               "nvalptr is NULL but both "
                               "SPAR_VARNUM and SPAR_DYNAMIC are specified");
        }
        else
        {
            GMX_RELEASE_ASSERT(params[i].val.u.ptr != NULL,
                               "value pointer is NULL");
        }
    }
    /* Parse the parameters */
    int nullParamIndex = 0;
    SelectionParserParameterList::const_iterator pparam;
    for (pparam = pparams.begin(); pparam != pparams.end(); ++pparam)
    {
        try
        {
            // Always assigned afterwards, but cppcheck does not see that.
            gmx_ana_selparam_t *oparam = NULL;
            /* Find the parameter and make some checks */
            if (!pparam->name().empty())
            {
                nullParamIndex = -1;
                oparam
                    = gmx_ana_selparam_find(pparam->name().c_str(), nparam, params);
                GMX_RELEASE_ASSERT(oparam != NULL, "Inconsistent selection parameter");
            }
            else if (nullParamIndex >= 0)
            {
                oparam = &params[nullParamIndex];
                if (oparam->name != NULL)
                {
                    std::string text(_gmx_sel_lexer_get_text(scanner, pparam->location()));
                    std::string message
                        = formatString("Unexpected '%s'", text.c_str());
                    GMX_THROW(InvalidInputError(message));
                }
                ++nullParamIndex;
            }
            else
            {
                GMX_RELEASE_ASSERT(false, "All NULL parameters should appear in "
                                   "the beginning of the list");
            }
            if (oparam->flags & SPAR_SET)
            {
                std::string message
                    = formatString("'%s' appears multiple times",
                                   pparam->name().c_str());
                GMX_THROW(InvalidInputError(message));
            }
            oparam->flags |= SPAR_SET;
            if (oparam->val.type != NO_VALUE && pparam->values().empty())
            {
                std::string text;
                if (pparam->name().empty())
                {
                    text = root->name();
                }
                else
                {
                    text = _gmx_sel_lexer_get_text(scanner, pparam->location());
                }
                std::string message
                    = formatString("'%s' should be followed by a value/expression",
                                   text.c_str());
                GMX_THROW(InvalidInputError(message));
            }
            /* Process the values for the parameter */
            convert_const_values(pparam->values_.get());
            convert_values(pparam->values_.get(), oparam->val.type, scanner);
            if (oparam->val.type == NO_VALUE)
            {
                parse_values_bool(pparam->name(), pparam->values(), oparam, scanner);
            }
            else if (oparam->flags & SPAR_RANGES)
            {
                parse_values_range(pparam->values(), oparam, scanner);
            }
            else if (oparam->flags & SPAR_VARNUM)
            {
                if (pparam->values().size() == 1
                    && pparam->values().front().hasExpressionValue())
                {
                    parse_values_varnum_expr(pparam->values(), oparam, root, scanner);
                }
                else
                {
                    parse_values_varnum(pparam->values(), oparam, root, scanner);
                }
            }
            else if (oparam->flags & SPAR_ENUMVAL)
            {
                parse_values_enum(pparam->values(), oparam, scanner);
            }
            else
            {
                parse_values_std(pparam->values(), oparam, root, scanner);
            }
        }
        catch (UserInputError &ex)
        {
            if (!pparam->name().empty())
            {
                std::string text(_gmx_sel_lexer_get_text(scanner, pparam->location()));
                ex.prependContext(formatString("In '%s'", text.c_str()));
            }
            errors.addCurrentExceptionAsNested();
        }
    }
    /* Check that all required parameters are present */
    for (int i = 0; i < nparam; ++i)
    {
        if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET))
        {
            std::string message;
            if (params[i].name == NULL)
            {
                message = formatString("'%s' should be followed by a value/expression",
                                       root->name().c_str());
            }
            else
            {
                message = formatString("'%s' is missing", params[i].name);
            }
            InvalidInputError ex(message);
            errors.addNested(ex);
        }
    }
    if (errors.hasNestedExceptions())
    {
        GMX_THROW(InvalidInputError(errors));
    }
}