/* Copyright JS Foundation and other contributors, http://js.foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef JS_PARSER_INTERNAL_H
#define JS_PARSER_INTERNAL_H

#include "common.h"

#include "byte-code.h"
#include "debugger.h"
#include "js-parser.h"
#include "js-parser-limits.h"
#include "js-lexer.h"
#include "js-scanner.h"

#include "ecma-module.h"

/** \addtogroup parser Parser
 * @{
 *
 * \addtogroup jsparser JavaScript
 * @{
 *
 * \addtogroup jsparser_internals Internals
 * @{
 */

/**
 * General parser flags.
 */
typedef enum
{
  PARSER_IS_STRICT = (1u << 0),               /**< strict mode code */
  PARSER_IS_FUNCTION = (1u << 1),             /**< function body is parsed */
  PARSER_IS_CLOSURE = (1u << 2),              /**< function body is encapsulated in {} block */
  PARSER_IS_FUNC_EXPRESSION = (1u << 3),      /**< a function expression is parsed */
  PARSER_IS_PROPERTY_GETTER = (1u << 4),      /**< a property getter function is parsed */
  PARSER_IS_PROPERTY_SETTER = (1u << 5),      /**< a property setter function is parsed */
  PARSER_HAS_NON_STRICT_ARG = (1u << 6),      /**< the function has arguments which
                                               *   are not supported in strict mode */
  PARSER_ARGUMENTS_NEEDED = (1u << 7),        /**< arguments object must be created */
  PARSER_LEXICAL_ENV_NEEDED = (1u << 8),      /**< lexical environment object must be created */
  PARSER_INSIDE_WITH = (1u << 9),             /**< code block is inside a with statement */
  PARSER_NO_END_LABEL = (1u << 10),           /**< return instruction must be inserted
                                               *   after the last byte code */
  PARSER_DEBUGGER_BREAKPOINT_APPENDED = (1u << 11), /**< pending (unsent) breakpoint
                                                     *   info is available */
#if JERRY_ESNEXT
  PARSER_LEXICAL_BLOCK_NEEDED = (1u << 12),   /**< global script: needs a lexical environment for let and const
                                               *   function: needs a lexical environment for arguments */
  PARSER_IS_ARROW_FUNCTION = (1u << 13),      /**< an arrow function is parsed */
  PARSER_IS_GENERATOR_FUNCTION = (1u << 14),  /**< a generator function is parsed */
  PARSER_IS_ASYNC_FUNCTION = (1u << 15),      /**< an async function is parsed */
  PARSER_DISALLOW_AWAIT_YIELD = (1u << 16),   /**< throw SyntaxError for await / yield keywords */
  PARSER_FUNCTION_IS_PARSING_ARGS = (1u << 17), /**< set when parsing function arguments */
  PARSER_FUNCTION_HAS_COMPLEX_ARGUMENT = (1u << 18), /**< function has complex (ES2015+) argument definition */
  PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */
  PARSER_CLASS_CONSTRUCTOR = (1u << 20),      /**< a class constructor is parsed
                                               *   Note: PARSER_ALLOW_SUPER must be present */
  /* These four status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
  PARSER_ALLOW_SUPER = (1u << 21),            /**< allow super property access */
  PARSER_ALLOW_SUPER_CALL = (1u << 22),       /**< allow super constructor call
                                               *   Note: PARSER_CLASS_CONSTRUCTOR must be present */
  PARSER_INSIDE_CLASS_FIELD = (1u << 23),     /**< a class field is being parsed */
  PARSER_ALLOW_NEW_TARGET = (1u << 24),       /**< allow new.target parsing in the current context */
  PARSER_IS_METHOD = (1u << 25),              /**< method is parsed */
#endif /* JERRY_ESNEXT */
#if JERRY_MODULE_SYSTEM
  PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 26),  /**< parsing a function or class default export */
  PARSER_MODULE_STORE_IDENT = (1u << 27),     /**< store identifier of the current export statement */
#endif /* JERRY_MODULE_SYSTEM */
  PARSER_HAS_LATE_LIT_INIT = (1u << 30),      /**< there are identifier or string literals which construction
                                               *   is postponed after the local parser data is freed */
#ifndef JERRY_NDEBUG
  PARSER_SCANNING_SUCCESSFUL = PARSER_HAS_LATE_LIT_INIT, /**< scanning process was successful */
#endif /* !JERRY_NDEBUG */
} parser_general_flags_t;

/**
 * Expression parsing flags.
 */
typedef enum
{
  PARSE_EXPR = 0,                             /**< parse an expression without any special flags */
  PARSE_EXPR_LEFT_HAND_SIDE = (1u << 0),      /**< parse a left-hand-side expression */
  PARSE_EXPR_NO_PUSH_RESULT = (1u << 1),      /**< do not push the result of the expression onto the stack */
  PARSE_EXPR_NO_COMMA = (1u << 2),            /**< do not parse comma operator */
  PARSE_EXPR_HAS_LITERAL = (1u << 3),         /**< a primary literal is provided by a
                                               *   CBC_PUSH_LITERAL instruction  */
} parser_expression_flags_t;

/**
 * Pattern parsing flags.
 */
