import { Pos } from "./token.ts";
import { VType } from "./vtype.ts";

export type Ast = File[];

export type File = {
    path: string;
    stmts: Stmt[];
};

export type Stmt = {
    kind: StmtKind;
    pos: Pos;
    id: number;
};

export type StmtKind =
    | { type: "error" }
    | { type: "import"; path: Expr }
    | { type: "break"; expr?: Expr }
    | { type: "return"; expr?: Expr }
    | {
        type: "fn";
        ident: string;
        params: Param[];
        returnType?: EType;
        body: Expr;
        anno?: Anno;
        vtype?: VType;
    }
    | { type: "let"; param: Param; value: Expr }
    | { type: "assign"; subject: Expr; value: Expr }
    | { type: "expr"; expr: Expr };

export type Expr = {
    kind: ExprKind;
    pos: Pos;
    vtype?: VType;
    id: number;
};

export type ExprKind =
    | { type: "error" }
    | { type: "int"; value: number }
    | { type: "string"; value: string }
    | { type: "ident"; value: string }
    | { type: "group"; expr: Expr }
    | { type: "field"; subject: Expr; value: string }
    | { type: "index"; subject: Expr; value: Expr }
    | { type: "call"; subject: Expr; args: Expr[] }
    | { type: "unary"; unaryType: UnaryType; subject: Expr }
    | { type: "binary"; binaryType: BinaryType; left: Expr; right: Expr }
    | { type: "if"; cond: Expr; truthy: Expr; falsy?: Expr }
    | { type: "bool"; value: boolean }
    | { type: "null" }
    | { type: "loop"; body: Expr }
    | { type: "block"; stmts: Stmt[]; expr?: Expr }
    | {
        type: "sym";
        ident: string;
        sym: Sym;
    };

export type UnaryType = "not";
export type BinaryType =
    | "+"
    | "*"
    | "=="
    | "-"
    | "/"
    | "!="
    | "<"
    | ">"
    | "<="
    | ">="
    | "or"
    | "and";

export type Param = {
    ident: string;
    etype?: EType;
    pos: Pos;
    vtype?: VType;
};

export type Sym = {
    ident: string;
    pos?: Pos;
} & SymKind;

export type SymKind =
    | { type: "let"; stmt: Stmt; param: Param }
    | { type: "let_static"; stmt: Stmt; param: Param }
    | { type: "fn"; stmt: Stmt }
    | { type: "fn_param"; param: Param }
    | { type: "closure"; inner: Sym }
    | { type: "builtin"; builtinId: number };

export type EType = {
    kind: ETypeKind;
    pos: Pos;
    id: number;
};

export type ETypeKind =
    | { type: "error" }
    | { type: "ident"; value: string }
    | { type: "array"; inner: EType }
    | { type: "struct"; fields: Param[] };

export type ETypeParam = {
    ident: string;
    pos: Pos;
    vtype?: VType;
};

export type Anno = {
    ident: string;
    values: Expr[];
    pos: Pos;
};