// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// parser.h -- DVX BASIC parser (recursive descent)
//
// Single-pass compiler: reads tokens from the lexer and emits
// p-code directly via the code generator. No AST. Forward
// references to SUBs/FUNCTIONs are resolved via backpatching.
//
// Embeddable: no DVX dependencies, pure C.

#ifndef DVXBASIC_PARSER_H
#define DVXBASIC_PARSER_H

#include "lexer.h"
#include "codegen.h"
#include "symtab.h"
#include "../runtime/vm.h"

#include <stdint.h>
#include <stdbool.h>

// ============================================================
// Parser state
// ============================================================

// Parse-error string sizes.  PARSE_ERROR_LEN is the final message stored
// on the parser; PARSE_ERR_SCRATCH is used for temporary formatting before
// copying into it (with a "Line N: " prefix).
#define BAS_PARSE_ERROR_LEN    1024
#define BAS_PARSE_ERR_SCRATCH  512

// Optional compile-time validator for CtrlName.Member references.
// The IDE populates this from the project's .frm files + widget DXE
// metadata so typos die at compile time instead of at event-click
// time.  bascomp leaves it NULL (runs on the host, no widget DXEs)
// and falls back to the runtime error net.  Dynamically-created
// controls aren't in the map, so lookupCtrlType returns NULL and
// validation is skipped for those -- no false positives.
typedef struct {
    // Return the widget type name for a control declared in a .frm,
    // or NULL if the control isn't statically known.
    const char *(*lookupCtrlType)(void *ctx, const char *ctrlName);
    // Return true if `methodName` is valid for widget type `wgtType`
    // (or a common method like Refresh/SetFocus).  Called with the
    // type string returned by lookupCtrlType.
    bool        (*isMethodValid)(void *ctx, const char *wgtType, const char *methodName);
    // Return true if `propName` is a valid property on wgtType.
    bool        (*isPropValid)(void *ctx, const char *wgtType, const char *propName);
    void         *ctx;
} BasCtrlValidatorT;


typedef struct {
    BasLexerT    lex;
    BasCodeGenT  cg;
    BasSymTabT   sym;
    char         error[BAS_PARSE_ERROR_LEN];
    bool         hasError;
    int32_t      errorLine;
    int32_t      prevLine;      // line of the previous token (for error reporting)
    int32_t      lastUdtTypeId;  // index of last resolved UDT type from resolveTypeName
    int32_t      optionBase;         // default array lower bound (0 or 1)
    bool         optionCompareText;  // true = case-insensitive string comparison
    bool         optionExplicit;     // true = variables must be declared with DIM
    uint8_t      defType[26];        // default type per letter (A-Z), set by DEFINT etc.
    char         currentProc[BAS_MAX_TOKEN_LEN]; // name of current SUB/FUNCTION
    // Per-form init block tracking
    int32_t      formInitJmpAddr;    // code position of JMP to patch (-1 = none)
    int32_t      formInitCodeStart;  // code position where init block starts (-1 = none)
    // Optional compile-time CtrlName.Member validator (IDE-only).
    const BasCtrlValidatorT *validator;
} BasParserT;

// ============================================================
// API
// ============================================================

// Initialize parser with source text.
void basParserInit(BasParserT *p, const char *source, int32_t sourceLen);

// Attach an optional compile-time validator for CtrlName.Member
// references.  The parser borrows the pointer -- caller owns the
// underlying struct and must keep it alive until basParserFree.
void basParserSetValidator(BasParserT *p, const BasCtrlValidatorT *v);

// Parse the entire source and generate p-code.
// Returns true on success, false on error (check p->error).
bool basParse(BasParserT *p);

// Build a module from the parsed code. Returns NULL on error.
// Caller owns the module and must free with basModuleFree().
BasModuleT *basParserBuildModule(BasParserT *p);

// Free parser resources.
void basParserFree(BasParserT *p);

#endif // DVXBASIC_PARSER_H
