package parser

import (
  "github.com/marzeq/quokka/shared"
)

type NodeType uint

const (
  NODE_TYPE_ROOT NodeType = iota

  NODE_TYPE_IDENTIFIER
  NODE_TYPE_BOOL_LITERAL
  NODE_TYPE_NUMBER_LITERAL
  NODE_TYPE_STRING_LITERAL
  NODE_TYPE_CHAR_LITERAL
  NODE_TYPE_STRUCT_LITERAL

  NODE_TYPE_FUNCTION_CALL

  NODE_TYPE_IF_EXPR

  NODE_TYPE_UNARY_OP
  NODE_TYPE_BINARY_OP

  NODE_TYPE_CAST

  NODE_TYPE_IMPORT
  NODE_TYPE_FUNCTION_DEF
  NODE_TYPE_STRUCT_DEF
  NODE_TYPE_IF
  NODE_TYPE_FOR
  NODE_TYPE_CONTROL_KEYWORD

  NODE_TYPE_DECLARATION
  NODE_TYPE_ASSIGNMENT

  NODE_TYPE_BLOCK
)

func (nt NodeType) IsExpression() bool {
  return nt == NODE_TYPE_IDENTIFIER ||
    nt == NODE_TYPE_BOOL_LITERAL ||
    nt == NODE_TYPE_NUMBER_LITERAL ||
    nt == NODE_TYPE_STRING_LITERAL ||
    nt == NODE_TYPE_CHAR_LITERAL ||
    nt == NODE_TYPE_STRUCT_LITERAL ||
    nt == NODE_TYPE_FUNCTION_CALL ||
    nt == NODE_TYPE_IF_EXPR ||
    nt == NODE_TYPE_UNARY_OP ||
    nt == NODE_TYPE_BINARY_OP ||
    nt == NODE_TYPE_CAST
}

func (nt NodeType) IsStatement() bool {
  return !nt.IsExpression()
}

func (nt NodeType) String() string {
  switch nt {
  case NODE_TYPE_ROOT:
    return "ROOT"
  case NODE_TYPE_IDENTIFIER:
    return "IDENTIFIER"
  case NODE_TYPE_CONTROL_KEYWORD:
    return "CONTROL_KEYWORD"
  case NODE_TYPE_NUMBER_LITERAL:
    return "NUMBER_LITERAL"
  case NODE_TYPE_STRING_LITERAL:
    return "STRING_LITERAL"
  case NODE_TYPE_CHAR_LITERAL:
    return "CHAR_LITERAL"
  case NODE_TYPE_BOOL_LITERAL:
    return "BOOL_LITERAL"
  case NODE_TYPE_STRUCT_LITERAL:
    return "STRUCT_LITERAL"
  case NODE_TYPE_FUNCTION_CALL:
    return "FUNCTION_CALL"
  case NODE_TYPE_UNARY_OP:
    return "UNARY_OP"
  case NODE_TYPE_BINARY_OP:
    return "BINARY_OP"
  case NODE_TYPE_CAST:
    return "CAST"
  case NODE_TYPE_IF:
    return "IF"
  case NODE_TYPE_IF_EXPR:
    return "IF_EXPR"
  case NODE_TYPE_DECLARATION:
    return "DECLARATION"
  case NODE_TYPE_ASSIGNMENT:
    return "ASSIGNMENT"
  case NODE_TYPE_BLOCK:
    return "BLOCK"
  case NODE_TYPE_FUNCTION_DEF:
    return "FUNCTION_DEF"
  case NODE_TYPE_STRUCT_DEF:
    return "STRUCT_DEF"
  case NODE_TYPE_IMPORT:
    return "IMPORT"
  case NODE_TYPE_FOR:
    return "FOR"
  default:
    return "UNKNOWN"
  }
}

type Node struct {
  Type     NodeType
  ExprType shared.Type
  Value    any
  Left     *Node
  Right    *Node
  Children []*Node
  Loc      shared.Location
}

type IfNodeValue struct {
  IfBranch       *IfBranch
  ElseIfBranches []*IfBranch
  ElseBranch     *IfBranch
}

type IfBranch struct {
  Condition *Node
  Node      *Node
}

type ForLoopValue struct {
  ExprsOrStmts []*Node
  Body         *Node
}

type FunctionValue struct {
  Name        *Node
  Args        []shared.Pair[*Node, *Node]
  RetType     *Node
  HasVariadic bool
}

type StructValue struct {
  Fields []shared.Pair[*Node, *Node]
}

type DeclarationValue struct {
  Mutable bool
  Type    *Node
}

type StructLiteralValue struct {
  StructType *Node
  Fields     []shared.Pair[*Node, *Node]
}