/* =====================================
 * Generated by Mod-c 0.26.5
 * MODULE declaration
 * ===================================== */

#include "declaration.h"

void declaration(void);

/**
 * TMod-c
 * By M. Scott Reynolds
 * Date 30 July 2026
 *
 * Declaration parsing routines.
 */
#include "arena.h"
#include "node.h"
#include "parser_common.h"
#include "parser_main.h"
#include "stddef.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "Lexer.h"
#include "ttype.h"
pNode parse_item(pParser p, NodeKind node_kind)
{
    assert(p != nil); /* precondition */
    TToken item_token = ((*p)).current;
    pTType item_type = nil;
    pNode initializer = nil;
    pNode item = nil;
    if ((item_token).kind != TOK_IDENT)
    {
        error_at(p, "parse_item: expected identifier", true);
    }
    const string name_start_l60_c19 = (item_token).start;
    const size_t name_len_l61_c17 = (item_token).length;
    advance(p);
    if (match(p, TOK_COLON))
    {
        item_type = TParser__parse_return_type(&(*p));
    }
    if (match(p, TOK_EQ))
    {
        initializer = TParser__parse_expr(&(*p));
        if (initializer == nil)
        {
            error_at(p, "parse_item: expected initializer or expression after '='", true);
            /* ENSURE (on return) */
    assert(item != nil); /* postcodition */
/* return value captured before defers */
            pNode __ret_l73 = nil;
            return __ret_l73;
        }
    }
    else if (node_kind == NODE_CONST_ITEM)
    {
        error_at(p, "parse_item: expected '=' initializer for CONST items", true);
        /* ENSURE (on return) */
    assert(item != nil); /* postcodition */
/* return value captured before defers */
        pNode __ret_l77 = nil;
        return __ret_l77;
    }
    else if (node_kind == NODE_LET_ITEM)
    {
        error_at(p, "parse_item: expected '=' initializer for LET Items", true);
        /* ENSURE (on return) */
    assert(item != nil); /* postcodition */
/* return value captured before defers */
        pNode __ret_l80 = nil;
        return __ret_l80;
    }
    item = node_create(((*p)).arena, node_kind, item_token);
    (((*item)).var_item).name = name_start_l60_c19;
    (((*item)).var_item).name_len = name_len_l61_c17;
    (((*item)).var_item).item_type = item_type;
    (((*item)).var_item).initializer = initializer;
    /* ENSURE (on return) */
    assert(item != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l89 = item;
    return __ret_l89;
}

/**
 * Apply grouped trailing type propagation for a comma list of items
 * under a single VAR / CONST / LET.
 *
 * This is a semantic rule (not a grammar rule) described in docs:
 *  - The rightmost explicit type propagates leftward to proceeding bare names.
 *  - An item with "=" but no ":" type is left with TYPE==NULL (for inference)
 *  - and does not block or reset propagation for names to its left.
 *  - A bare name (no ":" and no "=") with no pending type to its right is an error.
 *
 * Works for NODE_VAR_ITEM, NODE_CONST_ITEM, and NODE_LET_ITEM because they
 * alias the same struct layout in hte Node union, and parse_item always
 * writes the fields via the var_item member.
 */
static void apply_grouped_trailing_types(pParser p, pNode* items, size_t count, string decl_kind)
{
    pTType pending = nil;
    size_t i = {0};
    {
        const long long __for_end_l114 = (long long)(1);
        for (i = count; (long long)(i) >= __for_end_l114; i--)
        {
            {
                pNode it = items[i - 1];
                if ((((*it)).var_item).item_type != nil)
                {
                    pending = (((*it)).var_item).item_type;
                }
                else if ((((*it)).var_item).initializer != nil)
                {
                }
                else
                {
                    if (pending != nil)
                    {
                        (((*it)).var_item).item_type = pending;
                    }
                    else
                    {
                        char msg[128] = {0};
                        snprintf(msg, ((integer)sizeof(msg)), "parse_%s_decl: bare names without type or initializer in declaration list", (decl_kind ? decl_kind : "decl"));
                        error_at(p, msg, true);
                    }
                }
            }
        }
    }
}

/**
 * Parse VAR declaration (multi-item grouped trailing type)
 *
 * Uses apply_grouped_trailing_types() for the right-to-left type propagation rule.
 * See docs/langauge_report for the full semantic description.
 *
 * @param p         Parser state
 * @param exported  Whether EXPORT was seen before VAR
 * @param is_extern If the VAR has external definition (cannot also be static)
 * @param is_static If the VAR has static definition (cannot also be external)
 * @return          Parsed VAR_DECL node (exists on fatal error)
 */
pNode parse_var_decl(pParser p, bool exported, bool is_extern, bool is_static)
{
    assert(p != nil); /* precondition */
    TToken var_token = ((*p)).current;
    pNode decl = nil;
    advance(p);
    if (is_extern && is_static)
    {
        error_at(p, "parse_var_decl: VARs cannot be both 'EXTERN' and 'STATIC'", true);
    }
    else if (exported && is_static)
    {
        error_at(p, "parse_var_decl: VARs cannot be both 'EXPORT' and 'STATIC'", true);
    }
    decl = node_create(((*p)).arena, NODE_VAR_DECL, var_token);
    (((*decl)).var_decl).is_exported = exported;
    (((*decl)).var_decl).is_extern = is_extern;
    (((*decl)).var_decl).is_static = is_static;
    (((*decl)).var_decl).items = nil;
    (((*decl)).var_decl).count = 0;
    (((*decl)).var_decl).capacity = 0;
    do
    {
        {
            pNode item = nil;
            skip_layout_breaks(p);
            item = parse_item(p, NODE_VAR_ITEM);
            if (item == nil)
            {
                error_at(p, "parse_var_decl: Expected variable name after VAR", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*decl)).var_decl).items), &(((*decl)).var_decl).count, &(((*decl)).var_decl).capacity, item);
        }
    }
    while (!(!match(p, TOK_COMMA)));
    apply_grouped_trailing_types(p, (((*decl)).var_decl).items, (((*decl)).var_decl).count, "var");
    if (!matchEOS(p))
    {
        error_at(p, "parse_var_decl: Expected end-of-statement after VAR declaration", true);
    }
    /* ENSURE (on return) */
    assert(decl != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l199 = decl;
    return __ret_l199;
}

