// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_GN_FUNCTIONS_H_
#define TOOLS_GN_FUNCTIONS_H_

#include <map>
#include <string>
#include <string_view>
#include <vector>

class Err;
class BlockNode;
class FunctionCallNode;
class Label;
class ListNode;
class ParseNode;
class Scope;
class Value;

// -----------------------------------------------------------------------------

namespace functions {

// This type of function invocation has no block and evaluates its arguments
// itself rather than taking a pre-executed list. This allows us to implement
// certain built-in functions.
using SelfEvaluatingArgsFunction = Value (*)(Scope* scope,
                                             const FunctionCallNode* function,
                                             const ListNode* args_list,
                                             Err* err);

// This type of function invocation takes a block node that it will execute.
using GenericBlockFunction = Value (*)(Scope* scope,
                                       const FunctionCallNode* function,
                                       const std::vector<Value>& args,
                                       BlockNode* block,
                                       Err* err);

// This type of function takes a block, but does not need to control execution
// of it. The dispatch function will pre-execute the block and pass the
// resulting block_scope to the function.
using ExecutedBlockFunction = Value (*)(const FunctionCallNode* function,
                                        const std::vector<Value>& args,
                                        Scope* block_scope,
                                        Err* err);

// This type of function does not take a block. It just has arguments.
using NoBlockFunction = Value (*)(Scope* scope,
                                  const FunctionCallNode* function,
                                  const std::vector<Value>& args,
                                  Err* err);

extern const char kAction[];
extern const char kAction_HelpShort[];
extern const char kAction_Help[];
Value RunAction(Scope* scope,
                const FunctionCallNode* function,
                const std::vector<Value>& args,
                BlockNode* block,
                Err* err);

extern const char kActionForEach[];
extern const char kActionForEach_HelpShort[];
extern const char kActionForEach_Help[];
Value RunActionForEach(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args,
                       BlockNode* block,
                       Err* err);

extern const char kAssert[];
extern const char kAssert_HelpShort[];
extern const char kAssert_Help[];
Value RunAssert(Scope* scope,
                const FunctionCallNode* function,
                const std::vector<Value>& args,
                Err* err);

extern const char kBundleData[];
extern const char kBundleData_HelpShort[];
extern const char kBundleData_Help[];
Value RunBundleData(Scope* scope,
                    const FunctionCallNode* function,
                    const std::vector<Value>& args,
                    BlockNode* block,
                    Err* err);

extern const char kCreateBundle[];
extern const char kCreateBundle_HelpShort[];
extern const char kCreateBundle_Help[];
Value RunCreateBundle(Scope* scope,
                      const FunctionCallNode* function,
                      const std::vector<Value>& args,
                      BlockNode* block,
                      Err* err);

extern const char kConfig[];
extern const char kConfig_HelpShort[];
extern const char kConfig_Help[];
Value RunConfig(const FunctionCallNode* function,
                const std::vector<Value>& args,
                Scope* block_scope,
                Err* err);

extern const char kCopy[];
extern const char kCopy_HelpShort[];
extern const char kCopy_Help[];
Value RunCopy(const FunctionCallNode* function,
              const std::vector<Value>& args,
              Scope* block_scope,
              Err* err);

extern const char kDeclareArgs[];
extern const char kDeclareArgs_HelpShort[];
extern const char kDeclareArgs_Help[];
Value RunDeclareArgs(Scope* scope,
                     const FunctionCallNode* function,
                     const std::vector<Value>& args,
                     BlockNode* block,
                     Err* err);

extern const char kDefined[];
extern const char kDefined_HelpShort[];
extern const char kDefined_Help[];
Value RunDefined(Scope* scope,
                 const FunctionCallNode* function,
                 const ListNode* args_list,
                 Err* err);

extern const char kExecScript[];
extern const char kExecScript_HelpShort[];
extern const char kExecScript_Help[];
Value RunExecScript(Scope* scope,
                    const FunctionCallNode* function,
                    const std::vector<Value>& args,
                    Err* err);

extern const char kExecutable[];
extern const char kExecutable_HelpShort[];
extern const char kExecutable_Help[];
Value RunExecutable(Scope* scope,
                    const FunctionCallNode* function,
                    const std::vector<Value>& args,
                    BlockNode* block,
                    Err* err);

extern const char kFilterExclude[];
extern const char kFilterExclude_HelpShort[];
extern const char kFilterExclude_Help[];
Value RunFilterExclude(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args,
                       Err* err);

extern const char kFilterInclude[];
extern const char kFilterInclude_HelpShort[];
extern const char kFilterInclude_Help[];
Value RunFilterInclude(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args,
                       Err* err);

extern const char kForEach[];
extern const char kForEach_HelpShort[];
extern const char kForEach_Help[];
Value RunForEach(Scope* scope,
                 const FunctionCallNode* function,
                 const ListNode* args_list,
                 Err* err);

extern const char kForwardVariablesFrom[];
extern const char kForwardVariablesFrom_HelpShort[];
extern const char kForwardVariablesFrom_Help[];
Value RunForwardVariablesFrom(Scope* scope,
                              const FunctionCallNode* function,
                              const ListNode* args_list,
                              Err* err);

extern const char kGetEnv[];
extern const char kGetEnv_HelpShort[];
extern const char kGetEnv_Help[];
Value RunGetEnv(Scope* scope,
                const FunctionCallNode* function,
                const std::vector<Value>& args,
                Err* err);

extern const char kGetLabelInfo[];
extern const char kGetLabelInfo_HelpShort[];
extern const char kGetLabelInfo_Help[];
Value RunGetLabelInfo(Scope* scope,
                      const FunctionCallNode* function,
                      const std::vector<Value>& args,
                      Err* err);

extern const char kGetPathInfo[];
extern const char kGetPathInfo_HelpShort[];
extern const char kGetPathInfo_Help[];
Value RunGetPathInfo(Scope* scope,
                     const FunctionCallNode* function,
                     const std::vector<Value>& args,
                     Err* err);

extern const char kGetTargetOutputs[];
extern const char kGetTargetOutputs_HelpShort[];
extern const char kGetTargetOutputs_Help[];
Value RunGetTargetOutputs(Scope* scope,
                          const FunctionCallNode* function,
                          const std::vector<Value>& args,
                          Err* err);

extern const char kGeneratedFile[];
extern const char kGeneratedFile_HelpShort[];
extern const char kGeneratedFile_Help[];
Value RunGeneratedFile(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args,
                       BlockNode* block,
                       Err* err);

extern const char kGroup[];
extern const char kGroup_HelpShort[];
extern const char kGroup_Help[];
Value RunGroup(Scope* scope,
               const FunctionCallNode* function,
               const std::vector<Value>& args,
               BlockNode* block,
               Err* err);

extern const char kImport[];
extern const char kImport_HelpShort[];
extern const char kImport_Help[];
Value RunImport(Scope* scope,
                const FunctionCallNode* function,
                const std::vector<Value>& args,
                Err* err);

extern const char kLoadableModule[];
extern const char kLoadableModule_HelpShort[];
extern const char kLoadableModule_Help[];
Value RunLoadableModule(Scope* scope,
                        const FunctionCallNode* function,
                        const std::vector<Value>& args,
                        BlockNode* block,
                        Err* err);

extern const char kNotNeeded[];
extern const char kNotNeeded_HelpShort[];
extern const char kNotNeeded_Help[];
Value RunNotNeeded(Scope* scope,
                   const FunctionCallNode* function,
                   const ListNode* args_list,
                   Err* err);

extern const char kPool[];
extern const char kPool_HelpShort[];
extern const char kPool_Help[];
Value RunPool(const FunctionCallNode* function,
              const std::vector<Value>& args,
              Scope* block_scope,
              Err* err);

extern const char kPrint[];
extern const char kPrint_HelpShort[];
extern const char kPrint_Help[];
Value RunPrint(Scope* scope,
               const FunctionCallNode* function,
               const std::vector<Value>& args,
               Err* err);

extern const char kProcessFileTemplate[];
extern const char kProcessFileTemplate_HelpShort[];
extern const char kProcessFileTemplate_Help[];
Value RunProcessFileTemplate(Scope* scope,
                             const FunctionCallNode* function,
                             const std::vector<Value>& args,
                             Err* err);

extern const char kReadFile[];
extern const char kReadFile_HelpShort[];
extern const char kReadFile_Help[];
Value RunReadFile(Scope* scope,
                  const FunctionCallNode* function,
                  const std::vector<Value>& args,
                  Err* err);

extern const char kRebasePath[];
extern const char kRebasePath_HelpShort[];
extern const char kRebasePath_Help[];
Value RunRebasePath(Scope* scope,
                    const FunctionCallNode* function,
                    const std::vector<Value>& args,
                    Err* err);

extern const char kRustLibrary[];
extern const char kRustLibrary_HelpShort[];
extern const char kRustLibrary_Help[];
Value RunRustLibrary(Scope* scope,
                     const FunctionCallNode* function,
                     const std::vector<Value>& args,
                     BlockNode* block,
                     Err* err);

extern const char kRustProcMacro[];
extern const char kRustProcMacro_HelpShort[];
extern const char kRustProcMacro_Help[];
Value RunRustProcMacro(Scope* scope,
                   const FunctionCallNode* function,
                   const std::vector<Value>& args,
                   BlockNode* block,
                   Err* err);

extern const char kSetDefaults[];
extern const char kSetDefaults_HelpShort[];
extern const char kSetDefaults_Help[];
Value RunSetDefaults(Scope* scope,
                     const FunctionCallNode* function,
                     const std::vector<Value>& args,
                     BlockNode* block,
                     Err* err);

extern const char kSetDefaultToolchain[];
extern const char kSetDefaultToolchain_HelpShort[];
extern const char kSetDefaultToolchain_Help[];
Value RunSetDefaultToolchain(Scope* scope,
                             const FunctionCallNode* function,
                             const std::vector<Value>& args,
                             Err* err);

extern const char kSharedLibrary[];
extern const char kSharedLibrary_HelpShort[];
extern const char kSharedLibrary_Help[];
Value RunSharedLibrary(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args,
                       BlockNode* block,
                       Err* err);

extern const char kSourceSet[];
extern const char kSourceSet_HelpShort[];
extern const char kSourceSet_Help[];
Value RunSourceSet(Scope* scope,
                   const FunctionCallNode* function,
                   const std::vector<Value>& args,
                   BlockNode* block,
                   Err* err);

extern const char kSplitList[];
extern const char kSplitList_HelpShort[];
extern const char kSplitList_Help[];
Value RunSplitList(Scope* scope,
                   const FunctionCallNode* function,
                   const ListNode* args_list,
                   Err* err);

extern const char kStaticLibrary[];
extern const char kStaticLibrary_HelpShort[];
extern const char kStaticLibrary_Help[];
Value RunStaticLibrary(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args,
                       BlockNode* block,
                       Err* err);

extern const char kReplaceSubstr[];
extern const char kReplaceSubstr_HelpShort[];
extern const char kReplaceSubstr_Help[];
Value RunReplaceSubstr(Scope* scope,
                       const FunctionCallNode* function,
                       const std::vector<Value>& args_list,
                       Err* err);

extern const char kTarget[];
extern const char kTarget_HelpShort[];
extern const char kTarget_Help[];
Value RunTarget(Scope* scope,
                const FunctionCallNode* function,
                const std::vector<Value>& args,
                BlockNode* block,
                Err* err);

extern const char kTemplate[];
extern const char kTemplate_HelpShort[];
extern const char kTemplate_Help[];
Value RunTemplate(Scope* scope,
                  const FunctionCallNode* function,
                  const std::vector<Value>& args,
                  BlockNode* block,
                  Err* err);

extern const char kTool[];
extern const char kTool_HelpShort[];
extern const char kTool_Help[];
Value RunTool(Scope* scope,
              const FunctionCallNode* function,
              const std::vector<Value>& args,
              BlockNode* block,
              Err* err);

extern const char kToolchain[];
extern const char kToolchain_HelpShort[];
extern const char kToolchain_Help[];
Value RunToolchain(Scope* scope,
                   const FunctionCallNode* function,
                   const std::vector<Value>& args,
                   BlockNode* block,
                   Err* err);

extern const char kWriteFile[];
extern const char kWriteFile_HelpShort[];
extern const char kWriteFile_Help[];
Value RunWriteFile(Scope* scope,
                   const FunctionCallNode* function,
                   const std::vector<Value>& args,
                   Err* err);

// -----------------------------------------------------------------------------

// One function record. Only one of the given runner types will be non-null
// which indicates the type of function it is.
struct FunctionInfo {
  FunctionInfo();
  FunctionInfo(SelfEvaluatingArgsFunction seaf,
               const char* in_help_short,
               const char* in_help,
               bool in_is_target);
  FunctionInfo(GenericBlockFunction gbf,
               const char* in_help_short,
               const char* in_help,
               bool in_is_target);
  FunctionInfo(ExecutedBlockFunction ebf,
               const char* in_help_short,
               const char* in_help,
               bool in_is_target);
  FunctionInfo(NoBlockFunction nbf,
               const char* in_help_short,
               const char* in_help,
               bool in_is_target);

