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

#include "statement.h"

void statement(void);

/**
 * Mod-c
 * By M. Scott Reynolds
 * Date 17 July 2026
 *
 * statement.mc - Statement parsing routines.
 */
#include "arena.h"
#include "utils.h"
#include "node.h"
#include "parser_common.h"
#include "parser_main.h"
#include "Lexer.h"
#include "stddef.h"
#include "stdlib.h"
#include "stdio.h"
typedef const char* pcchar;
/**
 * Parse DEFER statement.
 * Grammar: "DEFER" statement ;
 * The deferred statement is stored in the currenb block's defer list.
 */
pNode parse_defer_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken defer_tok = {0};
    Node* action = {0};
    Node* n = {0};
    defer_tok = ((*p)).current;
    consume(p, TOK_KEYWORD_DEFER, "parse_defer_stmt: expected DEFER");
    action = TParser__parse_stmt(&(*p));
    if (action == nil)
    {
        error_at(p, "parse_defer_stmt: expected statement after DEFER", true);
    }
    n = node_create(((*p)).arena, NODE_DEFER, defer_tok);
    (((*n)).defer_stmt).action = action;
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_DEFER); /* postcodition */
/* return value captured before defers */
    pNode __ret_l75 = n;
    return __ret_l75;
}

/**
 * Parse DEBUG statement.
 * Grammar: "DEBUG" statement ;
 * The debug statement is generated in code when a debug flag is set.
 */
pNode parse_debug_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken debug_tok = {0};
    pNode action = {0};
    pNode n = {0};
    debug_tok = ((*p)).current;
    consume(p, TOK_KEYWORD_DEBUG, "parse_debug_stmt: expected DEBUG");
    action = TParser__parse_stmt(&(*p));
    if (action == nil)
    {
        error_at(p, "parse_debug_stmt: expected statement after DEBUG", true);
    }
    n = node_create(((*p)).arena, NODE_DEBUG, debug_tok);
    (((*n)).debug_stmt).action = action;
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_DEBUG); /* postcodition */
/* return value captured before defers */
    pNode __ret_l104 = n;
    return __ret_l104;
}

/**
 * Parse SWITCH statement.
 * Grammar:
 * 	"SWITCH" expression "OF"
 * 		{ "CASE" case-labels ":" statement-sequence }
 *		"ELSE" ":" statement-sequence
 * 	"END" ;
 *
 * 	case-labels = const-expression { "," const-expression } ;
 *
 * No fallthrough. ELSE is required.
 */
