-- | Contains all AST elements, all of these produced by the [Parser]("Parser.Parser") module.
module Parser.Ast where

import Data.Text (Text)
import MaybeVoid (MaybeVoid)

--------------------------------------------------------Program---------------------------------------------------------

-- * Program

-- | The head of the AST.
data Program = Program
  { -- | Top level variable declarations.
    Program -> [VarDecl]
topLevelVarDecls :: [VarDecl],
    -- | Top level function definitions.
    Program -> [FunctionDef]
topLevelFunctionDefs :: [FunctionDef]
  }
  deriving (Int -> Program -> ShowS
[Program] -> ShowS
Program -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Program] -> ShowS
$cshowList :: [Program] -> ShowS
show :: Program -> String
$cshow :: Program -> String
showsPrec :: Int -> Program -> ShowS
$cshowsPrec :: Int -> Program -> ShowS
Show)

-- | Function definition.
data FunctionDef = FunctionDef {FunctionDef -> Identifier
funcName :: Identifier, FunctionDef -> Function
func :: Function}
  deriving (Int -> FunctionDef -> ShowS
[FunctionDef] -> ShowS
FunctionDef -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FunctionDef] -> ShowS
$cshowList :: [FunctionDef] -> ShowS
show :: FunctionDef -> String
$cshow :: FunctionDef -> String
showsPrec :: Int -> FunctionDef -> ShowS
$cshowsPrec :: Int -> FunctionDef -> ShowS
Show)

------------------------------------------------------Expressions-------------------------------------------------------

-- * Expressions

-- | Expression.
data Expression
  = -- | Value expression, see 'Value'.
    ExprValue Value
  | -- | Identifier expression, see 'Identifier'.
    ExprIdentifier Identifier
  | -- | Unary operation expression (e.g., @!x@, @-4@), see 'UnaryOp'.
    ExprUnaryOp UnaryOp Expression
  | -- | Binary operation expression (e.g., @x + 7@), see 'BinaryOp'.
    ExprBinaryOp BinaryOp Expression Expression
  | -- | Array access by index expression.
    --
    -- > a[3]
    --
    -- > // func foo() int
    -- > ([2] int {3, 5})[1 + foo()]
    ExprArrayAccessByIndex Expression Expression
  | -- | Function call expression.
    --
    -- > foo(17, x, bar())
    --
    -- > (func (x int) int { return x * x; })(3)
    ExprFuncCall Expression [Expression]
  | -- | @len@ function call expression.
    --
    -- > len("abcd") // returns 4
    --
    -- > len([100] int {}) // returns 100
    ExprLenFuncCall Expression
  | -- | @print@ function call expression.
    --
    -- > print("some logs...") // prints "some logs..."
    --
    -- > print(3 + 6)  // prints "9"
    --
    -- > print("abc", 2) // prints "abc2"
    ExprPrintFuncCall [Expression]
  | -- | @println@ function call expression.
    --
    -- > println("some logs...") // prints "some logs...\n"
    --
    -- > println(3 + 6)  // prints "9\n"
    --
    -- > println("abc", 2) // prints "abc 2\n"
    ExprPrintlnFuncCall [Expression]
  | -- | @panic@ function call expression.
    --
    -- > panic("ERROR!!!") // fails with "panic: ERROR!!!\n"
    ExprPanicFuncCall Expression
  deriving (Int -> Expression -> ShowS
[Expression] -> ShowS
Expression -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Expression] -> ShowS
$cshowList :: [Expression] -> ShowS
show :: Expression -> String
$cshow :: Expression -> String
showsPrec :: Int -> Expression -> ShowS
$cshowsPrec :: Int -> Expression -> ShowS
Show)

-- ** Operators

-- | Binary operators.
data BinaryOp
  = -- | Or operator (@a || b@), works only for @bool@.
    OrOp
  | -- | And operator (@a && b@), works only for @bool@.
    AndOp
  | -- | Equality operator (@a == b@).
    EqOp
  | -- | Inequality operator (@a != b@).
    NeOp
  | -- | Less than or equal operator (@a <= b@), works only for @int@ and @string@.
    LeOp
  | -- | Less than operator (@a < b@), works only for @int@ and @string@.
    LtOp
  | -- | More than or equal operator (@a >= b@), works only for @int@ and @string@.
    MeOp
  | -- | More than operator (@a > b@), works only for @int@ and @string@.
    MtOp
  | -- | Plus operator (@a + b@), works only for @int@ and @string@.
    PlusOp
  | -- | Minus operator (@a - b@), works only for @int@.
    MinusOp
  | -- | Multiply operator (@a * b@), works only for @int@.
    MultOp
  | -- | Divide operator (@a / b@), works only for @int@.
    DivOp
  | -- | Modulus operator (@a % b@), works only for @int@.
    ModOp
  deriving (Int -> BinaryOp -> ShowS
[BinaryOp] -> ShowS
BinaryOp -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BinaryOp] -> ShowS
$cshowList :: [BinaryOp] -> ShowS
show :: BinaryOp -> String
$cshow :: BinaryOp -> String
showsPrec :: Int -> BinaryOp -> ShowS
$cshowsPrec :: Int -> BinaryOp -> ShowS
Show)