/**
 * Parse CONST declaration (multi-item grouped trailing type)
 *
 * Uses apply_grouped_trailing_types() for the right-to-left type propagation rule.
 * See docs/langauge_report.md for the full semantic description.
 *
 * @param p         Parser state
 * @param exported  Whether EXPORT was seen before CONST
 * @return          Parsed CONST_DECL node (exists on fatal error)
 */
pNode parse_const_decl(pParser p, bool exported)
{
    assert(p != nil); /* precondition */
    TToken const_token = ((*p)).current;
    pNode decl = nil;
    advance(p);
    decl = node_create(((*p)).arena, NODE_CONST_DECL, const_token);
    (((*decl)).const_decl).is_exported = exported;
    (((*decl)).const_decl).items = nil;
    (((*decl)).const_decl).count = 0;
    (((*decl)).const_decl).capacity = 0;
    do
    {
        {
            pNode item = nil;
            skip_layout_breaks(p);
            item = parse_item(p, NODE_CONST_ITEM);
            if (item == nil)
            {
                error_at(p, "parse_const_decl: Expected variable name after CONST", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*decl)).const_decl).items), &(((*decl)).const_decl).count, &(((*decl)).const_decl).capacity, item);
        }
    }
    while (!(!match(p, TOK_COMMA)));
    apply_grouped_trailing_types(p, (((*decl)).const_decl).items, (((*decl)).const_decl).count, "const");
    if (!matchEOS(p))
    {
        error_at(p, "parse_const_decl: Expected end-of-statement after CONST declaration", true);
    }
    /* ENSURE (on return) */
    assert(decl != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l253 = decl;
    return __ret_l253;
}

