import * as SWC from "./swc.ts";

export type Type = "int" | "float" | "string" | "boolean";

export const typeNames: Array<Type> = ["int", "float", "string", "boolean"];
export const validKeys: Record<string, Array<string>> = {
  attr: ["name", "authors", "about"],
  meta: ["username", "hostname", "editVersion", "editMysteryNumber"],
};
export const numOps = [
  "+", "-", "*", "/", "%", "^",
  "<=", ">=", "<", ">", "==", "!="
];
export const boolOps = ["&&", "||", "!", "==", "!="];
export const stringOps = ["+", "==", "!="];

export function validateBinaryOpTypes (
  a: Type,
  b: Type,
  op: SWC.BinaryOperator,
): boolean {
  // For purposes of validation, float and int are the same
  a = a === "float" ? "int" : a;
  b = b === "float" ? "int" : b;
  if (a === b) {
    switch (a) {
      case "int": return numOps.includes(op);
      case "string": return stringOps.includes(op);
      case "boolean": return boolOps.includes(op);
    }
  }
  return [a, b].includes("string") && op === "+";
}

export function validateAssignmentTypes (a: Type, b: Type) {
  return a === b
    || (a === "float" && b === "int")
    || (a === "int" && b === "float");
}

export function castValidBinaryOpTypes (
  a: Type,
  b: Type,
  op: SWC.BinaryOperator
): Type {
  return ["<", ">", "<=", ">=", "==", "!=", "&&", "||"].includes(op)
    ? "boolean"
    : a === b
      ? a
      : [a, b].includes("string") ? "string" : "float";
}