-- | Unary operators.
data UnaryOp
  = -- | Unary plus operator (@+a@), works only for @int@.
    UnaryPlusOp
  | -- | Unary minus operator (@-a@), works only for @int@.
    UnaryMinusOp
  | -- | Not operator (@!a@), works only for @bool@.
    NotOp
  deriving (Int -> UnaryOp -> ShowS
[UnaryOp] -> ShowS
UnaryOp -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnaryOp] -> ShowS
$cshowList :: [UnaryOp] -> ShowS
show :: UnaryOp -> String
$cshow :: UnaryOp -> String
showsPrec :: Int -> UnaryOp -> ShowS
$cshowsPrec :: Int -> UnaryOp -> ShowS
Show)

---------------------------------------------------------Types----------------------------------------------------------

-- * Types

-- | All existing types.
data Type
  = -- | 32-bit/64-bit (depending on the machine) integer type.
    TInt
  | -- | Boolean type.
    TBool
  | -- | String type.
    TString
  | -- | Array type, see 'ArrayType'.
    TArray ArrayType
  | -- | Function type, see 'FunctionType'.
    TFunction FunctionType
  deriving (Int -> Type -> ShowS
[Type] -> ShowS
Type -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Type] -> ShowS
$cshowList :: [Type] -> ShowS
show :: Type -> String
$cshow :: Type -> String
showsPrec :: Int -> Type -> ShowS
$cshowsPrec :: Int -> Type -> ShowS
Show)

-- | Array type, it contains the length of the array and its elements type.
--
-- > [3 + 4] int
data ArrayType = ArrayType {ArrayType -> Type
arrElementT :: Type, ArrayType -> Expression
arrLength :: Expression}
  deriving (Int -> ArrayType -> ShowS
[ArrayType] -> ShowS
ArrayType -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ArrayType] -> ShowS
$cshowList :: [ArrayType] -> ShowS
show :: ArrayType -> String
$cshow :: ArrayType -> String
showsPrec :: Int -> ArrayType -> ShowS
$cshowsPrec :: Int -> ArrayType -> ShowS
Show)

-- | Function type, it contains the result of the function and its parameters types.
--
-- > func (int, string) bool
--
-- > func ([3] int)
data FunctionType = FunctionType {FunctionType -> [Type]
funcParamsTs :: [Type], FunctionType -> MaybeVoid Type
funcResultT :: MaybeVoid Type}
  deriving (Int -> FunctionType -> ShowS
[FunctionType] -> ShowS
FunctionType -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FunctionType] -> ShowS
$cshowList :: [FunctionType] -> ShowS
show :: FunctionType -> String
$cshow :: FunctionType -> String
showsPrec :: Int -> FunctionType -> ShowS
$cshowsPrec :: Int -> FunctionType -> ShowS
Show)

-------------------------------------------------------Statements-------------------------------------------------------

-- * Statements

-- | Statement.
data Statement
  = -- | Return statement with optional return value.
    StmtReturn (MaybeVoid Expression)
  | -- | For goto statement, see 'ForGoTo'.
    StmtForGoTo ForGoTo
  | -- | For statement, see 'For'.
    StmtFor For
  | -- | Var declaration statement, see 'VarDecl'.
    StmtVarDecl VarDecl
  | -- | If-else statement, see 'IfElse'.
    StmtIfElse IfElse
  | -- | Block statement, see 'Block'.
    --
    -- > { 34; foo(34); if true {} else {}; return 17; }
    StmtBlock Block
  | -- | Simple statement, see 'SimpleStmt'.
    StmtSimple SimpleStmt
  deriving (Int -> Statement -> ShowS
[Statement] -> ShowS
Statement -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Statement] -> ShowS
$cshowList :: [Statement] -> ShowS
show :: Statement -> String
$cshow :: Statement -> String
showsPrec :: Int -> Statement -> ShowS
$cshowsPrec :: Int -> Statement -> ShowS
Show)

-- | Block of statements.
type Block = [Statement]

-- | For goto statement (either @break@ or @continue@), should be inside @for@.
data ForGoTo
  = -- | Break statement.
    Break
  | -- | Continue statement.
    Continue
  deriving (Int -> ForGoTo -> ShowS
[ForGoTo] -> ShowS
ForGoTo -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ForGoTo] -> ShowS
$cshowList :: [ForGoTo] -> ShowS
show :: ForGoTo -> String
$cshow :: ForGoTo -> String
showsPrec :: Int -> ForGoTo -> ShowS
$cshowsPrec :: Int -> ForGoTo -> ShowS
Show)

