예제 #1
0
파일: tuples.hpp 프로젝트: CTrauma/pypp11
 static TTuple to_c_tuple( PyObject* py_obj ){
     if( !convertible( py_obj ) ){
         throw std::runtime_error( "Unable to construct boost::tuples::tuple from Python object!" );
     }
     TTuple c_tuple;
     python::object py_sequence( handle<>( borrowed( py_obj ) ) );
     construct_impl( py_sequence, c_tuple, mpl::int_< 0 >(), length_type() );
     return c_tuple;
 }
예제 #2
0
// Select the best matching function for 'call' from 'candidateList'.
//
// Assumptions
//
// There is no exact match, so a selection algorithm needs to run. That is, the
// language-specific handler should check for exact match first, to
// decide what to do, before calling this selector.
//
// Input
//
//  * list of candidate signatures to select from
//  * the call
//  * a predicate function convertible(from, to) that says whether or not type
//    'from' can implicitly convert to type 'to' (it includes the case of what
//    the calling language would consider a matching type with no conversion
//    needed)
//  * a predicate function better(from1, from2, to1, to2) that says whether or
//    not a conversion from <-> to2 is considered better than a conversion
//    from <-> to1 (both in and out directions need testing, as declared by the
//    formal parameter)
//
// Output
//
//  * best matching candidate (or none, if no viable candidates found)
//  * whether there was a tie for the best match (ambiguous overload selection,
//    caller's choice for how to report)
//
const TFunction* TParseContextBase::selectFunction(
    const TVector<const TFunction*> candidateList,
    const TFunction& call,
    std::function<bool(const TType& from, const TType& to, TOperator op, int arg)> convertible,
    std::function<bool(const TType& from, const TType& to1, const TType& to2)> better,
    /* output */ bool& tie)
{
//
// Operation
//
// 1. Prune the input list of candidates down to a list of viable candidates,
// where each viable candidate has
//
//  * at least as many parameters as there are calling arguments, with any
//    remaining parameters being optional or having default values
//  * each parameter is true under convertible(A, B), where A is the calling
//    type for in and B is the formal type, and in addition, for out B is the
//    calling type and A is the formal type
//
// 2. If there are no viable candidates, return with no match.
//
// 3. If there is only one viable candidate, it is the best match.
//
// 4. If there are multiple viable candidates, select the first viable candidate
// as the incumbent. Compare the incumbent to the next viable candidate, and if
// that candidate is better (bullets below), make it the incumbent. Repeat, with
// a linear walk through the viable candidate list. The final incumbent will be
// returned as the best match. A viable candidate is better than the incumbent if
//
//  * it has a function argument with a better(...) conversion than the incumbent,
//    for all directions needed by in and out
//  * the incumbent has no argument with a better(...) conversion then the
//    candidate, for either in or out (as needed)
//
// 5. Check for ambiguity by comparing the best match against all other viable
// candidates. If any other viable candidate has a function argument with a
// better(...) conversion than the best candidate (for either in or out
// directions), return that there was a tie for best.
//

    tie = false;

    // 1. prune to viable...
    TVector<const TFunction*> viableCandidates;
    for (auto it = candidateList.begin(); it != candidateList.end(); ++it) {
        const TFunction& candidate = *(*it);

        // to even be a potential match, number of arguments must be >= the number of
        // fixed (non-default) parameters, and <= the total (including parameter with defaults).
        if (call.getParamCount() < candidate.getFixedParamCount() ||
            call.getParamCount() > candidate.getParamCount())
            continue;

        // see if arguments are convertible
        bool viable = true;

        // The call can have fewer parameters than the candidate, if some have defaults.
        const int paramCount = std::min(call.getParamCount(), candidate.getParamCount());
        for (int param = 0; param < paramCount; ++param) {
            if (candidate[param].type->getQualifier().isParamInput()) {
                if (! convertible(*call[param].type, *candidate[param].type, candidate.getBuiltInOp(), param)) {
                    viable = false;
                    break;
                }
            }
            if (candidate[param].type->getQualifier().isParamOutput()) {
                if (! convertible(*candidate[param].type, *call[param].type, candidate.getBuiltInOp(), param)) {
                    viable = false;
                    break;
                }
            }
        }

        if (viable)
            viableCandidates.push_back(&candidate);
    }

    // 2. none viable...
    if (viableCandidates.size() == 0)
        return nullptr;

    // 3. only one viable...
    if (viableCandidates.size() == 1)
        return viableCandidates.front();

    // 4. find best...
    const auto betterParam = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
        // is call -> can2 better than call -> can1 for any parameter
        bool hasBetterParam = false;
        for (int param = 0; param < call.getParamCount(); ++param) {
            if (better(*call[param].type, *can1[param].type, *can2[param].type)) {
                hasBetterParam = true;
                break;
            }
        }
        return hasBetterParam;
    };

    const auto equivalentParams = [&call, &better](const TFunction& can1, const TFunction& can2) -> bool {
        // is call -> can2 equivalent to call -> can1 for all the call parameters?
        for (int param = 0; param < call.getParamCount(); ++param) {
            if (better(*call[param].type, *can1[param].type, *can2[param].type) ||
                better(*call[param].type, *can2[param].type, *can1[param].type))
                return false;
        }
        return true;
    };

    const TFunction* incumbent = viableCandidates.front();
    for (auto it = viableCandidates.begin() + 1; it != viableCandidates.end(); ++it) {
        const TFunction& candidate = *(*it);
        if (betterParam(*incumbent, candidate) && ! betterParam(candidate, *incumbent))
            incumbent = &candidate;
    }

    // 5. ambiguity...
    for (auto it = viableCandidates.begin(); it != viableCandidates.end(); ++it) {
        if (incumbent == *it)
            continue;
        const TFunction& candidate = *(*it);

        // In the case of default parameters, it may have an identical initial set, which is
        // also ambiguous
        if (betterParam(*incumbent, candidate) || equivalentParams(*incumbent, candidate))
            tie = true;
    }

    return incumbent;
}