Example #1
0
        bool Parser::evaluateConfigReference(QualifiedName* qname)
        {
            if (qname == NULL)
                return true;

            AvmAssert(isConfigReference(qname));
            
            Str* ns = ((SimpleName*)qname->qualifier)->name;
            Str* name = ((SimpleName*)qname->name)->name;
            Expr* value = findConfigBinding(ns, name);
            if (value != NULL)
                return evaluateToBoolean(value);

            compiler->syntaxError(qname->pos, SYNTAXERR_UNBOUND_CONST_NAME);
            /*NOTREACHED*/
            return false;
        }
Example #2
0
        Expr* Parser::evaluateConfigDefinition(Str* ns, Expr* e)
        {
            // e is evaluated in an environment containing only config bindings.
            // ns is the default namespace: it will be used to qualify any unqualified name.
            
            switch (e->tag()) {
                case TAG_literalUndefined:
                case TAG_literalString:
                case TAG_literalNull:
                case TAG_literalUInt:
                case TAG_literalInt:
                case TAG_literalDouble:
                case TAG_literalBoolean:
                    return e;
                case TAG_simpleName: {
                    Expr* expr = findConfigBinding(ns, ((SimpleName*)e)->name);
                    if (expr == NULL)
                        compiler->syntaxError(expr->pos, SYNTAXERR_UNBOUND_CONST_NAME);
                    return expr;
                }
                case TAG_qualifiedName: {
                    QualifiedName* qname = (QualifiedName*)e;
                    if (qname->qualifier->tag() != TAG_simpleName || qname->name->tag() != TAG_simpleName)
                        compiler->syntaxError(e->pos, SYNTAXERR_UNBOUND_CONST_NAME);    // Specifically an illegal const name
                    Str* ns = ((SimpleName*)qname->qualifier)->name;
                    Str* name = ((SimpleName*)qname->name)->name;
                    Expr* value = findConfigBinding(ns, name);
                    if (value == NULL)
                        compiler->syntaxError(e->pos, SYNTAXERR_UNBOUND_CONST_NAME);
                    return value;
                }
                case TAG_binaryExpr: {
                    // CLARIFICATION: no short-circuiting
                    //
                    // We evaluate both sides of && and || in order to uncover
                    // any undefined variables lurking in non-taken branches.
                    BinaryExpr* binary = (BinaryExpr*)e;
                    Expr* lhs = evaluateConfigDefinition(ns, binary->lhs);
                    Expr* rhs = evaluateConfigDefinition(ns, binary->rhs);
                    switch (binary->op) {
                        case OPR_plus:
                            if (lhs->tag() == TAG_literalString || rhs->tag() == TAG_literalString) {
                                StringBuilder b(compiler);
                                b.append(((LiteralString*)lhs)->value);
                                b.append(((LiteralString*)rhs)->value);
                                return boxString(b.str());
                            }
                            return boxDouble(evaluateToNumber(lhs) + evaluateToNumber(rhs));
                        case OPR_minus:
                            return boxDouble(evaluateToNumber(lhs) - evaluateToNumber(rhs));
                        case OPR_multiply:
                            return boxDouble(evaluateToNumber(lhs) * evaluateToNumber(rhs));
                        case OPR_divide:
                            return boxDouble(evaluateToNumber(lhs) / evaluateToNumber(rhs));
                        case OPR_remainder:
                            return boxDouble(fmod(evaluateToNumber(lhs), evaluateToNumber(rhs)));
                        case OPR_leftShift:
                            return boxInt(evaluateToInt32(lhs) << (evaluateToUInt32(rhs) & 0x1F));
                        case OPR_rightShift:
                            return boxInt(evaluateToInt32(lhs) >> (evaluateToUInt32(rhs) & 0x1F));
                        case OPR_rightShiftUnsigned:
                            return boxUInt(evaluateToUInt32(lhs) >> (evaluateToUInt32(rhs) & 0x1F));
                        case OPR_bitwiseAnd:
                            return boxInt(evaluateToInt32(lhs) & evaluateToInt32(rhs));
                        case OPR_bitwiseOr:
                            return boxInt(evaluateToInt32(lhs) | evaluateToInt32(rhs));
                        case OPR_bitwiseXor:
                            return boxInt(evaluateToInt32(lhs) ^ evaluateToInt32(rhs));
                        case OPR_logicalAnd:
                            return boxBoolean(int(evaluateToBoolean(lhs)) + int(evaluateToBoolean(rhs)) == 2);
                        case OPR_logicalOr:
                            return boxBoolean(int(evaluateToBoolean(lhs)) + int(evaluateToBoolean(rhs)) != 0);
                        case OPR_less: {
                            int r = evaluateRelational(lhs, rhs);
                            return boxBoolean(r == -1 || r == 0 ? false : true);
                        }
                        case OPR_greater: {
                            int r = evaluateRelational(rhs, lhs);
                            return boxBoolean(r == -1 || r == 0 ? false : true);
                        }
                        case OPR_lessOrEqual: {
                            int r = evaluateRelational(rhs, lhs);
                            return boxBoolean(r == -1 || r == 1 ? false : true);
                        }
                        case OPR_greaterOrEqual: {
                            int r = evaluateRelational(lhs, rhs);
                            return boxBoolean(r == -1 || r == 1 ? false : true);
                        }
                        case OPR_equal:
                        case OPR_notEqual:
                        case OPR_strictEqual:
                        case OPR_strictNotEqual: {
                            if (lhs->tag() == TAG_literalInt || lhs->tag() == TAG_literalUInt)
                                lhs = boxDouble(evaluateToNumber(lhs));
                            if (rhs->tag() == TAG_literalInt || rhs->tag() == TAG_literalUInt)
                                rhs = boxDouble(evaluateToNumber(rhs));

                            bool equality;
                            if (binary->op == OPR_equal || binary->op == OPR_notEqual)
                                equality = binary->op == OPR_equal;
                            else
                                equality = binary->op == OPR_strictEqual;
                            
                            if (lhs->tag() != rhs->tag()) {
                                if (binary->op == OPR_equal || binary->op == OPR_notEqual) {
                                    if ((lhs->tag() == TAG_literalUndefined && rhs->tag() == TAG_literalNull) ||
                                        (lhs->tag() == TAG_literalNull && rhs->tag() == TAG_literalUndefined))
                                        return boxBoolean(true == equality);
                                    if ((lhs->tag() == TAG_literalString && rhs->tag() == TAG_literalDouble) ||
                                        (lhs->tag() == TAG_literalDouble && rhs->tag() == TAG_literalString))
                                        return boxBoolean((evaluateToNumber(lhs) == evaluateToNumber(rhs)) == equality);
                                    if (lhs->tag() == TAG_literalBoolean || rhs->tag() == TAG_literalBoolean)
                                        return boxBoolean((evaluateToBoolean(lhs) == evaluateToBoolean(rhs)) == equality);
                                }
                                return boxBoolean(false == equality);
                            }
                            if (lhs->tag() == TAG_literalUndefined || lhs->tag() == TAG_literalNull)
                                return boxBoolean(true == equality);
                            if (lhs->tag() == TAG_literalDouble)
                                return boxBoolean((evaluateToNumber(lhs) == evaluateToNumber(rhs)) == equality);
                            if (lhs->tag() == TAG_literalBoolean)
                                return boxBoolean((evaluateToBoolean(lhs) == evaluateToBoolean(rhs)) == equality);
                            if (lhs->tag() == TAG_literalString)
                                return boxBoolean((evaluateToString(lhs) == evaluateToString(rhs)) == equality);
                            failNonConstant(lhs);
                            /*NOTREACHED*/
                            break;
                        }
                        default:
                            // "as", "is", "in", ",", "="
                            compiler->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR);
                            /*NOTREACHED*/
                            break;
                    }
                    /*NOTREACHED*/
                    break;
                }
                case TAG_unaryExpr: {
                    // EXTENSION: typeof
                    //
                    // Supporting "typeof" makes some sort of sense (for example, the
                    // operand of typeof can be a config constant that can take on
                    // various values, and computing the name of the type into the
                    // program can be useful).
                    //
                    // EXTENSION: void
                    //
                    // Supporting "void" probably does not make a lot of sense, but it
                    // seems benign.
                    UnaryExpr* unary = (UnaryExpr*)e;
                    Expr* opd = evaluateConfigDefinition(ns, unary->expr);
                    switch (unary->op) {
                        case OPR_typeof:
                            switch (opd->tag()) {
                                case TAG_literalUndefined: return boxString("undefined");
                                case TAG_literalString:    return boxString("string");
                                case TAG_literalNull:      return boxString("object");
                                case TAG_literalUInt:
                                case TAG_literalInt:
                                case TAG_literalDouble:    return boxString("number");
                                case TAG_literalBoolean:   return boxString("boolean");
                                default:
                                    failNonConstant(opd);
                                    return NULL;
                            }
                        case OPR_bitwiseNot: return boxUInt(~evaluateToUInt32(opd));
                        case OPR_unminus:    return boxDouble(-evaluateToNumber(opd));
                        case OPR_unplus:     return boxDouble(evaluateToNumber(opd));
                        case OPR_not:        return boxBoolean(!evaluateToBoolean(opd));
                        case OPR_void:       return boxUndefined();
                        default:
                            // "delete", "++", "--"
                            compiler->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR);
                            /*NOTREACHED*/
                            break;
                    }
                    /*NOTREACHED*/
                    break;
                }
                case TAG_conditionalExpr: {
                    // EXTENSION: conditional operator
                    //
                    // It seems totally sensible to support "... ? ... : ...", though
                    // it's not mentioned in the conditional compilation spec.
                    //
                    // We evaluate both arms in order to uncover references to undefined
                    // configuration variables, same as for && and ||.
                    ConditionalExpr* cond = (ConditionalExpr*)e;
                    Expr* e1 = evaluateConfigDefinition(ns, cond->e1);
                    Expr* e2 = evaluateConfigDefinition(ns, cond->e2);
                    Expr* e3 = evaluateConfigDefinition(ns, cond->e3);
                    return evaluateToBoolean(e1) ? e2 : e3;
                }
                default:
                    // Property references, 'new', 'call' - lots of things
                    compiler->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR);
                    /*NOTREACHED*/
                    break;
            }
            /*NOTREACHED*/
            return NULL;
        }