pNode parse_let_decl(pParser p, bool exported)
{
    assert(p != nil); /* precondition */
    TToken let_token = ((*p)).current;
    pNode decl = nil;
    advance(p);
    decl = node_create(((*p)).arena, NODE_LET_DECL, let_token);
    (((*decl)).let_decl).is_exported = exported;
    (((*decl)).let_decl).items = nil;
    (((*decl)).let_decl).count = 0;
    (((*decl)).let_decl).capacity = 0;
    do
    {
        {
            pNode item = nil;
            skip_layout_breaks(p);
            item = parse_item(p, NODE_LET_ITEM);
            if (item == nil)
            {
                error_at(p, "parse_let_decl: Expected variable namae after LET", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*decl)).let_decl).items), &(((*decl)).let_decl).count, &(((*decl)).let_decl).capacity, item);
        }
    }
    while (!(!match(p, TOK_COMMA)));
    apply_grouped_trailing_types(p, (((*decl)).let_decl).items, (((*decl)).let_decl).count, "let");
    if (!matchEOS(p))
    {
        error_at(p, "parse_let_decl: Expected end-of-statement after LET declaration", true);
    }
    /* ENSURE (on return) */
    assert(decl != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l297 = decl;
    return __ret_l297;
}

/**
 * Parses TYPE declarations (multi-item support per grammar)
 *
 * Grammar (simplified for phase 1):
 *  type-def = "TYPE" time-item { "," type-item } end-of-statement
 *  type-item = identifier "=" type-expression
 */