Node* parse_switch_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    pNode expr = {0};
    TToken switch_tok = {0};
    pNode n = {0};
    switch_tok = ((*p)).current;
    consume(p, TOK_KEYWORD_SWITCH, "parse_switch_stmt: expected SWITCH");
    expr = TParser__parse_expr(&(*p));
    if (expr == nil)
    {
        error_at(p, "parse_switch_stmt: expected expression after SWITCH", true);
    }
    consume(p, TOK_KEYWORD_OF, "parse_switch_stmt: expected OF after SWITCH expression");
    n = node_create(((*p)).arena, NODE_SWITCH, switch_tok);
    (((*n)).switch_stmt).expr = expr;
    (((*n)).switch_stmt).cases = nil;
    (((*n)).switch_stmt).case_count = 0;
    (((*n)).switch_stmt).case_capacity = 0;
    (((*n)).switch_stmt).else_body = nil;
    skip_empty_statements(p);
    while (check(p, TOK_KEYWORD_CASE))
    {
        {
            pNode* labels = nil;
            size_t label_count = 0;
            size_t label_capacity = 0;
            pNode lab = nil;
            pNode body = nil;
            SwitchCase* case_arm = nil;
            consume(p, TOK_KEYWORD_CASE, "parse_switch_stt: expected CASE");
            lab = TParser__parse_const_expression(&(*p));
            if (lab == nil)
            {
                error_at(p, "parse_switch_stmt: expected const-expression in CASE label", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&labels), &label_count, &label_capacity, (pvoid)lab);
            while (match(p, TOK_COMMA))
            {
                {
                    lab = TParser__parse_const_expression(&(*p));
                    if (lab == nil)
                    {
                        error_at(p, "parse_switch_stmt: expected const-expression afer ','", true);
                    }
                    arena_append_ptr(((*p)).arena, (ppvoid)(&labels), &label_count, &label_capacity, (pvoid)lab);
                }
            }
            consume(p, TOK_COLON, "parse_switch_stmt: expected ':' after CASE labels");
            body = TParser__parse_statement_sequence(&(*p));
            case_arm = arena_alloc(((*p)).arena, ((integer)sizeof(SwitchCase)));
            ((*case_arm)).labels = labels;
            ((*case_arm)).label_count = label_count;
            ((*case_arm)).label_capacity = label_capacity;
            ((*case_arm)).body = body;
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*n)).switch_stmt).cases), &(((*n)).switch_stmt).case_count, &(((*n)).switch_stmt).case_capacity, (pvoid)case_arm);
            skip_empty_statements(p);
        }
    }
    consume(p, TOK_KEYWORD_ELSE, "parse_switch_stmt: expected ELSE (required)");
    consume(p, TOK_COLON, "parse_switch_stmt: expected ':' after ELSE");
    (((*n)).switch_stmt).else_body = TParser__parse_statement_sequence(&(*p));
    consume(p, TOK_KEYWORD_END, "parse_switch_stmt: expected END after SWITCH");
    if ((((*p)).current).kind == TOK_IDENT)
    {
        advance(p);
    }
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_SWITCH); /* postcodition */
/* return value captured before defers */
    Node* __ret_l208 = n;
    return __ret_l208;
}

/**
 * Parse qualident = identifier { "." identifier } starting at current IDENT.
 * Returns false if current token is not TOK_IDENT.
 */
static bool parse_qualident_span(pParser p, pcchar* start, size_t* length)
{
    assert(p != nil); /* precondition */
    if ((((*p)).current).kind != TOK_IDENT)
    {
        /* return value captured before defers */
        bool __ret_l223 = false;
        return __ret_l223;
    }
    (*start) = (((*p)).current).start;
    (*length) = (((*p)).current).length;
    advance(p);
    while (match(p, TOK_DOT))
    {
        {
            if ((((*p)).current).kind != TOK_IDENT)
            {
                error_at(p, "parse_qualident_span: expected identifier after '.' in qualident", true);
            }
            (*length) = (size_t)((((*p)).current).start + (((*p)).current).length - (*start));
            advance(p);
        }
    }
    /* return value captured before defers */
    bool __ret_l238 = true;
    return __ret_l238;
}

/**
 * Parse IMPORT statement
 * Grammar:
 * 		IMPORT [ import-item { , import-item } ] FROM import-source;
 *		import-source = string-literal | qualident ;
 * 		import-item = (identifier { "," identifier } | type-identifier "::" identifier) [ AS identifier ] ;
 *
 * Returns NODE_IMPORT node or nil if no IMPORT seen.
 */