typedef enum
{
  PARSER_PATTERN_NO_OPTS = 0,                  /**< parse the expression after '=' */
  PARSER_PATTERN_BINDING = (1u << 0),          /**< parse BindingPattern */
  PARSER_PATTERN_TARGET_ON_STACK = (1u << 1),  /**< assignment target is the topmost element on the stack */
  PARSER_PATTERN_TARGET_DEFAULT = (1u << 2),   /**< perform default value comparison for assignment target */
  PARSER_PATTERN_NESTED_PATTERN = (1u << 3),   /**< parse pattern inside a pattern */
  PARSER_PATTERN_LET = (1u << 4),              /**< pattern is a let declaration */
  PARSER_PATTERN_CONST = (1u << 5),            /**< pattern is a const declaration */
  PARSER_PATTERN_LOCAL = (1u << 6),            /**< pattern is a local (catch parameter) declaration */
  PARSER_PATTERN_REST_ELEMENT = (1u << 7),     /**< parse rest array / object element */
  PARSER_PATTERN_HAS_REST_ELEMENT = (1u << 8), /**< object literal rest element will be present */
  PARSER_PATTERN_ARGUMENTS = (1u << 9),        /**< parse arguments binding */
} parser_pattern_flags_t;

/**
 * Check type for scanner_is_context_needed function.
 */
typedef enum
{
  PARSER_CHECK_BLOCK_CONTEXT,                  /**< check block context */
#if JERRY_ESNEXT
  PARSER_CHECK_GLOBAL_CONTEXT,                 /**< check global context */
  PARSER_CHECK_FUNCTION_CONTEXT,               /**< check function context */
#endif /* JERRY_ESNEXT */
} parser_check_context_type_t;

#if JERRY_ESNEXT

/**
 * Class field bits.
 */
typedef enum
{
  PARSER_CLASS_FIELD_END = (1u << 0),          /**< last class field */
  PARSER_CLASS_FIELD_NORMAL = (1u << 1),       /**< normal (non-computed) class field */
  PARSER_CLASS_FIELD_INITIALIZED = (1u << 2),  /**< class field is initialized */
  PARSER_CLASS_FIELD_STATIC = (1u << 3),       /**< static class field */
} parser_class_field_type_t;

#endif /* JERRY_ESNEXT */

/**
 * Mask for strict mode code
 */
#define PARSER_STRICT_MODE_MASK 0x1

/**
 * Shorthand for function closure definition
 */
#define PARSER_FUNCTION_CLOSURE (PARSER_IS_FUNCTION | PARSER_IS_CLOSURE)

#if PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX
/**
 * Maximum number of bytes for branch target.
 */
#define PARSER_MAX_BRANCH_LENGTH 2
#else /* PARSER_MAXIMUM_CODE_SIZE > UINT16_MAX */
/**
 * Maximum number of bytes for branch target.
 */
#define PARSER_MAX_BRANCH_LENGTH 3
#endif /* PARSER_MAXIMUM_CODE_SIZE <= UINT16_MAX */

#if JERRY_ESNEXT
/**
 * Offset of PARSER_ALLOW_SUPER
 */
#define PARSER_SAVED_FLAGS_OFFSET \
  JERRY_LOG2 (PARSER_ALLOW_SUPER)

/**
 * Mask of saved flags
 */
#define PARSER_SAVED_FLAGS_MASK \
  ((1 << (JERRY_LOG2 (PARSER_ALLOW_NEW_TARGET) - JERRY_LOG2 (PARSER_ALLOW_SUPER) + 1)) - 1)

/**
 * Get class option bits from parser_general_flags_t
 */
#define PARSER_SAVE_STATUS_FLAGS(opts) \
  ((uint16_t) (((opts) >> PARSER_SAVED_FLAGS_OFFSET) & PARSER_SAVED_FLAGS_MASK))

/**
 * Mask for get class option bits from ecma_parse_opts_t
 */
#define PARSER_RESTORE_STATUS_FLAGS_MASK \
  (((ECMA_PARSE_ALLOW_NEW_TARGET << 1) - 1) - (ECMA_PARSE_ALLOW_SUPER - 1))

/**
 * Shift for get class option bits from ecma_parse_opts_t
 */
#define PARSER_RESTORE_STATUS_FLAGS_SHIFT \
  (JERRY_LOG2 (PARSER_ALLOW_SUPER) - JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER))

/**
 * Get class option bits from ecma_parse_opts_t
 */
#define PARSER_RESTORE_STATUS_FLAGS(opts) \
  (((opts) & PARSER_RESTORE_STATUS_FLAGS_MASK) << PARSER_RESTORE_STATUS_FLAGS_SHIFT)

/**
 * All flags that affect exotic arguments object creation.
 */
#define PARSER_ARGUMENTS_RELATED_FLAGS \
  (PARSER_ARGUMENTS_NEEDED | PARSER_FUNCTION_HAS_COMPLEX_ARGUMENT | PARSER_IS_STRICT)

/**
 * Get the corresponding eval flag for a ecma_parse_opts_t flag
 */
#define PARSER_GET_EVAL_FLAG(type) \
  ((type) >> JERRY_LOG2 (ECMA_PARSE_ALLOW_SUPER))

/**
 * Check non-generator async functions
 */
#define PARSER_IS_NORMAL_ASYNC_FUNCTION(status_flags) \
  (((status_flags) & (PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION)) == PARSER_IS_ASYNC_FUNCTION)

#else /* !JERRY_ESNEXT */

/**
 * All flags that affect exotic arguments object creation.
 */
#define PARSER_ARGUMENTS_RELATED_FLAGS \
  (PARSER_ARGUMENTS_NEEDED | PARSER_IS_STRICT)

