<commit_before>#include "test_parse_expression_syntax_error.h"
#include "test.h"
#include "lpg_parse_expression.h"
#include "lpg_array_size.h"

typedef struct test_parser_user
{
    unicode_code_point const *remaining_input;
    size_t remaining_size;
    parse_error const *expected_errors;
    size_t expected_count;
    source_location current_location;
} test_parser_user;

static rich_token find_next_token(callback_user user)
{
    test_parser_user *const parser_user = user;
    if (parser_user->remaining_size == 0)
    {
        rich_token result = rich_token_create(
            tokenize_success, token_space,
            unicode_view_create(parser_user->remaining_input, 0),
            parser_user->current_location);
        return result;
    }
    tokenize_result tokenized =
        tokenize(parser_user->remaining_input, parser_user->remaining_size);
    REQUIRE(tokenized.status == tokenize_success);
    REQUIRE(tokenized.length <= parser_user->remaining_size);
    rich_token result = rich_token_create(
        tokenized.status, tokenized.token,
        unicode_view_create(parser_user->remaining_input, tokenized.length),
        parser_user->current_location);
    if (tokenized.status == tokenize_success)
    {
        if (tokenized.token == token_newline)
        {
            ++parser_user->current_location.line;
            parser_user->current_location.approximate_column = 0;
        }
        else
        {
            parser_user->current_location.approximate_column +=
                tokenized.length;
        }
    }
    parser_user->remaining_input += tokenized.length;
    parser_user->remaining_size -= tokenized.length;
    return result;
}

static continue_flag handle_error(parse_error const error, callback_user user)
{
    test_parser_user *const parser_user = user;
    REQUIRE(parser_user->expected_count >= 1);
    REQUIRE(parse_error_equals(parser_user->expected_errors[0], error));
    --parser_user->expected_count;
    ++parser_user->expected_errors;
    return continue_yes;
}

static void test_syntax_error(parse_error const *expected_errors,
                              size_t const expected_count,
                              expression *const expected, unicode_string input)
{
    test_parser_user user = {
        input.data, input.length, expected_errors, expected_count};
    expression_parser parser =
        expression_parser_create(find_next_token, handle_error, &user);
    expression_parser_result result = parse_expression(&parser);
    if (expected)
    {<commit_msg>add struct initializer<commit_after>#include "test_parse_expression_syntax_error.h"
#include "test.h"
#include "lpg_parse_expression.h"
#include "lpg_array_size.h"

typedef struct test_parser_user
{
    unicode_code_point const *remaining_input;
    size_t remaining_size;
    parse_error const *expected_errors;
    size_t expected_count;
    source_location current_location;
} test_parser_user;

static rich_token find_next_token(callback_user user)
{
    test_parser_user *const parser_user = user;
    if (parser_user->remaining_size == 0)
    {
        rich_token result = rich_token_create(
            tokenize_success, token_space,
            unicode_view_create(parser_user->remaining_input, 0),
            parser_user->current_location);
        return result;
    }
    tokenize_result tokenized =
        tokenize(parser_user->remaining_input, parser_user->remaining_size);
    REQUIRE(tokenized.status == tokenize_success);
    REQUIRE(tokenized.length <= parser_user->remaining_size);
    rich_token result = rich_token_create(
        tokenized.status, tokenized.token,
        unicode_view_create(parser_user->remaining_input, tokenized.length),
        parser_user->current_location);
    if (tokenized.status == tokenize_success)
    {
        if (tokenized.token == token_newline)
        {
            ++parser_user->current_location.line;
            parser_user->current_location.approximate_column = 0;
        }
        else
        {
            parser_user->current_location.approximate_column +=
                tokenized.length;
        }
    }
    parser_user->remaining_input += tokenized.length;
    parser_user->remaining_size -= tokenized.length;
    return result;
}

static continue_flag handle_error(parse_error const error, callback_user user)
{
    test_parser_user *const parser_user = user;
    REQUIRE(parser_user->expected_count >= 1);
    REQUIRE(parse_error_equals(parser_user->expected_errors[0], error));
    --parser_user->expected_count;
    ++parser_user->expected_errors;
    return continue_yes;
}

static void test_syntax_error(parse_error const *expected_errors,
                              size_t const expected_count,
                              expression *const expected, unicode_string input)
{
    test_parser_user user = {input.data, input.length, expected_errors,
                             expected_count, source_location_create(0, 0)};
    expression_parser parser =
        expression_parser_create(find_next_token, handle_error, &user);
    expression_parser_result result = parse_expression(&parser);
    if (expected)
    {
{'fraction_non_alphanumeric': 0.0840630472854641, 'fraction_numerical': 0.002335084646818447, 'mean_word_length': 3.308466051969824, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5925684', 'n_tokens_mistral': 1531, 'n_tokens_neox': 1495, 'n_words': 258}