jerryscript/jerry-core/parser/js/js-scanner-util.c
Zoltan Herczeg fbde788d1f Scanner rework. (#3038)
The scanner was an on-demand tool of the parser, which was triggered by certain
statements. After the rework, the scanner runs only once, and collects all information.
This information is passed to the parser.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
2019-09-11 11:15:46 +02:00

291 lines
7.7 KiB
C

/* 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.
*/
#include "js-parser-internal.h"
#if ENABLED (JERRY_PARSER)
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_scanner Scanner
* @{
*/
/**
* Raise a scanner error.
*/
void
scanner_raise_error (parser_context_t *context_p) /**< context */
{
PARSER_THROW (context_p->try_buffer);
/* Should never been reached. */
JERRY_ASSERT (0);
} /* scanner_raise_error */
/**
* Allocate memory for scanner.
*
* @return allocated memory
*/
void *
scanner_malloc (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory block */
{
void *result;
JERRY_ASSERT (size > 0);
result = jmem_heap_alloc_block_null_on_error (size);
if (result == NULL)
{
scanner_cleanup (context_p);
/* This is the only error which specify its reason. */
context_p->error = PARSER_ERR_OUT_OF_MEMORY;
PARSER_THROW (context_p->try_buffer);
}
return result;
} /* scanner_malloc */
/**
* Free memory allocated by scanner_malloc.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_free (void *ptr, /**< pointer to free */
size_t size) /**< size of the memory block */
{
jmem_heap_free_block (ptr, size);
} /* scanner_free */
/**
* Insert a scanner info block into the scanner info chain.
*
* @return newly allocated scanner info
*/
scanner_info_t *
scanner_insert_info (parser_context_t *context_p, /**< context */
const uint8_t *source_p, /**< triggering position */
size_t size) /**< size of the memory block */
{
scanner_info_t *new_scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, size);
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
scanner_info_t *prev_scanner_info_p = NULL;
JERRY_ASSERT (scanner_info_p != NULL);
new_scanner_info_p->source_p = source_p;
while (source_p < scanner_info_p->source_p)
{
prev_scanner_info_p = scanner_info_p;
scanner_info_p = scanner_info_p->next_p;
JERRY_ASSERT (scanner_info_p != NULL);
}
/* Multiple scanner info blocks cannot be assigned to the same position. */
JERRY_ASSERT (source_p != scanner_info_p->source_p);
new_scanner_info_p->next_p = scanner_info_p;
if (JERRY_LIKELY (prev_scanner_info_p == NULL))
{
context_p->next_scanner_info_p = new_scanner_info_p;
}
else
{
prev_scanner_info_p->next_p = new_scanner_info_p;
}
return new_scanner_info_p;
} /* scanner_insert_info */
/**
* Release the next scanner info.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_release_next (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory block */
{
scanner_info_t *next_p = context_p->next_scanner_info_p->next_p;
jmem_heap_free_block (context_p->next_scanner_info_p, size);
context_p->next_scanner_info_p = next_p;
} /* scanner_release_next */
/**
* Set the active scanner info to the next scanner info.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_set_active (parser_context_t *context_p)
{
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
context_p->next_scanner_info_p = scanner_info_p->next_p;
scanner_info_p->next_p = context_p->active_scanner_info_p;
context_p->active_scanner_info_p = scanner_info_p;
} /* scanner_set_active */
/**
* Release the active scanner info.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_release_active (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory block */
{
scanner_info_t *next_p = context_p->active_scanner_info_p->next_p;
jmem_heap_free_block (context_p->active_scanner_info_p, size);
context_p->active_scanner_info_p = next_p;
} /* scanner_release_active */
void
scanner_release_switch_cases (scanner_case_info_t *case_p) /**< case list */
{
while (case_p != NULL)
{
scanner_case_info_t *next_p = case_p->next_p;
jmem_heap_free_block (case_p, sizeof (scanner_case_info_t));
case_p = next_p;
}
} /* scanner_release_switch_cases */
/**
* Reverse the scanner info chain after the scanning is completed.
*/
void
scanner_reverse_info_list (parser_context_t *context_p) /**< context */
{
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
scanner_info_t *last_scanner_info_p = NULL;
if (scanner_info_p->type == SCANNER_TYPE_END)
{
return;
}
do
{
scanner_info_t *next_scanner_info_p = scanner_info_p->next_p;
scanner_info_p->next_p = last_scanner_info_p;
last_scanner_info_p = scanner_info_p;
scanner_info_p = next_scanner_info_p;
}
while (scanner_info_p->type != SCANNER_TYPE_END);
context_p->next_scanner_info_p->next_p = scanner_info_p;
context_p->next_scanner_info_p = last_scanner_info_p;
} /* scanner_reverse_info_list */
/**
* Release unused scanner info blocks.
* This should happen only if an error is occured.
*/
void
scanner_cleanup (parser_context_t *context_p) /**< context */
{
scanner_info_t *scanner_info_p = context_p->next_scanner_info_p;
while (scanner_info_p != NULL)
{
scanner_info_t *next_scanner_info_p = scanner_info_p->next_p;
size_t size = sizeof (scanner_info_t);
switch (scanner_info_p->type)
{
case SCANNER_TYPE_END:
{
scanner_info_p = context_p->active_scanner_info_p;
continue;
}
case SCANNER_TYPE_WHILE:
case SCANNER_TYPE_FOR_IN:
#if ENABLED (JERRY_ES2015_FOR_OF)
case SCANNER_TYPE_FOR_OF:
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
case SCANNER_TYPE_CASE:
{
size = sizeof (scanner_location_info_t);
break;
}
case SCANNER_TYPE_FOR:
{
size = sizeof (scanner_for_info_t);
break;
}
case SCANNER_TYPE_SWITCH:
{
scanner_release_switch_cases (((scanner_switch_info_t *) scanner_info_p)->case_p);
size = sizeof (scanner_switch_info_t);
break;
}
default:
{
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_ARROW);
#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
JERRY_ASSERT (0);
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
break;
}
}
scanner_free (scanner_info_p, size);
scanner_info_p = next_scanner_info_p;
}
context_p->next_scanner_info_p = NULL;
context_p->active_scanner_info_p = NULL;
} /* scanner_cleanup */
/**
* Get location from context.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_get_location (scanner_location_t *location_p, /**< location */
parser_context_t *context_p) /**< context */
{
location_p->source_p = context_p->source_p;
location_p->line = context_p->line;
location_p->column = context_p->column;
} /* scanner_get_location */
/**
* Set context location.
*/
inline void JERRY_ATTR_ALWAYS_INLINE
scanner_set_location (parser_context_t *context_p, /**< context */
scanner_location_t *location_p) /**< location */
{
context_p->source_p = location_p->source_p;
context_p->line = location_p->line;
context_p->column = location_p->column;
} /* scanner_set_location */
/**
* @}
* @}
* @}
*/
#endif /* ENABLED (JERRY_PARSER) */