﻿#pragma once
#include <windows.h>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <sstream>
#include "fr_script.h"

// ASTノードの種類
enum NodeType {
    ND_BLOCK, ND_ASSIGN, ND_IF, ND_WHILE, ND_EXIT, ND_BREAK, ND_CONTINUE,
    ND_EXPR_INT, ND_EXPR_STR, ND_VAR, ND_FUNC_CALL, ND_CB_CALL,
    ND_ADD, ND_SUB, ND_MUL, ND_DIV, ND_MOD,
    ND_BIT_OR, ND_BIT_AND, ND_BIT_XOR, ND_BIT_NOT, ND_LSHIFT, ND_RSHIFT,
    ND_EQ, ND_NE, ND_STRICT_EQ, ND_STRICT_NE, ND_LT, ND_GT, ND_LE, ND_GE,
    ND_LOGIC_AND, ND_LOGIC_OR, ND_LOGIC_NOT,
	ND_ADD_ASSIGN, ND_SUB_ASSIGN, ND_MUL_ASSIGN, ND_DIV_ASSIGN, ND_MOD_ASSIGN, ND_RSHIFT_ASSIGN, ND_LSHIFT_ASSIGN, ND_OR_ASSIGN, ND_XOR_ASSIGN, ND_AND_ASSIGN,
	ND_ADD_ASSIGN_AFTER, ND_SUB_ASSIGN_AFTER
};

// 実行結果ステータス
enum ExecStatus { EXEC_NORMAL, EXEC_BREAK, EXEC_CONTINUE, EXEC_EXIT };

// Flexから提供される現在の行番号
extern int yylineno;

// 数値または文字列を保持する汎用型
struct Value {
    bool isString;
    int iVal;
    std::string sVal;

    Value() : isString(false), iVal(0) {}
    Value(int v) : isString(false), iVal(v) {}
    Value(const std::string& v) : isString(true), iVal(0), sVal(v) {}

    // ヘルパー: 数値への強制変換
    int toInt() const {
        if (!isString) return iVal;
        return atoi(sVal.c_str());
    }
    // ヘルパー: 文字列への強制変換
    std::string toStr() const {
        if (isString) return sVal;
        std::stringstream ss; ss << iVal;
        return ss.str();
    }
};

// コールバック用構造体
struct FRCallbackData {
    const char* symbol;
    Value* args;
    int argCount;
};

#ifndef FR_SCRIPT_H
#define FR_SCRIPT_H

// コールバック関数型
typedef int (*FRCallbackFunc)(FRCallbackData*);

// エラー発生時のコールバック
typedef void (*ErrorCallBack)(int errcd, int iLine, LPCWSTR errmes);

// ステップコールバック
typedef int (*StepCallBack)(int iLine);

// MessageBox代替関数
typedef int(WINAPI *PMSGBOXWAPI)(HWND, LPCWSTR, LPCWSTR, UINT);

#endif FR_SCRIPT_H

extern void errorCall(int errcd, int line, const char *msg);

// AST基底クラス
struct Node {
    NodeType type;
	int line; // 行番号保持用

	Node() : line(yylineno) {} // コンストラクタで行番号を自動取得
    virtual ~Node() {}
    virtual Value eval() = 0;
};

// グローバルコンテキスト
struct Context {
    std::map<std::string, Value> variables;
    FRCallbackFunc callback;
	ErrorCallBack errorCallBack;
	StepCallBack stepCallBack;
	PMSGBOXWAPI pMsgBoxW;
    ExecStatus status;
    int exitCode;
	HWND hWnd;

    Context() : callback(NULL), errorCallBack(NULL), stepCallBack(NULL), pMsgBoxW(NULL), status(EXEC_NORMAL), exitCode(0), hWnd(NULL) {}
    void clear() {
        variables.clear();
        status = EXEC_NORMAL;
        exitCode = 0;
    }
};

extern Context g_context;
extern Node* g_root;
extern int yylex();
extern int yyparse();
extern void yyerror(const char* s);

// --- 以下、ノードクラス定義をヘッダーに移動 ---

// 数値リテラル
struct IntNode : Node {
    int val;
    IntNode(int v);
    Value eval();
};

// 文字列リテラル
struct StringNode : Node {
    std::string value;

    StringNode(std::string* s) {
        type = ND_EXPR_STR; // 新しいノードタイプを定義
        if (s) {
            this->value = *s;
            delete s; // Parserから渡されたメモリを解放
        }
    }

    Value eval() {
        return Value(value); // 文字列型のValueを返す
    }
};

// 変数
struct VarNode : Node {
    std::string name;
    VarNode(std::string* n) { // nはlexerで確保されたメモリ
		if (n) {
            this->name = *n; // 内容をコピー
            delete n;        // Lexerで生成されたポインタを破棄
        }
        type = ND_VAR;
	}
    Value eval();
    Value& ref(); // 代入用
};

// 二項演算 (+, -, *, /, ==, && など)
struct BinaryNode : Node {
    Node* lhs;
    Node* rhs;
    BinaryNode(NodeType t, Node* l, Node* r);
    ~BinaryNode();
    Value eval();
};

// 単項演算 (-, !, ~)
struct UnaryNode : Node {
    Node* op;
    UnaryNode(NodeType t, Node* o);
    ~UnaryNode();
    Value eval();
};

// ブロック
struct BlockNode : Node {
    std::vector<Node*> stmts;
    BlockNode();
    ~BlockNode();
    void add(Node* n);
    Value eval();
};

// 代入
struct AssignNode : Node {
    VarNode* var;
    Node* expr;
    int op; // 0: =, 1: +=(変化後の値を返す), 2: +=(変化前の値を返す)
    AssignNode(VarNode* v, Node* e, int o);
    ~AssignNode();
    Value eval();
};

// IF文
struct IfNode : Node {
    Node* cond;
    Node* thenBlock;
    Node* elseBlock;
    IfNode(Node* c, Node* t, Node* e);
    ~IfNode();
    Value eval();
};

// WHILE文
struct WhileNode : Node {
    Node* cond;
    Node* block;
    bool isLoop;
    WhileNode(Node* c, Node* b, bool loop=false);
    ~WhileNode();
    Value eval();
};

// 関数呼び出し
struct FuncCallNode : Node {
    std::string name;
    std::vector<Node*> args;
    FuncCallNode(std::string* n);
    ~FuncCallNode();
    void addArg(Node* n);
    Value eval();
};

// コールバック呼び出し
struct CBCallNode : Node {
    std::string name;
    std::vector<Node*> args;
    CBCallNode(std::string* n);
    ~CBCallNode();
    void addArg(Node* n);
    Value eval();
};

// パース用一時リスト（args処理用）
struct ListNode : Node {
    std::vector<Node*> nodes;
    ListNode();
    Value eval();
    void push(Node* n);
};

// 文だけを表す単純ノード（BREAK, CONTINUE, EXIT用）
// ※前回のコードでは直接処理していましたが、汎用化のため追加してもOKです。
// 今回は前回コードに合わせて、これらはBisonアクション内で処理するか、
// 必要なら以下のように定義して実装してください。
struct FlowNode : Node {
    FlowNode(NodeType t);
    Value eval();
};

struct ExitNode : Node {
    Node* expr;
    ExitNode(Node* e = NULL);
    ~ExitNode();
    Value eval();
};