#endif /* JERRY_ESNEXT */

/* Checks whether unmapped arguments are needed. */
#define PARSER_NEEDS_MAPPED_ARGUMENTS(status_flags) \
  (((status_flags) & PARSER_ARGUMENTS_RELATED_FLAGS) == PARSER_ARGUMENTS_NEEDED)

/* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */
#define PARSER_CBC_STREAM_PAGE_SIZE \
  ((uint32_t) (64 - sizeof (void *)))

/* Defines the size of the max page. */
#define PARSER_STACK_PAGE_SIZE \
  ((uint32_t) (((sizeof (void *) > 4) ? 128 : 64) - sizeof (void *)))

/* Avoid compiler warnings for += operations. */
#define PARSER_PLUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) + (value))
#define PARSER_MINUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) - (value))
#define PARSER_PLUS_EQUAL_LC(base, value) (base) = (parser_line_counter_t) ((base) + (value))

/**
 * Argument for a compact-byte code.
 */
typedef struct
{
  uint16_t literal_index;                     /**< literal index argument */
  uint16_t value;                             /**< other argument (second literal or byte). */
  uint16_t third_literal_index;               /**< literal index argument */
  uint8_t literal_type;                       /**< last literal type */
  uint8_t literal_keyword_type;               /**< last literal keyword type */
} cbc_argument_t;

/* Useful parser macros. */

#define PARSER_CBC_UNAVAILABLE CBC_EXT_OPCODE

#define PARSER_TO_EXT_OPCODE(opcode) ((uint16_t) ((opcode) + 256))
#define PARSER_GET_EXT_OPCODE(opcode) ((opcode) - 256)
#define PARSER_IS_BASIC_OPCODE(opcode) ((opcode) < 256)
#define PARSER_IS_PUSH_LITERAL(opcode) \
  ((opcode) == CBC_PUSH_LITERAL \
   || (opcode) == CBC_PUSH_TWO_LITERALS \
   || (opcode) == CBC_PUSH_THREE_LITERALS)
#define PARSER_IS_PUSH_NUMBER(opcode) \
  ((opcode) >= CBC_PUSH_NUMBER_0 \
   && (opcode) <= CBC_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE)

#define PARSER_IS_MUTABLE_PUSH_LITERAL(opcode) \
  ((opcode) >= CBC_PUSH_LITERAL && (opcode) <= CBC_PUSH_THIS_LITERAL)

#define PARSER_IS_PUSH_LITERALS_WITH_THIS(opcode) \
  ((opcode) >= CBC_PUSH_LITERAL && (opcode) <= CBC_PUSH_THREE_LITERALS)

#define PARSER_IS_PUSH_PROP(opcode) \
  ((opcode) >= CBC_PUSH_PROP && (opcode) <= CBC_PUSH_PROP_THIS_LITERAL)

#define PARSER_IS_PUSH_PROP_LITERAL(opcode) \
  ((opcode) >= CBC_PUSH_PROP_LITERAL && (opcode) <= CBC_PUSH_PROP_THIS_LITERAL)

#define PARSER_PUSH_LITERAL_TO_PUSH_PROP_LITERAL(opcode) \
  (uint16_t) ((opcode) + (CBC_PUSH_PROP_LITERAL - CBC_PUSH_LITERAL))

#define PARSER_PUSH_PROP_LITERAL_TO_PUSH_LITERAL(opcode) \
  (uint16_t) ((opcode) - (CBC_PUSH_PROP_LITERAL - CBC_PUSH_LITERAL))

#define PARSER_PUSH_PROP_TO_PUSH_PROP_REFERENCE(opcode) \
  (uint16_t) ((opcode) + (CBC_PUSH_PROP_REFERENCE - CBC_PUSH_PROP))

#define PARSER_PUSH_PROP_REFERENCE_TO_PUSH_PROP(opcode) \
  (uint16_t) ((opcode) - (CBC_PUSH_PROP_REFERENCE - CBC_PUSH_PROP))

#define PARSER_GET_LITERAL(literal_index) \
  ((lexer_literal_t *) parser_list_get (&context_p->literal_pool, (literal_index)))

#define PARSER_TO_BINARY_OPERATION_WITH_RESULT(opcode) \
  (PARSER_TO_EXT_OPCODE(opcode) - CBC_ASSIGN_ADD + CBC_EXT_ASSIGN_ADD_PUSH_RESULT)

#define PARSER_TO_BINARY_OPERATION_WITH_BLOCK(opcode) \
  ((uint16_t) (PARSER_TO_EXT_OPCODE(opcode) - CBC_ASSIGN_ADD + CBC_EXT_ASSIGN_ADD_BLOCK))

#define PARSER_GET_FLAGS(op) \
  (PARSER_IS_BASIC_OPCODE (op) ? cbc_flags[(op)] : cbc_ext_flags[PARSER_GET_EXT_OPCODE (op)])

#define PARSER_OPCODE_IS_RETURN(op) \
  ((op) == CBC_RETURN \
   || (op) == CBC_RETURN_FUNCTION_END \
   || (op) == CBC_RETURN_WITH_LITERAL)

#define PARSER_ARGS_EQ(op, types) \
  ((PARSER_GET_FLAGS (op) & CBC_ARG_TYPES) == (types))

/**
 * All data allocated by the parser is
 * stored in parser_data_pages in the memory.
 */