Node* parse_import_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken import_token = ((*p)).current;
    Node* imp = nil;
    bool has_item = false;
    advance(p);
    imp = node_create(((*p)).arena, NODE_IMPORT, import_token);
    (((*imp)).import_stmt).items = nil;
    (((*imp)).import_stmt).count = 0;
    (((*imp)).import_stmt).capacity = 0;
    (((*imp)).import_stmt).from_path = nil;
    (((*imp)).import_stmt).path_len = 0;
    while (!check(p, TOK_KEYWORD_FROM) && !isEOF(p))
    {
        {
            Node* item = nil;
            skip_layout_breaks(p);
            if (check(p, TOK_KEYWORD_FROM))
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
            item = parse_import_item(p);
            if (item == nil)
            {
                if (!has_item)
                {
                    error_at(p, "parse_import_stmt: expected identifier in IMPORT", true);
                }
                                /* INVARIANT (on loop exit) */
                break;
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*imp)).import_stmt).items), &(((*imp)).import_stmt).count, &(((*imp)).import_stmt).capacity, item);
            match(p, TOK_COMMA);
        }
    }
    if (!match(p, TOK_KEYWORD_FROM))
    {
        error_at(p, "parse_import_stmt: IMPORT rquires FROM import-source", true);
    }
    if ((((*p)).current).kind == TOK_STRING)
    {
        (((*imp)).import_stmt).from_path = (((*p)).current).start;
        (((*imp)).import_stmt).path_len = (((*p)).current).length;
        advance(p);
    }
    else if (!parse_qualident_span(p, &(((*imp)).import_stmt).from_path, &(((*imp)).import_stmt).path_len))
    {
        error_at(p, "parse_import_stmt: expected stringliteral or module qualident after FROM", true);
    }
    if (!matchEOS(p))
    {
        error_at(p, "parse_import_stmt: expected end-of-statement after IMPORT statement", true);
    }
    /* ENSURE (on return) */
    assert(((*imp)).kind == NODE_IMPORT); /* postcodition */
/* return value captured before defers */
    Node* __ret_l310 = imp;
    return __ret_l310;
}

/**
 * Parse one import item:
 * 		plain: ident { "." ident } [ AS ident ]
 * 		method: Type "::" name [ AS ident ]
 */
Node* parse_import_item(pParser p)
{
    assert(p != nil); /* precondition */
    pcchar qual_start = nil;
    size_t qual_len = 0;
    pcchar owner_start = nil;
    size_t owner_len = 0;
    pcchar alias_start = nil;
    size_t alias_len = 0;
    Node* item = nil;
    if ((((*p)).current).kind != TOK_IDENT)
    {
        /* ENSURE (on return) */
    assert(((*item)).kind == NODE_IMPORT_ITEM); /* postcodition */
/* return value captured before defers */
        Node* __ret_l334 = nil;
        return __ret_l334;
    }
    qual_start = (((*p)).current).start;
    qual_len = (((*p)).current).length;
    advance(p);
    if (match(p, TOK_COLON_COLON))
    {
        owner_start = qual_start;
        owner_len = qual_len;
        if ((((*p)).current).kind != TOK_IDENT)
        {
            error_at(p, "parse_import_item: expected method name after '::'", true);
        }
        qual_start = (((*p)).current).start;
        qual_len = (((*p)).current).length;
        advance(p);
    }
    else
    {
        while (match(p, TOK_DOT))
        {
            {
                if ((((*p)).current).kind != TOK_IDENT)
                {
                    error_at(p, "parse_import_item: expected identifier after '.' in import name", true);
                }
                qual_len = (size_t)((((*p)).current).start + (((*p)).current).length - qual_start);
                advance(p);
            }
        }
    }
    if (match(p, TOK_KEYWORD_AS))
    {
        if ((((*p)).current).kind != TOK_IDENT)
        {
            error_at(p, "parse_import_item: expected identifier after AS", true);
        }
        alias_start = (((*p)).current).start;
        alias_len = (((*p)).current).length;
        advance(p);
    }
    item = node_create(((*p)).arena, NODE_IMPORT_ITEM, ((*p)).current);
    (((*item)).import_item).qualident = qual_start;
    (((*item)).import_item).qualident_len = qual_len;
    (((*item)).import_item).method_owner = owner_start;
    (((*item)).import_item).method_owner_len = owner_len;
    (((*item)).import_item).import_alias = alias_start;
    (((*item)).import_item).import_alias_len = alias_len;
    /* ENSURE (on return) */
    assert(((*item)).kind == NODE_IMPORT_ITEM); /* postcodition */
/* return value captured before defers */
    Node* __ret_l380 = item;
    return __ret_l380;
}

/**
 * Parse break statement
 */