-- | For statement, can represent any of the 3 possible @for@ kinds.
--
-- For kind, represents classic @for@ loop.
--
-- > for i := 0; i < n; i++ {
-- >   foo(i * i);
-- > }
--
-- > for ; ; {} // same as `for {}`
--
-- While kind, represents classic @while@ loop.
--
-- > for i < n {
-- >   foo(i * i);
-- >   i = i + 2;
-- > }
--
-- Loop kind, represents endless loop (@while true@).
--
-- > for {
-- >   temp := foo(i * i * i);
-- >   if temp == 108 { break; }
-- >   i = i + 23;
data For = For {For -> ForHead
forHead :: ForHead, For -> [Statement]
forBody :: Block}
  deriving (Int -> For -> ShowS
[For] -> ShowS
For -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [For] -> ShowS
$cshowList :: [For] -> ShowS
show :: For -> String
$cshow :: For -> String
showsPrec :: Int -> For -> ShowS
$cshowsPrec :: Int -> For -> ShowS
Show)

-- | For statement, can represent any of the 3 possible @for@ kinds.
data ForHead = ForHead
  { ForHead -> Maybe SimpleStmt
forPreStmt :: Maybe SimpleStmt,
    ForHead -> Maybe Expression
forCondition :: Maybe Expression,
    ForHead -> Maybe SimpleStmt
forPostStmt :: Maybe SimpleStmt
  }
  deriving (Int -> ForHead -> ShowS
[ForHead] -> ShowS
ForHead -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ForHead] -> ShowS
$cshowList :: [ForHead] -> ShowS
show :: ForHead -> String
$cshow :: ForHead -> String
showsPrec :: Int -> ForHead -> ShowS
$cshowsPrec :: Int -> ForHead -> ShowS
Show)

-- | Var declaration.
--
-- > var x int = 3
--
-- > var y = "hello"
--
-- > var z int
data VarDecl = VarDecl {VarDecl -> Identifier
varName :: Identifier, VarDecl -> VarValue
varValue :: VarValue}
  deriving (Int -> VarDecl -> ShowS
[VarDecl] -> ShowS
VarDecl -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [VarDecl] -> ShowS
$cshowList :: [VarDecl] -> ShowS
show :: VarDecl -> String
$cshow :: VarDecl -> String
showsPrec :: Int -> VarDecl -> ShowS
$cshowsPrec :: Int -> VarDecl -> ShowS
Show)

-- | Var value.
data VarValue
  = VarValue (Maybe Type) Expression
  | DefaultedVarValue Type
  deriving (Int -> VarValue -> ShowS
[VarValue] -> ShowS
VarValue -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [VarValue] -> ShowS
$cshowList :: [VarValue] -> ShowS
show :: VarValue -> String
$cshow :: VarValue -> String
showsPrec :: Int -> VarValue -> ShowS
$cshowsPrec :: Int -> VarValue -> ShowS
Show)

-- | If-else statement.
--
-- > if i < 42 { return "hello"; } else { return "goodbye"; }
--
-- > if true { println("hello"); }
data IfElse = IfElse
  { IfElse -> Maybe SimpleStmt
ifPreStmt :: Maybe SimpleStmt,
    IfElse -> Expression
ifCondition :: Expression,
    IfElse -> [Statement]
ifBody :: Block,
    IfElse -> Else
elseStmt :: Else
  }
  deriving (Int -> IfElse -> ShowS
[IfElse] -> ShowS
IfElse -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IfElse] -> ShowS
$cshowList :: [IfElse] -> ShowS
show :: IfElse -> String
$cshow :: IfElse -> String
showsPrec :: Int -> IfElse -> ShowS
$cshowsPrec :: Int -> IfElse -> ShowS
Show)

-- | Else part of the if-else statement.
data Else = NoElse | Else Block | Elif IfElse
  deriving (Int -> Else -> ShowS
[Else] -> ShowS
Else -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Else] -> ShowS
$cshowList :: [Else] -> ShowS
show :: Else -> String
$cshow :: Else -> String
showsPrec :: Int -> Else -> ShowS
$cshowsPrec :: Int -> Else -> ShowS
Show)