pNode parse_type_decl(pParser p, bool exported)
{
    assert(p != nil); /* precondition */
    TToken type_token = ((*p)).current;
    pNode decl = nil;
    advance(p);
    decl = node_create(((*p)).arena, NODE_TYPE_DECL, type_token);
    (((*decl)).type_decl).is_exported = exported;
    while (1)
    {
        {
            string name_start = {0};
            size_t name_len = 0;
            skip_layout_breaks(p);
            if ((((*p)).current).kind != TOK_IDENT)
            {
                error_at(p, "parse_type_decl: expected identifier after TYPE", true);
            }
            name_start = (((*p)).current).start;
            name_len = (((*p)).current).length;
            TParser__register_type_name(&(*p), name_start, name_len);
            advance(p);
            if (match(p, TOK_KEYWORD_FORWARD))
            {
                (((*decl)).type_decl).is_forward = true;
                (((*decl)).type_decl).is_extern = false;
                (((*decl)).type_decl).defined_type = nil;
                (((*decl)).type_decl).struct_body = nil;
                (((*decl)).type_decl).method_type = nil;
                (((*decl)).type_decl).enum_type = nil;
            }
            else
            {
                consume(p, TOK_EQ, "parse_type_decl: Expected '=' after type name in TYPE declaration");
                (((*decl)).type_decl).is_forward = false;
                const bool is_packed_l349_c26 = match(p, TOK_KEYWORD_PACKED);
                if (check(p, TOK_KEYWORD_STRUCT))
                {
                    pNode struct_node = parse_struct_type(p);
                    (((*struct_node)).struct_decl).name = name_start;
                    (((*struct_node)).struct_decl).name_len = name_len;
                    (((*struct_node)).struct_decl).is_packed = is_packed_l349_c26;
                    (((*decl)).type_decl).struct_body = struct_node;
                    (((*decl)).type_decl).defined_type = nil;
                    (((*decl)).type_decl).method_type = nil;
                    (((*decl)).type_decl).enum_type = nil;
                }
                else if (check(p, TOK_KEYWORD_UNION))
                {
                    pNode u = parse_union_type(p);
                    (((*u)).struct_decl).name = name_start;
                    (((*u)).struct_decl).name_len = name_len;
                    (((*u)).struct_decl).is_union = true;
                    (((*decl)).type_decl).struct_body = u;
                    (((*decl)).type_decl).defined_type = nil;
                    (((*decl)).type_decl).method_type = nil;
                    (((*decl)).type_decl).enum_type = nil;
                }
                else if (check(p, TOK_KEYWORD_PROCEDURE) || check(p, TOK_KEYWORD_FUNCTION))
                {
                    pNode mtype = parse_method_type(p);
                    (((*decl)).type_decl).method_type = mtype;
                    (((*decl)).type_decl).struct_body = nil;
                    (((*decl)).type_decl).defined_type = nil;
                    (((*decl)).type_decl).enum_type = nil;
                }
                else if (check(p, TOK_KEYWORD_ENUM))
                {
                    pNode enum_node = parse_enum_type(p);
                    (((*decl)).type_decl).enum_type = enum_node;
                    (((*decl)).type_decl).struct_body = nil;
                    (((*decl)).type_decl).method_type = nil;
                    (((*decl)).type_decl).defined_type = nil;
                }
                else
                {
                    pTType defined_type = TParser__parse_type_expression(&(*p));
                    (((*decl)).type_decl).defined_type = defined_type;
                    (((*decl)).type_decl).struct_body = nil;
                    (((*decl)).type_decl).method_type = nil;
                    (((*decl)).type_decl).enum_type = nil;
                }
            }
            (((*decl)).type_decl).name = name_start;
            (((*decl)).type_decl).name_len = name_len;
            (((*decl)).type_decl).initializer = nil;
            if (!match(p, TOK_COMMA))
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
        }
    }
    if (!matchEOS(p))
    {
        error_at(p, "parse_type_decl: Expected end-of-statement after TYPE declaration", true);
    }
    /* ENSURE (on return) */
    assert(decl != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l404 = decl;
    return __ret_l404;
}

/**
 * Parse EXTERN TYPE declaration
 * Grammar: "EXTERN" [ "EXPORT" ] "TYPE" identifier [ "=" type-expression ] EOS
 * Caller has already consumed EXTERN and optional EXPORT.
 */
pNode parse_extern_type_decl(pParser p, bool exported)
{
    assert(p != nil); /* precondition */
    TToken type_token = ((*p)).current;
    string name_start = {0};
    size_t name_len = {0};
    pNode decl = nil;
    consume(p, TOK_KEYWORD_TYPE, "parse_extern_type_decl: expected TYPE after EXTERN");
    if ((((*p)).current).kind != TOK_IDENT)
    {
        error_at(p, "parse_extern_type_decl: expected identifier after EXTERN TYPE", true);
    }
    name_start = (((*p)).current).start;
    name_len = (((*p)).current).length;
    TParser__register_type_name(&(*p), name_start, name_len);
    advance(p);
    decl = node_create(((*p)).arena, NODE_TYPE_DECL, type_token);
    (((*decl)).type_decl).is_forward = false;
    (((*decl)).type_decl).is_exported = exported;
    (((*decl)).type_decl).is_extern = true;
    (((*decl)).type_decl).name = name_start;
    (((*decl)).type_decl).name_len = name_len;
    (((*decl)).type_decl).struct_body = nil;
    (((*decl)).type_decl).method_type = nil;
    (((*decl)).type_decl).initializer = nil;
    if (match(p, TOK_EQ))
    {
        (((*decl)).type_decl).defined_type = TParser__parse_type_expression(&(*p));
    }
    else
    {
        (((*decl)).type_decl).defined_type = nil;
    }
    if (!matchEOS(p))
    {
        error_at(p, "parse_extern_type_decl: expected end-of-statement after EXTERN TYPE", true);
    }
    /* ENSURE (on return) */
    assert(decl != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l457 = decl;
    return __ret_l457;
}

/**
 * Parse a single parameter: identifer : type
 * Returns a NODE_PARAM node
 */
pNode parse_param(pParser p)
{
    assert(p != nil); /* precondition */
    string name_start = {0};
    size_t name_len = {0};
    pTType item_type = nil;
    pNode param_node = nil;
    const bool is_const_l477_c17 = match(p, TOK_KEYWORD_CONST);
    const bool is_var_l478_c15 = match(p, TOK_KEYWORD_VAR);
    const bool is_ref_l479_c15 = match(p, TOK_KEYWORD_REF);
    if (is_var_l478_c15 && (is_const_l477_c17 || is_ref_l479_c15))
    {
        error_at(p, "parse_param: VAR cannot be combined with CONST or REF", true);
    }
    if ((((*p)).current).kind != TOK_IDENT)
    {
        error_at(p, "parse_param: expected parameter name (identifier)", true);
    }
    name_start = (((*p)).current).start;
    name_len = (((*p)).current).length;
    advance(p);
    consume(p, TOK_COLON, "parse_param: expected ':' after parameter name");
    item_type = TParser__parse_return_type(&(*p));
    param_node = node_create(((*p)).arena, NODE_PARAM, ((*p)).current);
    (((*param_node)).param).name = name_start;
    (((*param_node)).param).name_len = name_len;
    (((*param_node)).param).param_type = item_type;
    (((*param_node)).param).is_ref = is_ref_l479_c15;
    (((*param_node)).param).is_var = is_var_l478_c15;
    (((*param_node)).param).is_const = is_const_l477_c17;
    /* ENSURE (on return) */
    assert(param_node != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l507 = param_node;
    return __ret_l507;
}

/**
 * Parse optional parameter list: ( param, {, param } )
 * Returns nil if no opening '(' is present, otherwise returns a NODE_PARAM_LIST node.
 * The list node owns the dynamic array of parameters (allocated in arena).
 */
pNode parse_param_list(pParser p)
{
    assert(p != nil); /* precondition */
    pNode list = nil;
    if (!match(p, TOK_LPAREN))
    {
        /* return value captured before defers */
        pNode __ret_l525 = nil;
        return __ret_l525;
    }
    list = node_create(((*p)).arena, NODE_PARAM_LIST, ((*p)).current);
    (((*list)).param_list).params = nil;
    (((*list)).param_list).count = 0;
    (((*list)).param_list).capacity = 0;
    while (!check(p, TOK_RPAREN) && !check(p, TOK_EOF))
    {
        {
            pNode param = {0};
            skip_layout_breaks(p);
            param = parse_param(p);
            if (param == nil)
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*list)).param_list).params), &(((*list)).param_list).count, &(((*list)).param_list).capacity, param);
            if (!match(p, TOK_COMMA))
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
        }
    }
    consume(p, TOK_RPAREN, "parse_param_list: expected ')' after parameter list");
    /* return value captured before defers */
    pNode __ret_l556 = list;
    return __ret_l556;
}

