{-# LANGUAGE LambdaCase, FlexibleContexts #-}

-- | Abstract Syntax Tree (AST) definitions for the simple functional language.
module Syntax where

-- | Identifier type, representing variable and function names.
type Ident = String

-- | A program is simply a list of declarations (functions).
data Program = Program [Decl]
  deriving (Int -> Program -> ShowS
[Program] -> ShowS
Program -> String
(Int -> Program -> ShowS)
-> (Program -> String) -> ([Program] -> ShowS) -> Show Program
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)

-- | A top-level declaration consists of a function name, its parameters, and its body expression.
data Decl = FunDecl Ident [Ident] Expr
  deriving (Int -> Decl -> ShowS
[Decl] -> ShowS
Decl -> String
(Int -> Decl -> ShowS)
-> (Decl -> String) -> ([Decl] -> ShowS) -> Show Decl
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Decl] -> ShowS
$cshowList :: [Decl] -> ShowS
show :: Decl -> String
$cshow :: Decl -> String
showsPrec :: Int -> Decl -> ShowS
$cshowsPrec :: Int -> Decl -> ShowS
Show)

-- | Expressions in the language.
data Expr
  = Var Ident                -- ^ Variable reference
  | Lit Literal              -- ^ Literal constant
  | Lambda [Ident] Expr      -- ^ Lambda abstraction with parameters and body
  | If Expr Expr Expr        -- ^ Conditional: if <cond> then <then> else <else>
  | Case Expr [(Pattern, Expr)] -- ^ Pattern matching: case <expr> of <alternatives>
  | Let [Decl] Expr          -- ^ Local declarations and body expression
  | App Expr Expr            -- ^ Function application
  | BinOp BinOperator Expr Expr -- ^ Binary operator application
  | UnOp UnOperator Expr     -- ^ Unary operator application
  | List [Expr]              -- ^ List literal
  | Tuple [Expr]             -- ^ Tuple literal
  deriving (Int -> Expr -> ShowS
[Expr] -> ShowS
Expr -> String
(Int -> Expr -> ShowS)
-> (Expr -> String) -> ([Expr] -> ShowS) -> Show Expr
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Expr] -> ShowS
$cshowList :: [Expr] -> ShowS
show :: Expr -> String
$cshow :: Expr -> String
showsPrec :: Int -> Expr -> ShowS
$cshowsPrec :: Int -> Expr -> ShowS
Show)

-- | Patterns used in case alternatives.
data Pattern
  = PWildcard                -- ^ Matches anything ("_" pattern)
  | PVar Ident               -- ^ Variable pattern, binds the identifier
  | PLit Literal             -- ^ Literal pattern
  | PList [Pattern]          -- ^ List pattern
  | PTuple [Pattern]         -- ^ Tuple pattern
  deriving (Int -> Pattern -> ShowS
[Pattern] -> ShowS
Pattern -> String
(Int -> Pattern -> ShowS)
-> (Pattern -> String) -> ([Pattern] -> ShowS) -> Show Pattern
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Pattern] -> ShowS
$cshowList :: [Pattern] -> ShowS
show :: Pattern -> String
$cshow :: Pattern -> String
showsPrec :: Int -> Pattern -> ShowS
$cshowsPrec :: Int -> Pattern -> ShowS
Show)

-- | Literal values supported by the language.
data Literal
  = LInt Int                 -- ^ Integer literal
  | LFloat Double            -- ^ Floating-point literal
  | LChar Char               -- ^ Character literal
  | LString String           -- ^ String literal
  | LBool Bool               -- ^ Boolean literal
  deriving (Int -> Literal -> ShowS
[Literal] -> ShowS
Literal -> String
(Int -> Literal -> ShowS)
-> (Literal -> String) -> ([Literal] -> ShowS) -> Show Literal
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Literal] -> ShowS
$cshowList :: [Literal] -> ShowS
show :: Literal -> String
$cshow :: Literal -> String
showsPrec :: Int -> Literal -> ShowS
$cshowsPrec :: Int -> Literal -> ShowS
Show)

-- | Binary operators.
data BinOperator
  = Add  -- ^ Addition (+)
  | Sub  -- ^ Subtraction (-)
  | Mul  -- ^ Multiplication (*)
  | Div  -- ^ Division (/)
  | Mod  -- ^ Modulus (mod)
  | Eq   -- ^ Equality (==)
  | Neq  -- ^ Inequality (/=)
  | Lt   -- ^ Less than (<)
  | Le   -- ^ Less than or equal (<=)
  | Gt   -- ^ Greater than (>)
  | Ge   -- ^ Greater than or equal (>=)
  | And  -- ^ Logical and (&&)
  | Or   -- ^ Logical or (||)
  deriving (Int -> BinOperator -> ShowS
[BinOperator] -> ShowS
BinOperator -> String
(Int -> BinOperator -> ShowS)
-> (BinOperator -> String)
-> ([BinOperator] -> ShowS)
-> Show BinOperator
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BinOperator] -> ShowS
$cshowList :: [BinOperator] -> ShowS
show :: BinOperator -> String
$cshow :: BinOperator -> String
showsPrec :: Int -> BinOperator -> ShowS
$cshowsPrec :: Int -> BinOperator -> ShowS
Show)

-- | Unary operators.
data UnOperator
  = Neg  -- ^ Numeric negation (\n -> -n)
  | Not  -- ^ Logical negation (not)
  deriving (Int -> UnOperator -> ShowS
[UnOperator] -> ShowS
UnOperator -> String
(Int -> UnOperator -> ShowS)
-> (UnOperator -> String)
-> ([UnOperator] -> ShowS)
-> Show UnOperator
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UnOperator] -> ShowS
$cshowList :: [UnOperator] -> ShowS
show :: UnOperator -> String
$cshow :: UnOperator -> String
showsPrec :: Int -> UnOperator -> ShowS
$cshowsPrec :: Int -> UnOperator -> ShowS
Show)