Node* parse_break_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken break_tok = ((*p)).current;
    Node* n = nil;
    consume(p, TOK_KEYWORD_BREAK, "parse_break_stmt: expected BREAK");
    if (!matchEOS(p))
    {
        error_at(p, "parse_break_statement: expected end-of-statement after BREAK", true);
    }
    n = node_create(((*p)).arena, NODE_BREAK, break_tok);
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_BREAK); /* postcodition */
/* return value captured before defers */
    Node* __ret_l405 = n;
    return __ret_l405;
}

/**
 * Parse CONTINUE statement
 */
Node* parse_continue_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken cont_tok = ((*p)).current;
    Node* n = nil;
    consume(p, TOK_KEYWORD_CONTINUE, "parse_continue_stmt: expected CONTINUE");
    if (!matchEOS(p))
    {
        error_at(p, "parse_continue_stmt: expected end-of-statement after CONTINUE", true);
    }
    n = node_create(((*p)).arena, NODE_CONTINUE, cont_tok);
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_CONTINUE); /* postcodition */
/* return value captured before defers */
    Node* __ret_l429 = n;
    return __ret_l429;
}

/**
 * Parse RETURN statement
 */
Node* parse_return_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken ret_tok = ((*p)).current;
    Node* expr = nil;
    Node* n = nil;
    consume(p, TOK_KEYWORD_RETURN, "parse_return_stmt: expected RETURN");
    if (!checkEOS(p))
    {
        expr = TParser__parse_expr(&(*p));
    }
    if (!matchEOS(p))
    {
        error_at(p, "parse_return_stmt: expected end-of-statement after RETURN", true);
    }
    n = node_create(((*p)).arena, NODE_RETURN, ret_tok);
    (((*n)).ret).expr = expr;
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_RETURN); /* postcodition */
/* return value captured before defers */
    Node* __ret_l460 = n;
    return __ret_l460;
}

/**
 * Parse IF statement
 */
Node* parse_if_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken if_tok = ((*p)).current;
    Node* cond = nil;
    Node* then_block = nil;
    Node* last_elsif = nil;
    Node* n = nil;
    consume(p, TOK_KEYWORD_IF, "parse_if_stmt: expected IF");
    cond = TParser__parse_expr(&(*p));
    if (cond == nil)
    {
        error_at(p, "parse_if_stmt: expected condition after IF", true);
    }
    consume(p, TOK_KEYWORD_THEN, "parse_if_stmt: expected THEN after IF condition");
    then_block = TParser__parse_statement_sequence(&(*p));
    n = node_create(((*p)).arena, NODE_IF, if_tok);
    (((*n)).if_stmt).cond = cond;
    (((*n)).if_stmt).then_ = then_block;
    (((*n)).if_stmt).elsif_ = nil;
    (((*n)).if_stmt).else_ = nil;
    last_elsif = n;
    while (match(p, TOK_KEYWORD_ELSIF))
    {
        {
            Node* elsif_cond = TParser__parse_expr(&(*p));
            Node* elsif_then = nil;
            Node* elsif_node = nil;
            if (elsif_cond == nil)
            {
                error_at(p, "parse_if_stmt: expected condition after ELSIF", true);
            }
            consume(p, TOK_KEYWORD_THEN, "parse_if_stmt: expected THEN after ELSIF condition");
            elsif_then = TParser__parse_statement_sequence(&(*p));
            elsif_node = node_create(((*p)).arena, NODE_ELSIF, ((*p)).current);
            (((*elsif_node)).if_stmt).cond = elsif_cond;
            (((*elsif_node)).if_stmt).then_ = elsif_then;
            (((*elsif_node)).if_stmt).elsif_ = nil;
            (((*elsif_node)).if_stmt).else_ = nil;
            (((*last_elsif)).if_stmt).elsif_ = elsif_node;
            last_elsif = elsif_node;
        }
    }
    if (match(p, TOK_KEYWORD_ELSE))
    {
        Node* else_block = TParser__parse_statement_sequence(&(*p));
        (((*last_elsif)).if_stmt).else_ = else_block;
    }
    consume(p, TOK_KEYWORD_END, "parse_if_stmt: expected END after IF condition");
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_IF); /* postcodition */
/* return value captured before defers */
    Node* __ret_l528 = n;
    return __ret_l528;
}