typedef struct parser_mem_page_t
{
  struct parser_mem_page_t *next_p;           /**< next page */
  uint8_t bytes[];                            /**< memory bytes, C99 flexible array member */
} parser_mem_page_t;

/**
 * Structure for managing parser memory.
 */
typedef struct
{
  parser_mem_page_t *first_p;                 /**< first allocated page */
  parser_mem_page_t *last_p;                  /**< last allocated page */
  uint32_t last_position;                     /**< position of the last allocated byte */
} parser_mem_data_t;

/**
 * Parser memory list.
 */
typedef struct
{
  parser_mem_data_t data;                     /**< storage space */
  uint32_t page_size;                         /**< size of each page */
  uint32_t item_size;                         /**< size of each item */
  uint32_t item_count;                        /**< number of items on each page */
} parser_list_t;

/**
 * Iterator for parser memory list.
 */
typedef struct
{
  parser_list_t *list_p;                      /**< parser list */
  parser_mem_page_t *current_p;               /**< currently processed page */
  size_t current_position;                    /**< current position on the page */
} parser_list_iterator_t;

/**
 * Parser memory stack.
 */
typedef struct
{
  parser_mem_data_t data;                     /**< storage space */
  parser_mem_page_t *free_page_p;             /**< space for fast allocation */
} parser_stack_t;

/**
 * Iterator for parser memory stack.
 */
typedef struct
{
  parser_mem_page_t *current_p;               /**< currently processed page */
  size_t current_position;                    /**< current position on the page */
} parser_stack_iterator_t;

/**
 * Branch type.
 */
typedef struct
{
  parser_mem_page_t *page_p;                  /**< branch location page */
  uint32_t offset;                            /**< branch location offset */
} parser_branch_t;

/**
 * Branch chain type.
 */
typedef struct parser_branch_node_t
{
  struct parser_branch_node_t *next_p;        /**< next linked list node */
  parser_branch_t branch;                     /**< branch */
} parser_branch_node_t;

/**
 * Items of scope stack.
 */
typedef struct
{
  uint16_t map_from;                          /**< original literal index */
  uint16_t map_to;                            /**< encoded register or literal index and flags */
} parser_scope_stack_t;

/**
 * This item represents a function literal in the scope stack.
 *
 * When map_from == PARSER_SCOPE_STACK_FUNC:
 *   map_to represents the literal reserved for a function literal
 *   Note: the name of the function is the previous value in the scope stack
 *   Note: map_to is not encoded in this case
 */
#define PARSER_SCOPE_STACK_FUNC 0xffff

#if JERRY_ESNEXT

/**
 * Mask for decoding the register index of map_to
 */
#define PARSER_SCOPE_STACK_REGISTER_MASK 0x3fff

/**
 * Function statements with the name specified
 * in map_from should not be copied to global scope.
 */
#define PARSER_SCOPE_STACK_NO_FUNCTION_COPY 0x8000

/**
 * The scope stack item represents a const binding stored in register
 */
#define PARSER_SCOPE_STACK_IS_CONST_REG 0x4000

/**
 * The scope stack item represents a binding which has already created with ECMA_VALUE_UNINITIALIZED
 */
#define PARSER_SCOPE_STACK_IS_LOCAL_CREATED (PARSER_SCOPE_STACK_IS_CONST_REG)

#endif /* JERRY_ESNEXT */

/**
 * Starting literal index for registers.
 */
#define PARSER_REGISTER_START 0x8000

/**
 * Invalid literal index
 */
#define PARSER_INVALID_LITERAL_INDEX UINT16_MAX

/**
 * Lastly emitted opcode is not a function literal
 */
#define PARSER_NOT_FUNCTION_LITERAL PARSER_INVALID_LITERAL_INDEX

/**
 * Lastly emitted opcode is not a named function literal
 */
#define PARSER_NAMED_FUNCTION (uint16_t) (PARSER_NOT_FUNCTION_LITERAL - 1)

/**
 * Lastly emitted opcode is not an anonymous class literal
 */
#define PARSER_ANONYMOUS_CLASS (uint16_t) (PARSER_NAMED_FUNCTION - 1)

/* Forward definitions for js-scanner-internal.h. */
struct scanner_context_t;
typedef struct scanner_context_t scanner_context_t;

#if JERRY_DEBUGGER
/**
 * Extra information for each breakpoint.
 */
typedef struct
{
  uint32_t value;                             /**< line or offset of the breakpoint */
} parser_breakpoint_info_t;

/**
 * Maximum number of breakpoint info.
 */
#define PARSER_MAX_BREAKPOINT_INFO_COUNT \
  (JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE / sizeof (parser_breakpoint_info_t))

#endif /* JERRY_DEBUGGER */

#if JERRY_LINE_INFO

typedef struct
{
  parser_mem_page_t *last_page_p;             /**< last page of line info data */
  uint32_t byte_code_position;                /**< last byte code position */
  parser_line_counter_t line;                 /**< last line */
  parser_line_counter_t column;               /**< last column */
} parser_line_info_data_t;

#endif /* JERRY_LINE_INFO */

/**
 * Those members of a context which needs
 * to be saved when a sub-function is parsed.
 */
