/*
 * Copyright 2021 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SKSL_METHODREFERENCE
#define SKSL_METHODREFERENCE

#include "src/sksl/SkSLContext.h"
#include "src/sksl/ir/SkSLExpression.h"

namespace SkSL {

class FunctionDeclaration;

/**
 * An identifier referring to a method name, along with an instance for the call.
 * This is an intermediate value: MethodReferences are always eventually replaced by FunctionCalls
 * in valid programs.
 *
 * Method calls are only supported on effect-child types, and they all resolve to intrinsics
 * prefixed with '$', and taking the 'self' object as the last parameter. For example:
 *
 *   uniform shader child;
 *   ...
 *   child.eval(xy)  -->  $eval(xy, child)
 */
class MethodReference final : public Expression {
public:
    inline static constexpr Kind kIRNodeKind = Kind::kMethodReference;

    MethodReference(const Context& context,
                    Position pos,
                    std::unique_ptr<Expression> self,
                    const FunctionDeclaration* overloadChain)
            : INHERITED(pos, kIRNodeKind, context.fTypes.fInvalid.get())
            , fSelf(std::move(self))
            , fOverloadChain(overloadChain) {}

    std::unique_ptr<Expression>& self() { return fSelf; }
    const std::unique_ptr<Expression>& self() const { return fSelf; }

    const FunctionDeclaration* overloadChain() const { return fOverloadChain; }

    std::unique_ptr<Expression> clone(Position pos) const override {
        return std::unique_ptr<Expression>(new MethodReference(
                pos, this->self()->clone(), this->overloadChain(), &this->type()));
    }

    std::string description(OperatorPrecedence) const override {
        return "<method>";
    }

private:
    MethodReference(Position pos,
                    std::unique_ptr<Expression> self,
                    const FunctionDeclaration* overloadChain,
                    const Type* type)
            : INHERITED(pos, kIRNodeKind, type)
            , fSelf(std::move(self))
            , fOverloadChain(overloadChain) {}

    std::unique_ptr<Expression> fSelf;
    const FunctionDeclaration* fOverloadChain;

    using INHERITED = Expression;
};

}  // namespace SkSL

#endif