-- | Simple statement, its main difference between other statements is that it can be used inside @for@ \"pre\" and \"post\" statements.
--
-- > for i := 0; i < n; i++ { println(i); }
data SimpleStmt
  = -- | Assignment statement (e.g., @x = 17@, @a[3] = \"42\"@).
    StmtAssignment Lvalue Expression
  | -- | Increment or decrement statement (e.g., @x++@, @a[3]++@, @x--@, @a[3]--@).
    StmtIncDec Lvalue IncDec
  | -- | Short var declaration statement (e.g., @x := 3@, @y := true@).
    StmtShortVarDecl Identifier Expression
  | -- | Expression statement.
    StmtExpression Expression
  deriving (Int -> SimpleStmt -> ShowS
[SimpleStmt] -> ShowS
SimpleStmt -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SimpleStmt] -> ShowS
$cshowList :: [SimpleStmt] -> ShowS
show :: SimpleStmt -> String
$cshow :: SimpleStmt -> String
showsPrec :: Int -> SimpleStmt -> ShowS
$cshowsPrec :: Int -> SimpleStmt -> ShowS
Show)

-- | Lvalue, i.e. an expression that can be placed on the left-hand side of the assignment, increment, or decrement statements.
data Lvalue
  = -- | Any variable can be lvalue (e.g., @x = 3@, @x++@).
    LvalVar Identifier
  | -- | Any array element can be lvalue (e.g., @a[5][7] = 3@, @a[0]++@).
    LvalArrEl Identifier [Expression]
  deriving (Int -> Lvalue -> ShowS
[Lvalue] -> ShowS
Lvalue -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Lvalue] -> ShowS
$cshowList :: [Lvalue] -> ShowS
show :: Lvalue -> String
$cshow :: Lvalue -> String
showsPrec :: Int -> Lvalue -> ShowS
$cshowsPrec :: Int -> Lvalue -> ShowS
Show)

-- | Increment or decrement.
data IncDec = Inc | Dec
  deriving (Int -> IncDec -> ShowS
[IncDec] -> ShowS
IncDec -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [IncDec] -> ShowS
$cshowList :: [IncDec] -> ShowS
show :: IncDec -> String
$cshow :: IncDec -> String
showsPrec :: Int -> IncDec -> ShowS
$cshowsPrec :: Int -> IncDec -> ShowS
Show)

---------------------------------------------------------Values---------------------------------------------------------

-- * Values

-- | Literal, array, or function value.
data Value
  = -- | Int literal value (e.g., @17@, @0xFF@, @0b101001@).
    ValInt Integer
  | -- | Boolean literal value (e.g., @true@, @false@).
    ValBool Bool
  | -- | String literal value (e.g., @\"Hello\"@, @\"\"@, @\"Some\\ntext\"@).
    ValString Text
  | -- | Array value, see 'ArrayValue'.
    ValArray ArrayValue
  | -- | Function value, see 'FunctionValue'.
    ValFunction FunctionValue
  deriving (Int -> Value -> ShowS
[Value] -> ShowS
Value -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Value] -> ShowS
$cshowList :: [Value] -> ShowS
show :: Value -> String
$cshow :: Value -> String
showsPrec :: Int -> Value -> ShowS
$cshowsPrec :: Int -> Value -> ShowS
Show)

-- | Array value.
--
-- > [3] int {1, 2}
--
-- > [10] bool {}
data ArrayValue = ArrayValue {ArrayValue -> ArrayType
arrT :: ArrayType, ArrayValue -> [Expression]
arrElements :: [Expression]}
  deriving (Int -> ArrayValue -> ShowS
[ArrayValue] -> ShowS
ArrayValue -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ArrayValue] -> ShowS
$cshowList :: [ArrayValue] -> ShowS
show :: ArrayValue -> String
$cshow :: ArrayValue -> String
showsPrec :: Int -> ArrayValue -> ShowS
$cshowsPrec :: Int -> ArrayValue -> ShowS
Show)

-- | Function value.
data FunctionValue
  = -- | Anonymous function, see 'Function'.
    --
    -- > func (x int) int { return x * x; }
    --
    -- > func () {}
    AnonymousFunction Function
  | -- | Null literal (@nil@).
    Nil
  deriving (Int -> FunctionValue -> ShowS
[FunctionValue] -> ShowS
FunctionValue -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FunctionValue] -> ShowS
$cshowList :: [FunctionValue] -> ShowS
show :: FunctionValue -> String
$cshow :: FunctionValue -> String
showsPrec :: Int -> FunctionValue -> ShowS
$cshowsPrec :: Int -> FunctionValue -> ShowS
Show)

-- | Function representation without name.
--
-- It contains the result of the function, its parameters, and its body.
data Function = Function {Function -> [(Identifier, Type)]
funcParams :: [(Identifier, Type)], Function -> MaybeVoid Type
funcResult :: MaybeVoid Type, Function -> [Statement]
funcBody :: Block}
  deriving (Int -> Function -> ShowS
[Function] -> ShowS
Function -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Function] -> ShowS
$cshowList :: [Function] -> ShowS
show :: Function -> String
$cshow :: Function -> String
showsPrec :: Int -> Function -> ShowS
$cshowsPrec :: Int -> Function -> ShowS
Show)

-- | Any valid identifier (e.g., @he42llo@, @_42@).
type Identifier = Text