typedef struct parser_saved_context_t
{
  /* Parser members. */
  uint32_t status_flags;                      /**< parsing options */
  uint16_t stack_depth;                       /**< current stack depth */
  uint16_t stack_limit;                       /**< maximum stack depth */
  struct parser_saved_context_t *prev_context_p; /**< last saved context */
  parser_stack_iterator_t last_statement;     /**< last statement position */

  /* Literal types */
  uint16_t argument_count;                    /**< number of function arguments */
#if JERRY_ESNEXT
  uint16_t argument_length;                   /**< length property of arguments */
#endif /* JERRY_ESNEXT */
  uint16_t register_count;                    /**< number of registers */
  uint16_t literal_count;                     /**< number of literals */

  /* Memory storage members. */
  parser_mem_data_t byte_code;                /**< byte code buffer */
  uint32_t byte_code_size;                    /**< byte code size for branches */
  parser_mem_data_t literal_pool_data;        /**< literal list */
  parser_scope_stack_t *scope_stack_p;        /**< scope stack */
  uint16_t scope_stack_size;                  /**< size of scope stack */
  uint16_t scope_stack_top;                   /**< preserved top of scope stack */
  uint16_t scope_stack_reg_top;               /**< preserved top register of scope stack */
#if JERRY_ESNEXT
  uint16_t scope_stack_global_end;            /**< end of global declarations of a function */
  ecma_value_t tagged_template_literal_cp;    /**< compessed pointer to the tagged template literal collection */
#endif /* JERRY_ESNEXT */

#ifndef JERRY_NDEBUG
  uint16_t context_stack_depth;               /**< current context stack depth */
#endif /* !JERRY_NDEBUG */

#if JERRY_LINE_INFO
  parser_line_info_data_t *line_info_p;       /**< line info data */
#endif /* JERRY_LINE_INFO */

#if JERRY_FUNCTION_TO_STRING
  const uint8_t *function_start_p;            /**< start position of the current function */
#endif /* JERRY_FUNCTION_TO_STRING */
} parser_saved_context_t;

/**
 * Shared parser context.
 */
typedef struct
{
  PARSER_TRY_CONTEXT (try_buffer);            /**< try_buffer */
  parser_error_t error;                       /**< error code */
  /** Union for rarely used members. */
  union
  {
    void *allocated_buffer_p;                 /**< dinamically allocated buffer
                                               *   which needs to be freed on error */
    scanner_context_t *scanner_context_p;     /**< scanner context for the pre-scanner */
  } u;
  uint32_t allocated_buffer_size;             /**< size of the dinamically allocated buffer */

  /* Parser members. */
  uint32_t status_flags;                      /**< status flags */
  uint32_t global_status_flags;               /**< global status flags */
  uint16_t stack_depth;                       /**< current stack depth */
  uint16_t stack_limit;                       /**< maximum stack depth */
  const jerry_parse_options_t *options_p;     /**< parse options */
  parser_saved_context_t *last_context_p;     /**< last saved context */
  parser_stack_iterator_t last_statement;     /**< last statement position */
  cbc_script_t *script_p;                     /**< current script */
  const uint8_t *source_start_p;              /**< source start */
  lit_utf8_size_t source_size;                /**< source size */
  const uint8_t *arguments_start_p;           /**< function argument list start */
  lit_utf8_size_t arguments_size;             /**< function argument list size */
  ecma_value_t script_value;                  /**< current script as value */
  ecma_value_t argument_list;                 /**< current argument list as value */
  ecma_value_t user_value;                    /**< current user value */

#if JERRY_MODULE_SYSTEM
  ecma_module_names_t *module_names_p;        /**< import / export names that is being processed */
  lexer_literal_t *module_identifier_lit_p;   /**< the literal for the identifier of the current element */
#endif /* JERRY_MODULE_SYSTEM */

  /* Lexer members. */
  lexer_token_t token;                        /**< current token */
  lexer_lit_object_t lit_object;              /**< current literal object */
  const uint8_t *source_p;                    /**< next source byte */
  const uint8_t *source_end_p;                /**< last source byte */
  parser_line_counter_t line;                 /**< current line */
  parser_line_counter_t column;               /**< current column */

  /* Scanner members. */
  scanner_info_t *next_scanner_info_p;        /**< next scanner info block */
  scanner_info_t *active_scanner_info_p;      /**< currently active scanner info block */
  scanner_info_t *skipped_scanner_info_p;     /**< next scanner info block */
  scanner_info_t *skipped_scanner_info_end_p; /**< currently active scanner info block */

  /* Compact byte code members. */
  cbc_argument_t last_cbc;                    /**< argument of the last cbc */
  uint16_t last_cbc_opcode;                   /**< opcode of the last cbc */

  /* Literal types */
  uint16_t argument_count;                    /**< number of function arguments */
#if JERRY_ESNEXT
  uint16_t argument_length;                   /**< length property of arguments */
#endif /* JERRY_ESNEXT */
  uint16_t register_count;                    /**< number of registers */
  uint16_t literal_count;                     /**< number of literals */

  /* Memory storage members. */
  parser_mem_data_t byte_code;                /**< byte code buffer */
  uint32_t byte_code_size;                    /**< current byte code size for branches */
  parser_list_t literal_pool;                 /**< literal list */
  parser_mem_data_t stack;                    /**< storage space */
  parser_scope_stack_t *scope_stack_p;        /**< scope stack */
  parser_mem_page_t *free_page_p;             /**< space for fast allocation */
  uint16_t scope_stack_size;                  /**< size of scope stack */
  uint16_t scope_stack_top;                   /**< current top of scope stack */
  uint16_t scope_stack_reg_top;               /**< current top register of scope stack */
#if JERRY_ESNEXT
  uint16_t scope_stack_global_end;            /**< end of global declarations of a function */
  ecma_value_t tagged_template_literal_cp;    /**< compessed pointer to the tagged template literal collection */
#endif /* JERRY_ESNEXT */
  uint8_t stack_top_uint8;                    /**< top byte stored on the stack */

#ifndef JERRY_NDEBUG
  /* Variables for debugging / logging. */
  uint16_t context_stack_depth;               /**< current context stack depth */
#endif /* !JERRY_NDEBUG */

#if JERRY_PARSER_DUMP_BYTE_CODE
  int is_show_opcodes;                        /**< show opcodes */
  uint32_t total_byte_code_size;              /**< total byte code size */
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */

#if JERRY_DEBUGGER
  parser_breakpoint_info_t breakpoint_info[PARSER_MAX_BREAKPOINT_INFO_COUNT]; /**< breakpoint info list */
  uint16_t breakpoint_info_count;             /**< current breakpoint index */
  parser_line_counter_t last_breakpoint_line; /**< last line where breakpoint has been inserted */
#endif /* JERRY_DEBUGGER */

#if JERRY_LINE_INFO
  parser_line_info_data_t *line_info_p;       /**< line info data */
#endif /* JERRY_LINE_INFO */

#if JERRY_FUNCTION_TO_STRING
  const uint8_t *function_start_p;            /**< start position of the function which will be parsed */
  const uint8_t *function_end_p;              /**< end position of the current function */
#endif /* JERRY_FUNCTION_TO_STRING */
} parser_context_t;