/**
 * Evaluates this Expr based on the given context node and processor state
 * @param context the context node for evaluation of this Expr
 * @param ps the ContextState containing the stack information needed
 * for evaluation
 * @return the result of the evaluation
**/
nsresult
BooleanFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
{
    *aResult = nsnull;

    txListIterator iter(&params);
    switch (mType) {
    case TX_BOOLEAN:
    {
        if (!requireParams(1, 1, aContext))
            return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

        aContext->recycler()->getBoolResult(
            evaluateToBoolean((Expr*)iter.next(), aContext), aResult);

        return NS_OK;
    }
    case TX_LANG:
    {
        if (!requireParams(1, 1, aContext))
            return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

        txXPathTreeWalker walker(aContext->getContextNode());

        nsAutoString lang;
        PRBool found;
        do {
            found = walker.getAttr(txXMLAtoms::lang, kNameSpaceID_XML,
                                   lang);
        } while (!found && walker.moveToParent());

        if (!found) {
            aContext->recycler()->getBoolResult(PR_FALSE, aResult);

            return NS_OK;
        }

        nsAutoString arg;
        evaluateToString((Expr*)iter.next(), aContext, arg);
        PRBool result = arg.Equals(Substring(lang, 0, arg.Length()),
                                   txCaseInsensitiveStringComparator()) &&
                        (lang.Length() == arg.Length() ||
                         lang.CharAt(arg.Length()) == '-');

        aContext->recycler()->getBoolResult(result, aResult);

        return NS_OK;
    }
    case TX_NOT:
    {
        if (!requireParams(1, 1, aContext))
            return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

        aContext->recycler()->getBoolResult(
            !evaluateToBoolean((Expr*)iter.next(), aContext), aResult);

        return NS_OK;
    }
    case TX_TRUE:
    {
        if (!requireParams(0, 0, aContext))
            return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

        aContext->recycler()->getBoolResult(PR_TRUE, aResult);

        return NS_OK;
    }
    case TX_FALSE:
    {
        if (!requireParams(0, 0, aContext))
            return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

        aContext->recycler()->getBoolResult(PR_FALSE, aResult);

        return NS_OK;
    }
    }

    aContext->receiveError(NS_LITERAL_STRING("Internal error"),
                           NS_ERROR_UNEXPECTED);
    return NS_ERROR_UNEXPECTED;
}