/* * Copyright (C) Igor Sysoev * Copyright (C) NGINX, Inc. */ #ifndef _NJS_LEXER_H_INCLUDED_ #define _NJS_LEXER_H_INCLUDED_ typedef enum { NJS_TOKEN_ERROR = -1, NJS_TOKEN_ILLEGAL = 0, NJS_TOKEN_END, NJS_TOKEN_SPACE, NJS_TOKEN_LINE_END, NJS_TOKEN_DOUBLE_QUOTE, NJS_TOKEN_SINGLE_QUOTE, NJS_TOKEN_OPEN_PARENTHESIS, NJS_TOKEN_CLOSE_PARENTHESIS, NJS_TOKEN_OPEN_BRACKET, NJS_TOKEN_CLOSE_BRACKET, NJS_TOKEN_OPEN_BRACE, NJS_TOKEN_CLOSE_BRACE, NJS_TOKEN_COMMA, NJS_TOKEN_DOT, NJS_TOKEN_ELLIPSIS, NJS_TOKEN_SEMICOLON, NJS_TOKEN_COLON, NJS_TOKEN_CONDITIONAL, NJS_TOKEN_COMMENT, NJS_TOKEN_ASSIGNMENT, NJS_TOKEN_ARROW, NJS_TOKEN_ADDITION_ASSIGNMENT, NJS_TOKEN_SUBTRACTION_ASSIGNMENT, NJS_TOKEN_MULTIPLICATION_ASSIGNMENT, NJS_TOKEN_EXPONENTIATION_ASSIGNMENT, NJS_TOKEN_DIVISION_ASSIGNMENT, NJS_TOKEN_REMAINDER_ASSIGNMENT, NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT, NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT, NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT, NJS_TOKEN_BITWISE_OR_ASSIGNMENT, NJS_TOKEN_BITWISE_XOR_ASSIGNMENT, NJS_TOKEN_BITWISE_AND_ASSIGNMENT, NJS_TOKEN_INCREMENT, NJS_TOKEN_DECREMENT, NJS_TOKEN_POST_INCREMENT, NJS_TOKEN_POST_DECREMENT, #define NJS_TOKEN_LAST_ASSIGNMENT NJS_TOKEN_POST_DECREMENT NJS_TOKEN_EQUAL, NJS_TOKEN_STRICT_EQUAL, NJS_TOKEN_NOT_EQUAL, NJS_TOKEN_STRICT_NOT_EQUAL, NJS_TOKEN_ADDITION, NJS_TOKEN_UNARY_PLUS, NJS_TOKEN_SUBTRACTION, NJS_TOKEN_UNARY_NEGATION, NJS_TOKEN_MULTIPLICATION, NJS_TOKEN_EXPONENTIATION, NJS_TOKEN_DIVISION, NJS_TOKEN_REMAINDER, NJS_TOKEN_LESS, NJS_TOKEN_LESS_OR_EQUAL, NJS_TOKEN_LEFT_SHIFT, NJS_TOKEN_GREATER, NJS_TOKEN_GREATER_OR_EQUAL, NJS_TOKEN_RIGHT_SHIFT, NJS_TOKEN_UNSIGNED_RIGHT_SHIFT, NJS_TOKEN_BITWISE_OR, NJS_TOKEN_LOGICAL_OR, NJS_TOKEN_BITWISE_XOR, NJS_TOKEN_BITWISE_AND, NJS_TOKEN_LOGICAL_AND, NJS_TOKEN_BITWISE_NOT, NJS_TOKEN_LOGICAL_NOT, NJS_TOKEN_COALESCE, NJS_TOKEN_IN, NJS_TOKEN_OF, NJS_TOKEN_INSTANCEOF, NJS_TOKEN_TYPEOF, NJS_TOKEN_VOID, NJS_TOKEN_NEW, NJS_TOKEN_DELETE, NJS_TOKEN_YIELD, NJS_TOKEN_DIGIT, NJS_TOKEN_LETTER, #define NJS_TOKEN_FIRST_CONST NJS_TOKEN_NULL NJS_TOKEN_NULL, NJS_TOKEN_NUMBER, NJS_TOKEN_TRUE, NJS_TOKEN_UNDEFINED, NJS_TOKEN_FALSE, NJS_TOKEN_STRING, #define NJS_TOKEN_LAST_CONST NJS_TOKEN_STRING NJS_TOKEN_ESCAPE_STRING, NJS_TOKEN_UNTERMINATED_STRING, NJS_TOKEN_NAME, NJS_TOKEN_OBJECT, NJS_TOKEN_OBJECT_VALUE, NJS_TOKEN_PROPERTY, NJS_TOKEN_PROPERTY_INIT, NJS_TOKEN_PROPERTY_DELETE, NJS_TOKEN_PROPERTY_GETTER, NJS_TOKEN_PROPERTY_SETTER, NJS_TOKEN_PROTO_INIT, NJS_TOKEN_ARRAY, NJS_TOKEN_GRAVE, NJS_TOKEN_TEMPLATE_LITERAL, NJS_TOKEN_FUNCTION, NJS_TOKEN_FUNCTION_DECLARATION, NJS_TOKEN_FUNCTION_EXPRESSION, NJS_TOKEN_FUNCTION_CALL, NJS_TOKEN_METHOD_CALL, NJS_TOKEN_ARGUMENT, NJS_TOKEN_RETURN, NJS_TOKEN_ASYNC_FUNCTION, NJS_TOKEN_ASYNC_FUNCTION_DECLARATION, NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION, NJS_TOKEN_REGEXP, NJS_TOKEN_EXTERNAL, NJS_TOKEN_STATEMENT, NJS_TOKEN_BLOCK, NJS_TOKEN_VAR, NJS_TOKEN_IF, NJS_TOKEN_ELSE, NJS_TOKEN_BRANCHING, NJS_TOKEN_WHILE, NJS_TOKEN_DO, NJS_TOKEN_FOR, NJS_TOKEN_FOR_IN, NJS_TOKEN_BREAK, NJS_TOKEN_CONTINUE, NJS_TOKEN_SWITCH, NJS_TOKEN_CASE, NJS_TOKEN_DEFAULT, NJS_TOKEN_WITH, NJS_TOKEN_TRY, NJS_TOKEN_CATCH, NJS_TOKEN_FINALLY, NJS_TOKEN_THROW, NJS_TOKEN_THIS, NJS_TOKEN_ARGUMENTS, NJS_TOKEN_EVAL, NJS_TOKEN_IMPORT, NJS_TOKEN_EXPORT, NJS_TOKEN_TARGET, NJS_TOKEN_FROM, NJS_TOKEN_META, NJS_TOKEN_AWAIT, NJS_TOKEN_ASYNC, NJS_TOKEN_CLASS, NJS_TOKEN_CONST, NJS_TOKEN_DEBUGGER, NJS_TOKEN_ENUM, NJS_TOKEN_EXTENDS, NJS_TOKEN_IMPLEMENTS, NJS_TOKEN_INTERFACE, NJS_TOKEN_LET, NJS_TOKEN_PACKAGE, NJS_TOKEN_PRIVATE, NJS_TOKEN_PROTECTED, NJS_TOKEN_PUBLIC, NJS_TOKEN_STATIC, NJS_TOKEN_SUPER, NJS_TOKEN_RESERVED, } njs_token_type_t; typedef enum { NJS_KEYWORD_TYPE_UNDEF = 0, NJS_KEYWORD_TYPE_RESERVED = 1, NJS_KEYWORD_TYPE_KEYWORD = 2 } njs_keyword_type_t; typedef struct { njs_token_type_t type; njs_bool_t reserved; } njs_keyword_t; typedef struct { const char *key; const njs_keyword_t *value; size_t length; size_t next; } njs_lexer_keyword_entry_t; typedef struct { njs_token_type_t type:16; njs_keyword_type_t keyword_type; uint32_t line; uint32_t atom_id; njs_str_t text; double number; njs_queue_link_t link; } njs_lexer_token_t; typedef struct { njs_lexer_token_t *token; njs_queue_t preread; /* of njs_lexer_token_t */ u_char *prev_start; njs_token_type_t prev_type:16; njs_token_type_t last_type:16; uint32_t line; njs_str_t file; njs_vm_t *vm; u_char *start; u_char *end; #define NJS_INITIAL_IN_STACK_SIZE 128 uint8_t *in_stack; njs_int_t in_stack_ptr; njs_int_t in_stack_size; } njs_lexer_t; njs_int_t njs_lexer_init(njs_vm_t *vm, njs_lexer_t *lexer, njs_str_t *file, u_char *start, u_char *end); njs_lexer_token_t *njs_lexer_token(njs_lexer_t *lexer, njs_bool_t with_end_line); njs_lexer_token_t *njs_lexer_peek_token(njs_lexer_t *lexer, njs_lexer_token_t *current, njs_bool_t with_end_line); void njs_lexer_consume_token(njs_lexer_t *lexer, unsigned length); njs_int_t njs_lexer_make_token(njs_lexer_t *lexer, njs_lexer_token_t *token); njs_int_t njs_lexer_in_stack_init(njs_lexer_t *lexer); njs_int_t njs_lexer_in_stack_push(njs_lexer_t *lexer); void njs_lexer_in_stack_pop(njs_lexer_t *lexer); void njs_lexer_in_fail_set(njs_lexer_t *lexer, njs_int_t flag); njs_int_t njs_lexer_in_fail_get(njs_lexer_t *lexer); const njs_lexer_keyword_entry_t *njs_lexer_keyword(const u_char *key, size_t length); njs_int_t njs_lexer_keywords(njs_arr_t *array); njs_inline void njs_lexer_entry(njs_vm_t *vm, uintptr_t atom_id, njs_str_t *entry) { njs_value_t value; njs_atom_to_value(vm, &value, atom_id); njs_string_get(vm, &value, entry); } njs_inline njs_bool_t njs_lexer_token_is_keyword(njs_lexer_token_t *token) { return token->keyword_type & NJS_KEYWORD_TYPE_KEYWORD; } njs_inline njs_bool_t njs_lexer_token_is_reserved(njs_lexer_token_t *token) { return token->keyword_type & NJS_KEYWORD_TYPE_RESERVED; } njs_inline njs_bool_t njs_lexer_token_is_name(njs_lexer_token_t *token) { return token->type == NJS_TOKEN_NAME || (!njs_lexer_token_is_reserved(token) && njs_lexer_token_is_keyword(token)); } njs_inline njs_bool_t njs_lexer_token_is_identifier_name(njs_lexer_token_t *token) { return token->type == NJS_TOKEN_NAME || njs_lexer_token_is_keyword(token); } njs_inline njs_bool_t njs_lexer_token_is_binding_identifier(njs_lexer_token_t *token) { switch (token->type) { case NJS_TOKEN_NAME: case NJS_TOKEN_YIELD: case NJS_TOKEN_AWAIT: return 1; default: return (!njs_lexer_token_is_reserved(token) && njs_lexer_token_is_keyword(token)); }; } njs_inline njs_bool_t njs_lexer_token_is_label_identifier(njs_lexer_token_t *token) { return njs_lexer_token_is_binding_identifier(token); } njs_inline njs_bool_t njs_lexer_token_is_identifier_reference(njs_lexer_token_t *token) { return njs_lexer_token_is_binding_identifier(token); } #endif /* _NJS_LEXER_H_INCLUDED_ */