/**
 * Parse PROCEDURE or FUNCTION declaration.
 * Grammar:
 *      method-prototype = [ "RECURSIVE" ] ( "PROCEDURE" | "FUNCTION" )
 *          qualified-method_name formal_parameters EOS ;
 *      qualified-method-name = type-identifier "::" identifier | identifier ;
 *
 * Instance methods pass self as the first formal parameter, e.g.
 *  function Counter::get(self: Counter): integer
 *
 * Returns NODE_PROC_DECL or NODE_FUNC_DECL.
 * Exits on fatal error.
 */
pNode parse_proc_or_func_decl(pParser p, bool exported, bool is_recursive, bool is_extern)
{
    assert(p != nil); /* precondition */
    TToken proc_token = ((*p)).current;
    const bool is_function_l578_c20 = ((proc_token).kind == TOK_KEYWORD_FUNCTION);
    bool is_forward = false;
    pNode n = nil;
    advance(p);
    n = node_create(((*p)).arena, (is_function_l578_c20 ? NODE_FUNC_DECL : NODE_PROC_DECL), proc_token);
    (((*n)).proc_decl).is_exported = exported;
    (((*n)).proc_decl).is_function = is_function_l578_c20;
    (((*n)).proc_decl).is_recursive = is_recursive;
    (((*n)).proc_decl).is_forward = false;
    (((*n)).proc_decl).is_extern = is_extern;
    (((*n)).proc_decl).method_owner = nil;
    (((*n)).proc_decl).method_owner_len = 0;
    (((*n)).proc_decl).params = nil;
    if ((((*p)).current).kind != TOK_IDENT)
    {
        error_at(p, "parse_proc_or_func_decl: expected procedure or function name", true);
    }
    {
        TToken first = ((*p)).current;
        advance(p);
        if (match(p, TOK_COLON_COLON))
        {
            if ((((*p)).current).kind != TOK_IDENT)
            {
                error_at(p, "parse_proc_or_func_decl: expected method name after '::'", true);
            }
            (((*n)).proc_decl).method_owner = (first).start;
            (((*n)).proc_decl).method_owner_len = (first).length;
            (((*n)).proc_decl).name = (((*p)).current).start;
            (((*n)).proc_decl).name_len = (((*p)).current).length;
            advance(p);
        }
        else
        {
            (((*n)).proc_decl).name = (first).start;
            (((*n)).proc_decl).name_len = (first).length;
        }
    }
    (((*n)).proc_decl).params = parse_param_list(p);
    if (is_function_l578_c20)
    {
        if (match(p, TOK_COLON))
        {
            (((*n)).proc_decl).return_type = TParser__parse_return_type(&(*p));
        }
        else
        {
            error_at(p, "parse_proc_or_func_decl: FUNCTION must have return type: TType", true);
        }
    }
    else
    {
        (((*n)).proc_decl).return_type = nil;
    }
    is_forward = match(p, TOK_KEYWORD_FORWARD);
    (((*n)).proc_decl).is_forward = is_forward;
    skip_empty_statements(p);
    if (is_extern || is_forward)
    {
        (matchEOS(p));
        (((*n)).proc_decl).body = nil;
    }
    else if (check(p, TOK_KEYWORD_BEGIN))
    {
        (((*n)).proc_decl).body = TParser__parse_block(&(*p));
    }
    else
    {
        (((*n)).proc_decl).body = nil;
    }
    /* ENSURE (on return) */
    assert(n != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l652 = n;
    return __ret_l652;
}

/**
 * Parse STRUCT type expression (RHS of TYPE declaration)
 * Grammar:
 *      struct-type = STRUCT [EXTENDS qualident]
 *          { field-decl EOS }
 *
 * Returns a NODE_STRUCT_DECL node (is_union = false).
 */
pNode parse_struct_type(pParser p)
{
    assert(p != nil); /* precondition */
    TToken struct_token = ((*p)).current;
    bool is_packed = match(p, TOK_KEYWORD_PACKED);
    string name = nil;
    size_t name_len = 0;
    pTType extends_type = nil;
    pNode s = nil;
    consume(p, TOK_KEYWORD_STRUCT, "parse_struct_type: expected STRUCT ... = ");
    if (match(p, TOK_KEYWORD_EXTENDS))
    {
        if ((((*p)).current).kind != TOK_IDENT)
        {
            error_at(p, "parse_struct_type: expected type idnetifer after EXTENDS", true);
        }
        extends_type = type_create_named(((*p)).arena, (((*p)).current).start, (((*p)).current).length);
        advance(p);
    }
    s = node_create(((*p)).arena, NODE_STRUCT_DECL, struct_token);
    (((*s)).struct_decl).name = name;
    (((*s)).struct_decl).name_len = name_len;
    (((*s)).struct_decl).extends_type = extends_type;
    (((*s)).struct_decl).is_packed = is_packed;
    (((*s)).struct_decl).fields = nil;
    (((*s)).struct_decl).field_count = 0;
    (((*s)).struct_decl).field_capacity = 0;
    (((*s)).struct_decl).is_exported = false;
    (((*s)).struct_decl).is_union = false;
    while (1)
    {
        {
            string fname = {0};
            size_t flen = {0};
            pTType ftype = nil;
            pNode finit = nil;
            pNode field = nil;
            skip_empty_statements(p);
            if (check(p, TOK_KEYWORD_END) || check(p, TOK_EOF))
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
            if ((((*p)).current).kind != TOK_IDENT)
            {
                error_at(p, "parse_struct_type: expected field name (identifier) in struct", true);
            }
            fname = (((*p)).current).start;
            flen = (((*p)).current).length;
            advance(p);
            if (match(p, TOK_COLON))
            {
                ftype = TParser__parse_return_type(&(*p));
            }
            if (match(p, TOK_EQ))
            {
                finit = TParser__parse_const_expression(&(*p));
            }
            field = node_create(((*p)).arena, NODE_FIELD_DECL, ((*p)).current);
            (((*field)).field_decl).name = fname;
            (((*field)).field_decl).name_len = flen;
            (((*field)).field_decl).field_type = ftype;
            (((*field)).field_decl).initializer = finit;
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*s)).struct_decl).fields), &(((*s)).struct_decl).field_count, &(((*s)).struct_decl).field_capacity, field);
            (matchEOS(p));
        }
    }
    consume(p, TOK_KEYWORD_END, "parse_struct_type: expected 'END' after struct fields");
    /* ENSURE (on return) */
    assert(s != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l747 = s;
    return __ret_l747;
}