/**
 * @}
 * @}
 * @}
 *
 * \addtogroup mem Memory allocation
 * @{
 *
 * \addtogroup mem_parser Parser memory manager
 * @{
 */

/* Memory management.
 * Note: throws an error if unsuccessful. */
void *parser_malloc (parser_context_t *context_p, size_t size);
void parser_free (void *ptr, size_t size);
void *parser_malloc_local (parser_context_t *context_p, size_t size);
void parser_free_local (void *ptr, size_t size);
void parser_free_allocated_buffer (parser_context_t *context_p);

/* Parser byte stream. */

void parser_cbc_stream_init (parser_mem_data_t *data_p);
void parser_cbc_stream_free (parser_mem_data_t *data_p);
void parser_cbc_stream_alloc_page (parser_context_t *context_p, parser_mem_data_t *data_p);

/* Parser list. Ensures pointer alignment. */

void parser_list_init (parser_list_t *list_p, uint32_t item_size, uint32_t item_count);
void parser_list_free (parser_list_t *list_p);
void parser_list_reset (parser_list_t *list_p);
void *parser_list_append (parser_context_t *context_p, parser_list_t *list_p);
void *parser_list_get (parser_list_t *list_p, size_t index);
void parser_list_iterator_init (parser_list_t *list_p, parser_list_iterator_t *iterator_p);
void *parser_list_iterator_next (parser_list_iterator_t *iterator_p);

/* Parser stack. Optimized for pushing bytes.
 * Pop functions never throws error. */

void parser_stack_init (parser_context_t *context_p);
void parser_stack_free (parser_context_t *context_p);
void parser_stack_push_uint8 (parser_context_t *context_p, uint8_t uint8_value);
void parser_stack_pop_uint8 (parser_context_t *context_p);
void parser_stack_change_last_uint8 (parser_context_t *context_p, uint8_t new_value);
uint8_t *parser_stack_get_prev_uint8 (parser_context_t *context_p);
void parser_stack_push_uint16 (parser_context_t *context_p, uint16_t uint16_value);
uint16_t parser_stack_pop_uint16 (parser_context_t *context_p);
void parser_stack_push (parser_context_t *context_p, const void *data_p, uint32_t length);
void parser_stack_pop (parser_context_t *context_p, void *data_p, uint32_t length);
void parser_stack_iterator_init (parser_context_t *context_p, parser_stack_iterator_t *iterator);
uint8_t parser_stack_iterator_read_uint8 (parser_stack_iterator_t *iterator);
void parser_stack_iterator_skip (parser_stack_iterator_t *iterator, size_t length);
void parser_stack_iterator_read (parser_stack_iterator_t *iterator, void *data_p, size_t length);
void parser_stack_iterator_write (parser_stack_iterator_t *iterator, const void *data_p, size_t length);

/**
 * @}
 * @}
 *
 * \addtogroup parser Parser
 * @{
 *
 * \addtogroup jsparser JavaScript
 * @{
 *
 * \addtogroup jsparser_utils Utility
 * @{
 */

/* Compact byte code emitting functions. */

void parser_flush_cbc (parser_context_t *context_p);
void parser_emit_cbc (parser_context_t *context_p, uint16_t opcode);
void parser_emit_cbc_literal (parser_context_t *context_p, uint16_t opcode, uint16_t literal_index);
void parser_emit_cbc_literal_value (parser_context_t *context_p, uint16_t opcode, uint16_t literal_index,
                                    uint16_t value);
void parser_emit_cbc_literal_from_token (parser_context_t *context_p, uint16_t opcode);
void parser_emit_cbc_call (parser_context_t *context_p, uint16_t opcode, size_t call_arguments);
void parser_emit_cbc_push_number (parser_context_t *context_p, bool is_negative_number);
void parser_emit_cbc_forward_branch (parser_context_t *context_p, uint16_t opcode, parser_branch_t *branch_p);
parser_branch_node_t *parser_emit_cbc_forward_branch_item (parser_context_t *context_p, uint16_t opcode,
                                                           parser_branch_node_t *next_p);
