#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "../core_runtime/core_runtime_private.h"
#include "script_compile_private.h"
#include "script_memory_private.h"

enum {
    SCRIPT_YY_STRING_TOKEN_TYPE = 0x0d
};

/* NOT_FROM_ORIGINAL_SOURCE: explicit low-half store for string-token handles. */
static void coduomp_script_yy_set_string_handle_token(uint16_t handle)
{
    uint16_t *slot = (uint16_t *)&script_yylval.words[0];
    *slot = handle;
}

sval_u *
node1_(sval_u *out,
       coduo_script_yystype_word_t word)
{
    out->words[0] = word;
    return out;
}

sval_u *
node_pos(sval_u *out,
         coduo_script_yystype_word_t word)
{
    out->words[0] = word;
    return out;
}

sval_u *
node0(sval_u *out,
                      coduo_script_yystype_word_t word0)
{
    coduo_scr_parser_words1_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node1(sval_u *out,
                   coduo_script_yystype_word_t word0,
                   coduo_script_yystype_word_t word1)
{
    coduo_scr_parser_words2_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node2(sval_u *out,
                   coduo_script_yystype_word_t word0,
                   coduo_script_yystype_word_t word1,
                   coduo_script_yystype_word_t word2)
{
    coduo_scr_parser_words3_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node2_(sval_u *out,
                  coduo_script_yystype_word_t word0,
                  coduo_script_yystype_word_t word1)
{
    coduo_scr_parser_words2_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node3(sval_u *out,
                   coduo_script_yystype_word_t word0,
                   coduo_script_yystype_word_t word1,
                   coduo_script_yystype_word_t word2,
                   coduo_script_yystype_word_t word3)
{
    coduo_scr_parser_words4_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    words->words[3] = word3;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
ScriptAst_NewTriple(sval_u *out,
                    coduo_script_yystype_word_t word0,
                    coduo_script_yystype_word_t word1,
                    coduo_script_yystype_word_t word2)
{
    coduo_scr_parser_words3_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node4(sval_u *out,
                   coduo_script_yystype_word_t word0,
                   coduo_script_yystype_word_t word1,
                   coduo_script_yystype_word_t word2,
                   coduo_script_yystype_word_t word3,
                   coduo_script_yystype_word_t word4)
{
    coduo_scr_parser_words5_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    words->words[3] = word3;
    words->words[4] = word4;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
ScriptAst_NewQuad(sval_u *out,
                  coduo_script_yystype_word_t word0,
                  coduo_script_yystype_word_t word1,
                  coduo_script_yystype_word_t word2,
                  coduo_script_yystype_word_t word3)
{
    coduo_scr_parser_words4_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    words->words[3] = word3;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node5(sval_u *out,
                   coduo_script_yystype_word_t word0,
                   coduo_script_yystype_word_t word1,
                   coduo_script_yystype_word_t word2,
                   coduo_script_yystype_word_t word3,
                   coduo_script_yystype_word_t word4,
                   coduo_script_yystype_word_t word5)
{
    coduo_scr_parser_words6_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    words->words[3] = word3;
    words->words[4] = word4;
    words->words[5] = word5;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
node6(sval_u *out,
                   coduo_script_yystype_word_t word0,
                   coduo_script_yystype_word_t word1,
                   coduo_script_yystype_word_t word2,
                   coduo_script_yystype_word_t word3,
                   coduo_script_yystype_word_t word4,
                   coduo_script_yystype_word_t word5,
                   coduo_script_yystype_word_t word6)
{
    coduo_scr_parser_words7_t *words =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*words));

    words->words[0] = word0;
    words->words[1] = word1;
    words->words[2] = word2;
    words->words[3] = word3;
    words->words[4] = word4;
    words->words[5] = word5;
    words->words[6] = word6;
    out->words[0] = (coduo_script_yystype_word_t)words;
    return out;
}

sval_u *
linked_list_end(sval_u *out,
                      coduo_script_yystype_word_t value)
{
    coduo_scr_parser_list_link_t *item =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*item));
    item->value = value;
    item->next = NULL;

    coduo_scr_parser_list_t *list =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*list));
    list->head = item;
    list->tail = item;

    out->words[0] = (coduo_script_yystype_word_t)list;
    return out;
}

sval_u *
prepend_node(sval_u *out,
                         coduo_script_yystype_word_t value,
                         coduo_script_yystype_word_t headValue)
{
    coduo_scr_parser_list_link_t **head =
        (coduo_scr_parser_list_link_t **)headValue;
    coduo_scr_parser_list_link_t *item =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*item));

    item->value = value;
    item->next = *head;
    *head = item;
    out->words[0] = (coduo_script_yystype_word_t)head;
    return out;
}

sval_u *
append_node(sval_u *out,
                        coduo_script_yystype_word_t listValue,
                        coduo_script_yystype_word_t value)
{
    coduo_scr_parser_list_t *list =
        (coduo_scr_parser_list_t *)listValue;
    coduo_scr_parser_list_link_t *item =
        Hunk_AllocateTempMemoryHighInternal((size_t)sizeof(*item));

    item->value = value;
    item->next = NULL;
    list->tail->next = item;
    list->tail = item;
    out->words[0] = (coduo_script_yystype_word_t)list;
    return out;
}

sval_u *
ScriptYyList_Concat(sval_u *out,
                    coduo_scr_parser_list_t *left,
                    coduo_scr_parser_list_t *right)
{
    left->tail->next = right->head;
    left->tail = right->tail;
    out->words[0] = (coduo_script_yystype_word_t)left;
    return out;
}

void ScriptYy_SetLowercaseStringToken(const char *text, int32_t length)
{
    coduomp_script_yy_set_string_handle_token(SL_GetLowercaseStringOfLen(
        text, 0, length + 1, SCRIPT_YY_STRING_TOKEN_TYPE));
}

void ScriptYy_SetEscapedStringToken(const char *text, int32_t length)
{
    char unescaped[(size_t)length + 1U];
    int32_t readIndex = 0;
    int32_t writeIndex = 0;

    while (readIndex < length) {
        if (text[readIndex] == '\\') {
            if (readIndex + 1 == length) {
                break;
            }

            char escaped = text[readIndex + 1];
            if (escaped == 'n') {
                unescaped[writeIndex] = '\n';
            } else if (escaped == 'r') {
                unescaped[writeIndex] = '\r';
            } else if (escaped == 't') {
                unescaped[writeIndex] = '\t';
            } else {
                unescaped[writeIndex] = escaped;
            }

            readIndex += 2;
            writeIndex++;
            continue;
        }

        unescaped[writeIndex] = text[readIndex];
        readIndex++;
        writeIndex++;
    }

    unescaped[writeIndex] = '\0';
    coduomp_script_yy_set_string_handle_token(
        SL_GetString_(unescaped, 0, SCRIPT_YY_STRING_TOKEN_TYPE));
}

void ScriptYy_SetIntToken(const char *text)
{
    int32_t value = (int32_t)script_yylval.words[0];

    sscanf(text, "%d", &value);
    script_yylval.words[0] = (coduo_script_yystype_word_t)value;
}

void ScriptYy_SetFloatToken(const char *text)
{
    float value;
    uint32_t valueBits = (uint32_t)script_yylval.words[0];

    memcpy(&value, &valueBits, sizeof(value));
    sscanf(text, "%f", &value);
    script_yylval.words[0] = 0;
    memcpy(&script_yylval.words[0], &value, sizeof(value));
}