/**
 * Parse UNION type expression (RHS of TYPE declaration).
 * Grammar:
 *      union-type = UNION
 *          { field-decl EOS } 
 *
 * Returns a NODE_STRUCT_DECL node with .is_union set to true
 */
pNode parse_union_type(pParser p)
{
    assert(p != nil); /* precondition */
    TToken union_token = ((*p)).current;
    string name = {0};
    size_t name_len = {0};
    pNode u = nil;
    consume(p, TOK_KEYWORD_UNION, "parse_untion_type: expected UNION");
    u = node_create(((*p)).arena, NODE_STRUCT_DECL, union_token);
    (((*u)).struct_decl).name = name;
    (((*u)).struct_decl).name_len = name_len;
    (((*u)).struct_decl).fields = nil;
    (((*u)).struct_decl).field_count = 0;
    (((*u)).struct_decl).field_capacity = 0;
    (((*u)).struct_decl).is_exported = false;
    (((*u)).struct_decl).is_union = true;
    while (1)
    {
        {
            string fname = {0};
            size_t flen = {0};
            pTType ftype = nil;
            pNode finit = nil;
            pNode field = nil;
            skip_empty_statements(p);
            if (check(p, TOK_KEYWORD_END) || check(p, TOK_EOF))
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
            if ((((*p)).current).kind != TOK_IDENT)
            {
                error_at(p, "parse_union_type: expected field name (identifier) in UNION", true);
            }
            fname = (((*p)).current).start;
            flen = (((*p)).current).length;
            advance(p);
            if (match(p, TOK_COLON))
            {
                ftype = TParser__parse_return_type(&(*p));
            }
            if (match(p, TOK_EQ))
            {
                finit = TParser__parse_const_expression(&(*p));
            }
            field = node_create(((*p)).arena, NODE_FIELD_DECL, ((*p)).current);
            (((*field)).field_decl).name = fname;
            (((*field)).field_decl).name_len = flen;
            (((*field)).field_decl).field_type = ftype;
            (((*field)).field_decl).initializer = finit;
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*u)).struct_decl).fields), &(((*u)).struct_decl).field_count, &(((*u)).struct_decl).field_capacity, field);
            matchEOS(p);
        }
    }
    consume(p, TOK_KEYWORD_END, "parse_union_type: expected 'END' after union fields");
    /* ENSURE (on return) */
    assert(u != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l828 = u;
    return __ret_l828;
}