void parser_emit_cbc_backward_branch (parser_context_t *context_p, uint16_t opcode, uint32_t offset);
ecma_string_t *parser_new_ecma_string_from_literal (lexer_literal_t *literal_p);
void parser_set_branch_to_current_position (parser_context_t *context_p, parser_branch_t *branch_p);
void parser_set_breaks_to_current_position (parser_context_t *context_p, parser_branch_node_t *current_p);
void parser_set_continues_to_current_position (parser_context_t *context_p, parser_branch_node_t *current_p);

/* Convenience macros. */
#define parser_emit_cbc_ext(context_p, opcode) \
  parser_emit_cbc ((context_p), PARSER_TO_EXT_OPCODE (opcode))
#define parser_emit_cbc_ext_literal(context_p, opcode, literal_index) \
  parser_emit_cbc_literal ((context_p), PARSER_TO_EXT_OPCODE (opcode), (literal_index))
#define parser_emit_cbc_ext_literal_from_token(context_p, opcode) \
  parser_emit_cbc_literal_from_token ((context_p), PARSER_TO_EXT_OPCODE (opcode))
#define parser_emit_cbc_ext_call(context_p, opcode, call_arguments) \
  parser_emit_cbc_call ((context_p), PARSER_TO_EXT_OPCODE (opcode), (call_arguments))
#define parser_emit_cbc_ext_call(context_p, opcode, call_arguments) \
  parser_emit_cbc_call ((context_p), PARSER_TO_EXT_OPCODE (opcode), (call_arguments))
#define parser_emit_cbc_ext_forward_branch(context_p, opcode, branch_p) \
  parser_emit_cbc_forward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (branch_p))
#define parser_emit_cbc_ext_backward_branch(context_p, opcode, offset) \
  parser_emit_cbc_backward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (offset))

#if JERRY_ESNEXT
void parser_reverse_class_fields (parser_context_t *context_p, size_t fields_size);
#endif /* JERRY_ESNEXT */

/**
 * @}
 *
 * \addtogroup jsparser_lexer Lexer
 * @{
 */

/* Lexer functions */

void lexer_next_token (parser_context_t *context_p);
bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t character);
bool lexer_check_next_characters (parser_context_t *context_p, lit_utf8_byte_t character1,
                                  lit_utf8_byte_t character2);
uint8_t lexer_consume_next_character (parser_context_t *context_p);
bool lexer_check_post_primary_exp (parser_context_t *context_p);
#if JERRY_ESNEXT
void lexer_skip_empty_statements (parser_context_t *context_p);
bool lexer_check_arrow (parser_context_t *context_p);
bool lexer_check_arrow_param (parser_context_t *context_p);
bool lexer_check_yield_no_arg (parser_context_t *context_p);
bool lexer_consume_generator (parser_context_t *context_p);
bool lexer_consume_assign (parser_context_t *context_p);
void lexer_update_await_yield (parser_context_t *context_p, uint32_t status_flags);
#endif /* JERRY_ESNEXT */
void lexer_parse_string (parser_context_t *context_p, lexer_string_options_t opts);
void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type);
bool lexer_scan_identifier (parser_context_t *context_p);
void lexer_check_property_modifier (parser_context_t *context_p);
void lexer_convert_ident_to_cesu8 (uint8_t *destination_p, const uint8_t *source_p, prop_length_t length);

const uint8_t *lexer_convert_literal_to_chars (parser_context_t *context_p,  const lexer_lit_location_t *literal_p,
                                               uint8_t *local_byte_array_p, lexer_string_options_t opts);
void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts);
lexer_literal_t *lexer_construct_unused_literal (parser_context_t *context_p);
void lexer_construct_literal_object (parser_context_t *context_p, const lexer_lit_location_t *lit_location_p,
                                     uint8_t literal_type);
bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
void lexer_convert_push_number_to_push_literal (parser_context_t *context_p);
uint16_t lexer_construct_function_object (parser_context_t *context_p, uint32_t extra_status_flags);
void lexer_construct_regexp_object (parser_context_t *context_p, bool parse_only);
bool lexer_compare_identifier_to_string (const lexer_lit_location_t *left_p, const uint8_t *right_p, size_t size);
bool lexer_compare_identifiers (parser_context_t *context_p, const lexer_lit_location_t *left_p,
                                const lexer_lit_location_t *right_p);
bool lexer_current_is_literal (parser_context_t *context_p, const lexer_lit_location_t *right_ident_p);
bool lexer_string_is_use_strict (parser_context_t *context_p);
bool lexer_string_is_directive (parser_context_t *context_p);
#if JERRY_ESNEXT
bool lexer_token_is_identifier (parser_context_t *context_p, const char *identifier_p,
                                size_t identifier_length);
bool lexer_token_is_let (parser_context_t *context_p);
bool lexer_token_is_async (parser_context_t *context_p);
#endif /* JERRY_ESNEXT */
bool lexer_compare_literal_to_string (parser_context_t *context_p, const char *string_p, size_t string_length);
void lexer_init_line_info (parser_context_t *context_p);
uint8_t lexer_convert_binary_lvalue_token_to_binary (uint8_t token);

/**
 * @}
 *
 * \addtogroup jsparser_expr Expression parser
 * @{
 */

/* Parser functions. */