/**
 * Parse WHILE ... DO ... END statement
 * Grammar:
 * 		"WHILE" expression "DO" statement-sequence "END"
 *
 * Returns NODE_WHILE node
 * Exits on fatal error (missing DO, END, etc).
 */
Node* parse_while_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken while_token = ((*p)).current;
    Node* n = nil;
    advance(p);
    n = node_create(((*p)).arena, NODE_WHILE, while_token);
    (((*n)).while_stmt).invariants = nil;
    (((*n)).while_stmt).invariant_count = 0;
    (((*n)).while_stmt).invariant_capacity = 0;
    (((*n)).while_stmt).cond = TParser__parse_expr(&(*p));
    if ((((*n)).while_stmt).cond == nil)
    {
        error_at(p, "parse_while_stmt: expected expression after WHILE", true);
    }
    consume(p, TOK_KEYWORD_DO, "parse_while_stmt: expected DO after WHILE condition");
    skip_empty_statements(p);
    while (check(p, TOK_KEYWORD_INVARIANT))
    {
        {
            Node* expr = nil;
            advance(p);
            expr = TParser__parse_expr(&(*p));
            if (expr == nil)
            {
                error_at(p, "parse_while_stmt: expected expression after INVARIANT ...", true);
            }
            if (!matchEOS(p))
            {
                error_at(p, "parse_while_stmt: expected end-of-statement after INVARIANT expression", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*n)).while_stmt).invariants), &(((*n)).while_stmt).invariant_count, &(((*n)).while_stmt).invariant_capacity, expr);
            skip_empty_statements(p);
        }
    }
    (((*n)).while_stmt).body = TParser__parse_statement_sequence(&(*p));
    consume(p, TOK_KEYWORD_END, "parse_while_stmt: expected END after WHILE body");
    if ((((*p)).current).kind == TOK_IDENT)
    {
        advance(p);
    }
    if (!matchEOS(p))
    {
    }
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_WHILE); /* postcodition */
/* return value captured before defers */
    Node* __ret_l605 = n;
    return __ret_l605;
}

/**
 * Parse FOR statement with optional BY step
 * Grammar:
 *		"FOR" identifier ":=" expression ( "TO" | "DOWNTO" ) expression
 *			[ "BY" const-expression ] "DO" statement-sequence "END"
 */