/**
 * Parse a method type (PROCEDURE or FUNCTION siangature unsed as a type).
 * Grammar:
 *      method-type = ( "PROCEDRE" | "FUNCTION" ) format_parameters
 *
 * This is used on the right-hand size of TYPE declarations, and can
 * also appear in parameter types and variable declarations.
 * 
 * Returns a NODE_METHOD_TYPE node.
 */
pNode parse_method_type(pParser p)
{
    assert(p != nil); /* precondition */
    TToken type_token = ((*p)).current;
    bool is_function = ((type_token).kind == TOK_KEYWORD_FUNCTION);
    pNode n = nil;
    advance(p);
    n = node_create(((*p)).arena, NODE_METHOD_TYPE, type_token);
    (((*n)).method_type).is_function = is_function;
    (((*n)).method_type).params = nil;
    (((*n)).method_type).return_type = nil;
    (((*n)).method_type).params = parse_param_list(p);
    if (is_function)
    {
        if (match(p, TOK_COLON))
        {
            (((*n)).method_type).return_type = TParser__parse_return_type(&(*p));
        }
        else
        {
            error_at(p, "parse_method_type: FUNCTION type must have a return type after ':'", true);
        }
    }
    /* ENSURE (on return) */
    assert(n != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l871 = n;
    return __ret_l871;
}

/**
 * Parse one enum member: identifer [ "=" const-exprssion ]
 */
static pNode parse_enum_item(pParser p)
{
    assert(p != nil); /* precondition */
    TToken item_tok = {0};
    string name = {0};
    size_t name_len = {0};
    pNode item = nil;
    if ((((*p)).current).kind != TOK_IDENT)
    {
        /* return value captured before defers */
        pNode __ret_l891 = nil;
        return __ret_l891;
    }
    item_tok = ((*p)).current;
    name = (((*p)).current).start;
    name_len = (((*p)).current).length;
    advance(p);
    item = node_create(((*p)).arena, NODE_ENUM_ITEM, item_tok);
    (((*item)).enum_item).name = name;
    (((*item)).enum_item).name_len = name_len;
    (((*item)).enum_item).value = nil;
    if (match(p, TOK_EQ))
    {
        (((*item)).enum_item).value = TParser__parse_const_expression(&(*p));
    }
    /* return value captured before defers */
    pNode __ret_l909 = item;
    return __ret_l909;
}

/**
 * Parse ENUM type epxression (RHOS of TYPE declaration).
 * Grammar: 
 *      enum-type = "ENUM" [ EOS ] enum-decl { "," enum-decl } [","] [ EOS ] "END" ;
 *      enum-decl = identifier [ "=" const-expression ] ;
 *
 * Returns NODE_ENUM_TYPE, Outer TYPE_DECL supplies the type name.
 */
pNode parse_enum_type(pParser p)
{
    assert(p != nil); /* precondition */
    TToken enum_token = ((*p)).current;
    pNode e = nil;
    consume(p, TOK_KEYWORD_ENUM, "parse_enum_type: expected ENUM");
    e = node_create(((*p)).arena, NODE_ENUM_TYPE, enum_token);
    (((*e)).enum_type).name = nil;
    (((*e)).enum_type).name_len = 0;
    (((*e)).enum_type).elements = nil;
    (((*e)).enum_type).count = 0;
    (((*e)).enum_type).capacity = 0;
    (matchEOS(p));
    while (!check(p, TOK_KEYWORD_END) && !isEOF(p))
    {
        {
            pNode item = nil;
            skip_layout_breaks(p);
            item = parse_enum_item(p);
            if (item == nil)
            {
                error_at(p, "parse_enum_type: expected enum member identifier", true);
                                /* INVARIANT (on loop exit) */
                break;
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*e)).enum_type).elements), &(((*e)).enum_type).count, &(((*e)).enum_type).capacity, item);
            if (match(p, TOK_COMMA))
            {
                skip_layout_breaks(p);
                                /* INVARIANT (on loop exit) */
                continue;
            }
            skip_layout_breaks(p);
            if (check(p, TOK_KEYWORD_END))
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
            error_at(p, "parse_enum_type: expected ',' or END after enum member", true);
        }
    }
    if ((((*e)).enum_type).count == 0)
    {
        error_at(p, "parse_enum_type: enum requires at least one member", true);
    }
    consume(p, TOK_KEYWORD_END, "parse_enum_type: expected END after enum members");
    /* ENSURE (on return) */
    assert(e != nil); /* postcodition */
/* return value captured before defers */
    pNode __ret_l976 = e;
    return __ret_l976;
}


void declaration(void)
{
}