void parser_parse_block_expression (parser_context_t *context_p, int options);
void parser_parse_expression_statement (parser_context_t *context_p, int options);
void parser_parse_expression (parser_context_t *context_p, int options);
#if JERRY_ESNEXT
void parser_parse_class (parser_context_t *context_p, bool is_statement);
void parser_parse_initializer (parser_context_t *context_p, parser_pattern_flags_t flags);
void parser_parse_initializer_by_next_char (parser_context_t *context_p, parser_pattern_flags_t flags);
#endif /* JERRY_ESNEXT */

/**
 * @}
 *
 * \addtogroup jsparser_scanner Scanner
 * @{
 */

void scanner_release_next (parser_context_t *context_p, size_t size);
void scanner_set_active (parser_context_t *context_p);
void scanner_revert_active (parser_context_t *context_p);
void scanner_release_active (parser_context_t *context_p, size_t size);
void scanner_release_switch_cases (scanner_case_info_t *case_p);
void scanner_seek (parser_context_t *context_p);
void scanner_reverse_info_list (parser_context_t *context_p);
void scanner_cleanup (parser_context_t *context_p);

bool scanner_is_context_needed (parser_context_t *context_p, parser_check_context_type_t check_type);
#if JERRY_ESNEXT
bool scanner_try_scan_new_target (parser_context_t *context_p);
void scanner_check_variables (parser_context_t *context_p);
#endif /* JERRY_ESNEXT */
void scanner_create_variables (parser_context_t *context_p, uint32_t option_flags);

void scanner_get_location (scanner_location_t *location_p, parser_context_t *context_p);
void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p);
uint16_t scanner_decode_map_to (parser_scope_stack_t *stack_item_p);
#if JERRY_ESNEXT
uint16_t scanner_save_literal (parser_context_t *context_p, uint16_t ident_index);
bool scanner_literal_is_const_reg (parser_context_t *context_p, uint16_t literal_index);
bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_index);
bool scanner_literal_exists (parser_context_t *context_p, uint16_t literal_index);
#endif /* JERRY_ESNEXT */

void scanner_scan_all (parser_context_t *context_p);

/**
 * @}
 *
 * \addtogroup jsparser_stmt Statement parser
 * @{
 */

void parser_parse_statements (parser_context_t *context_p);
void parser_free_jumps (parser_stack_iterator_t iterator);

#if JERRY_MODULE_SYSTEM
/**
 * @}
 *
 * \addtogroup jsparser_stmt Module statement parser
 * @{
 */

extern const lexer_lit_location_t lexer_default_literal;
void parser_module_check_request_place (parser_context_t *context_p);
void parser_module_context_init (parser_context_t *context_p);
void parser_module_append_names (parser_context_t *context_p, ecma_module_names_t **module_names_p);
void parser_module_handle_module_specifier (parser_context_t *context_p, ecma_module_node_t **node_list_p);
void parser_module_handle_requests (parser_context_t *context_p);
void parser_module_parse_export_clause (parser_context_t *context_p);
void parser_module_parse_import_clause (parser_context_t *context_p);
void parser_module_set_default (parser_context_t *context_p);
bool parser_module_check_duplicate_import (parser_context_t *context_p, ecma_string_t *local_name_p);
bool parser_module_check_duplicate_export (parser_context_t *context_p, ecma_string_t *export_name_p);
void parser_module_append_export_name (parser_context_t *context_p);
void parser_module_add_names_to_node (parser_context_t *context_p,
                                      ecma_string_t *imex_name_p,
                                      ecma_string_t *local_name_p);

#endif /* JERRY_MODULE_SYSTEM */

/*
 * @}
 *
 * \addtogroup jsparser_line_info_create Create line info data
 * @{
 */

#if JERRY_LINE_INFO
void parser_line_info_free (parser_line_info_data_t *line_info_p);
void parser_line_info_append (parser_context_t *context_p,
                              parser_line_counter_t line, parser_line_counter_t column);
uint8_t *parser_line_info_generate (parser_context_t *context_p);
#endif /* JERRY_LINE_INFO */

/**
 * @}
 *
 * \addtogroup jsparser_parser Parser
 * @{
 */

ecma_compiled_code_t *parser_parse_function (parser_context_t *context_p, uint32_t status_flags);
#if JERRY_ESNEXT
ecma_compiled_code_t *parser_parse_arrow_function (parser_context_t *context_p, uint32_t status_flags);
ecma_compiled_code_t *parser_parse_class_fields (parser_context_t *context_p);
void parser_set_function_name (parser_context_t *context_p, uint16_t function_literal_index, uint16_t name_index,
                               uint32_t status_flags);
void parser_compiled_code_set_function_name (parser_context_t *context_p, ecma_compiled_code_t *bytecode_p,
                                             uint16_t name_index, uint32_t status_flags);
uint16_t parser_check_anonymous_function_declaration (parser_context_t *context_p);
#endif /* JERRY_ESNEXT */

/* Error management. */

void parser_raise_error (parser_context_t *context_p, parser_error_t error);

/* Debug functions. */

#if JERRY_DEBUGGER

void parser_append_breakpoint_info (parser_context_t *context_p, jerry_debugger_header_type_t type, uint32_t value);

#endif /* JERRY_DEBUGGER */

#if JERRY_PARSER_DUMP_BYTE_CODE
void util_print_cbc (ecma_compiled_code_t *compiled_code_p);
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */

/**
 * @}
 * @}
 * @}
 */

#endif /* !JS_PARSER_INTERNAL_H */