  SelfEvaluatingArgsFunction self_evaluating_args_runner;
  GenericBlockFunction generic_block_runner;
  ExecutedBlockFunction executed_block_runner;
  NoBlockFunction no_block_runner;

  const char* help_short;
  const char* help;

  bool is_target;
};

using FunctionInfoMap = std::map<std::string_view, FunctionInfo>;

// Returns the mapping of all built-in functions.
const FunctionInfoMap& GetFunctions();

// Runs the given function.
Value RunFunction(Scope* scope,
                  const FunctionCallNode* function,
                  const ListNode* args_list,
                  BlockNode* block,  // Optional.
                  Err* err);

}  // namespace functions

// Helper functions -----------------------------------------------------------

// Validates that the scope that a value is defined in is not the scope
// of the current declare_args() call, if that's what we're in. It is
// illegal to read a value from inside the same declare_args() call, since
// the overrides will not have been applied yet (see `gn help declare_args`
// for more).
bool EnsureNotReadingFromSameDeclareArgs(const ParseNode* node,
                                         const Scope* cur_scope,
                                         const Scope* val_scope,
                                         Err* err);

// Verifies that the current scope is not processing an import. If it is, it
// will set the error, blame the given parse node for it, and return false.
bool EnsureNotProcessingImport(const ParseNode* node,
                               const Scope* scope,
                               Err* err);