Node* parse_for_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken for_tok = ((*p)).current;
    pcchar var_name = nil;
    size_t var_len = 0;
    Node* start_expr = nil;
    Node* end_expr = nil;
    int step = 0;
    Node* n = nil;
    consume(p, TOK_KEYWORD_FOR, "parse_for_stmt: expected FOR");
    if ((((*p)).current).kind != TOK_IDENT)
    {
        error_at(p, "parse_for_stmt: expected variable name after FOR", true);
    }
    var_name = (((*p)).current).start;
    var_len = (((*p)).current).length;
    advance(p);
    consume(p, TOK_COLON_EQ, "parse_for_stmt: expected ':='' afer FOR variable");
    start_expr = TParser__parse_expr(&(*p));
    if (start_expr == nil)
    {
        error_at(p, "parse_for_stmt: expected expression after ':='", true);
    }
    skip_layout_breaks(p);
    const bool is_downto_l646_c15 = match(p, TOK_KEYWORD_DOWNTO);
    if (!is_downto_l646_c15)
    {
        consume(p, TOK_KEYWORD_TO, "parse_for_stmt: expected TO or DOWNTO after start expression");
    }
    end_expr = TParser__parse_expr(&(*p));
    if (end_expr == nil)
    {
        error_at(p, "parse_for_stmt: expected end expression after TO/DOWNTO", true);
    }
    step = 1;
    skip_layout_breaks(p);
    if (match(p, TOK_KEYWORD_BY))
    {
        Node* step_expr = TParser__parse_const_expression(&(*p));
        if (step_expr == nil)
        {
            error_at(p, "parse_for_stmt: expected constant expession after BY", true);
        }
        if (((*step_expr)).kind == NODE_LITERAL && (((*step_expr)).token).kind == TOK_NUMBER)
        {
            step = (int)utils_parse_integer_literal((((*step_expr)).token).start, (((*step_expr)).token).length);
            if (step == 0)
            {
                step = 1;
            }
        }
        else
        {
            step = 1;
        }
    }
    consume(p, TOK_KEYWORD_DO, "parse_for_stmt: expected DO after FOR header");
    n = node_create(((*p)).arena, NODE_FOR, for_tok);
    (((*n)).for_stmt).var_name = var_name;
    (((*n)).for_stmt).var_len = var_len;
    (((*n)).for_stmt).start_ = start_expr;
    (((*n)).for_stmt).end_ = end_expr;
    (((*n)).for_stmt).step = (is_downto_l646_c15 ? -step : step);
    (((*n)).for_stmt).invariants = nil;
    (((*n)).for_stmt).invariant_count = 0;
    (((*n)).for_stmt).invariant_capacity = 0;
    skip_empty_statements(p);
    while (check(p, TOK_KEYWORD_INVARIANT))
    {
        {
            Node* expr = nil;
            advance(p);
            expr = TParser__parse_expr(&(*p));
            if (expr == nil)
            {
                error_at(p, "parse_for_stmt: expected expression afer INVARIANT", true);
            }
            if (!matchEOS(p))
            {
                error_at(p, "parse_for_stmt: expected end-of-statement after INVARIANT expression", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*n)).for_stmt).invariants), &(((*n)).for_stmt).invariant_count, &(((*n)).for_stmt).invariant_capacity, expr);
            skip_empty_statements(p);
        }
    }
    (((*n)).for_stmt).body = TParser__parse_statement_sequence(&(*p));
    consume(p, TOK_KEYWORD_END, "parse_for_stmt: expected END at end of FOR statements");
    if (check(p, TOK_IDENT))
    {
        advance(p);
    }
    if (!matchEOS(p))
    {
    }
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_FOR); /* postcodition */
/* return value captured before defers */
    Node* __ret_l726 = n;
    return __ret_l726;
}

/**
 * Parse REPEAT ... UNTIL statement
 */
Node* parse_repeat_until_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    TToken repeat_tok = ((*p)).current;
    Node* n = nil;
    Node* cond = nil;
    consume(p, TOK_KEYWORD_REPEAT, "parse_repeat_until_stmt: expected REPEAT");
    n = node_create(((*p)).arena, NODE_REPEAT_UNTIL, repeat_tok);
    (((*n)).repeat_until).invariants = nil;
    (((*n)).repeat_until).invariant_count = 0;
    (((*n)).repeat_until).invariant_capacity = 0;
    skip_empty_statements(p);
    while (check(p, TOK_KEYWORD_INVARIANT))
    {
        {
            Node* expr = nil;
            advance(p);
            expr = TParser__parse_expr(&(*p));
            if (expr == nil)
            {
                error_at(p, "parse_repeat_until_stmt: expected expression after INVARIANT", true);
            }
            if (!matchEOS(p))
            {
                error_at(p, "parse_repeat_until_stmt: expected end-of-statement after INVARIANT expression", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*n)).repeat_until).invariants), &(((*n)).repeat_until).invariant_count, &(((*n)).repeat_until).invariant_capacity, expr);
            skip_empty_statements(p);
        }
    }
    (((*n)).repeat_until).body = TParser__parse_statement_sequence(&(*p));
    consume(p, TOK_KEYWORD_UNTIL, "parse_repeat_until_stmt: expected UNTIL after REPEAT body");
    cond = TParser__parse_expr(&(*p));
    if (cond == nil)
    {
        error_at(p, "parse_repeat_until_stmt: expected condition after UNTIL", true);
    }
    (((*n)).repeat_until).cond = cond;
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_REPEAT_UNTIL); /* postcodition */
/* return value captured before defers */
    Node* __ret_l784 = n;
    return __ret_l784;
}