// Like EnsureNotProcessingImport but checks for running the build config.
bool EnsureNotProcessingBuildConfig(const ParseNode* node,
                                    const Scope* scope,
                                    Err* err);

// Sets up the |block_scope| for executing a target (or something like it).
// The |scope| is the containing scope. It should have been already set as the
// parent for the |block_scope| when the |block_scope| was created.
//
// This will set up the target defaults and set the |target_name| variable in
// the block scope to the current target name, which is assumed to be the first
// argument to the function.
//
// On success, returns true. On failure, sets the error and returns false.
bool FillTargetBlockScope(const Scope* scope,
                          const FunctionCallNode* function,
                          const std::string& target_type,
                          const BlockNode* block,
                          const std::vector<Value>& args,
                          Scope* block_scope,
                          Err* err);

// Sets the given error to a message explaining that the function call requires
// a block.
void FillNeedsBlockError(const FunctionCallNode* function, Err* err);

// Validates that the given function call has one string argument. This is
// the most common function signature, so it saves space to have this helper.
// Returns false and sets the error on failure.
bool EnsureSingleStringArg(const FunctionCallNode* function,
                           const std::vector<Value>& args,
                           Err* err);

// Returns the name of the toolchain for the given scope.
const Label& ToolchainLabelForScope(const Scope* scope);

// Generates a label for the given scope, using the current directory and
// toolchain, and the given name.
Label MakeLabelForScope(const Scope* scope,
                        const FunctionCallNode* function,
                        const std::string& name);

// Some types of blocks can't be nested inside other ones. For such cases,
// instantiate this object upon entering the block and Enter() will fail if
// there is already another non-nestable block on the stack.
class NonNestableBlock {
 public:
  // type_description is a string that will be used in error messages
  // describing the type of the block, for example, "template" or "config".
  NonNestableBlock(Scope* scope,
                   const FunctionCallNode* function,
                   const char* type_description);
  ~NonNestableBlock();

  bool Enter(Err* err);

 private:
  // Used as a void* key for the Scope to track our property. The actual value
  // is never used.
  static const int kKey;

  Scope* scope_;
  const FunctionCallNode* function_;
  const char* type_description_;

  // Set to true when the key is added to the scope so we don't try to
  // delete nonexistent keys which will cause assertions.
  bool key_added_;
};

#endif  // TOOLS_GN_FUNCTIONS_H_