/**
 * Parse LOOP statement
 */
Node* parse_loop_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    Node* n = nil;
    TToken loop_tok = ((*p)).current;
    consume(p, TOK_KEYWORD_LOOP, "parse_loop_stmt: expected LOOP");
    n = node_create(((*p)).arena, NODE_LOOP, loop_tok);
    (((*n)).loop_stmt).invariants = nil;
    (((*n)).loop_stmt).invariant_count = 0;
    (((*n)).loop_stmt).invariant_capacity = 0;
    skip_empty_statements(p);
    while (check(p, TOK_KEYWORD_INVARIANT))
    {
        {
            Node* expr = nil;
            advance(p);
            expr = TParser__parse_expr(&(*p));
            if (expr == nil)
            {
                error_at(p, "parse_loop_stmt: expected expression after INVARIANT", true);
            }
            if (!matchEOS(p))
            {
                error_at(p, "parse_loop_stmt: expected end-of-statement after INVARIANT expression", true);
            }
            arena_append_ptr(((*p)).arena, (ppvoid)(&(((*n)).loop_stmt).invariants), &(((*n)).loop_stmt).invariant_count, &(((*n)).loop_stmt).invariant_capacity, expr);
            skip_empty_statements(p);
        }
    }
    (((*n)).loop_stmt).body = TParser__parse_statement_sequence(&(*p));
    consume(p, TOK_KEYWORD_END, "parse_loop_stmt: expected END after LOOP statements");
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_LOOP); /* postcodition */
/* return value captured before defers */
    Node* __ret_l835 = n;
    return __ret_l835;
}

/**
 * Parse INC / DEC statement
 * Grammar:
 * 		inc-stmt = "INC" "(" designator [ "," expression ] ")"
 * 		dec-stmt = "DEC" "(" designator [ "," expression ] ")"
 */
Node* parse_inc_dec_stmt(pParser p)
{
    assert(p != nil); /* precondition */
    Node* n = nil;
    TToken tok = ((*p)).current;
    Node* designator = nil;
    Node* step = nil;
    bool is_inc = match(p, TOK_KEYWORD_INC);
    if (!is_inc)
    {
        consume(p, TOK_KEYWORD_DEC, "parse_inc_dec_stmt: expected INC or DEC");
    }
    consume(p, TOK_LPAREN, "parse_inc_dec_stmt: expected '(' after INC/DEC");
    designator = TParser__parse_designator(&(*p));
    if (designator == nil)
    {
        error_at(p, "parse_inc_dec_stmt: expected designator in INC/DEC", true);
    }
    if (match(p, TOK_COMMA))
    {
        step = TParser__parse_expr(&(*p));
        if (step == nil)
        {
            error_at(p, "parse_inc_dec_stmt: expected expression afer comma in INC/DEC", true);
        }
    }
    consume(p, TOK_RPAREN, "parse_inc_dec_stmt: expected ')' after INC/DEC arguments");
    if (!matchEOS(p))
    {
        error_at(p, "parse_inc_dec_stmt: expected end-of-statement after INC/DEC", true);
    }
    n = node_create(((*p)).arena, (is_inc ? NODE_INC : NODE_DEC), tok);
    (((*n)).binary).left = designator;
    (((*n)).binary).right = step;
    (((*n)).binary).op = (is_inc ? TOK_ADD : TOK_SUB);
    /* ENSURE (on return) */
    assert(((*n)).kind == NODE_INC || ((*n)).kind == NODE_DEC); /* postcodition */
/* return value captured before defers */
    Node* __ret_l888 = n;
    return __ret_l888;
}


void statement(void)
{
}
