packages feed

canontra-0.1.0.0: src/Canontra/IR/Expression.hs

{- |
Module      : Canontra.IR.Expression
Description : Language-independent syntax expressions, operators, and statements.

Expressions and statements capture the operational pulse of computation across
Python, JavaScript, TypeScript, Go, and Rust. This intermediate representation
strips away source-level syntax quirks while faithfully retaining algebraic operator
precedence, control branches, async semantics, concurrency, and invocation contracts.
-}
module Canontra.IR.Expression
  ( Op (..)
  , Lit (..)
  , FStringPart (..)
  , MatchCase (..)
  , SelectCase (..)
  , Expr (..)
  , Stmt (..)
  , CompFor (..)
  ) where

import Control.DeepSeq (NFData)
import Data.Aeson (FromJSON, ToJSON)
import Data.Text (Text)
import GHC.Generics (Generic)
import Canontra.Types (Parameter)

data Op
  = OpAdd | OpSub | OpMul | OpDiv | OpFloorDiv | OpMod | OpPow
  | OpBitAnd | OpBitOr | OpBitXor | OpShiftL | OpShiftR
  | OpEq | OpNotEq | OpLt | OpLtE | OpGt | OpGtE
  | OpAnd | OpOr | OpNot | OpInvert | OpIn | OpNotIn | OpIs | OpIsNot
  | OpMatMult
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data Lit
  = LitInt Integer   -- e.g. 42
  | LitFloat Double  -- e.g. 3.14159
  | LitString Text   -- e.g. "hello"
  | LitBytes Text    -- e.g. b"binary"
  | LitBool Bool     -- e.g. True
  | LitNone          -- e.g. None / null / nil
  | LitEllipsis      -- e.g. ... / _
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data CompFor = CompFor
  { compTarget :: Expr   -- e.g. x in [x for x in items]
  , compIter   :: Expr   -- e.g. items
  , compIfs    :: [Expr] -- e.g. [x > 0]
  } deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data FStringPart
  = FStringText Text
  | FStringExpr Expr (Maybe Text) (Maybe Text) -- Expr, Conversion (!r, !s), FormatSpec
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data MatchCase = MatchCase
  { mcPattern :: Expr
  , mcGuard   :: Maybe Expr
  , mcBody    :: [Stmt]
  } deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data SelectCase
  = SelectSend Expr Expr        -- e.g. ch <- val
  | SelectRecv (Maybe Text) Expr -- e.g. val := <-ch / <-ch
  | SelectDefault               -- e.g. default:
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data Expr
  = ExprId Text                                      -- e.g. variable name "total"
  | ExprLit Lit                                      -- e.g. integer literal 100
  | ExprBinary Op Expr Expr                          -- e.g. a + b
  | ExprUnary Op Expr                                -- e.g. -x or not flag
  | ExprCall Expr [Expr] [(Text, Expr)]              -- e.g. f(a, key=val)
  | ExprAttr Expr Text                               -- e.g. obj.property
  | ExprSubscript Expr Expr                          -- e.g. arr[idx]
  | ExprSlice (Maybe Expr) (Maybe Expr) (Maybe Expr) -- e.g. a[start:stop:step]
  | ExprList [Expr]                                  -- e.g. [1, 2, 3]
  | ExprTuple [Expr]                                 -- e.g. (1, 2)
  | ExprDict [(Expr, Expr)]                          -- e.g. {"k": v}
  | ExprSet [Expr]                                   -- e.g. {1, 2, 3}
  | ExprLambda [Parameter] Expr                      -- e.g. lambda x: x * 2 / (x) => x * 2
  | ExprTernary Expr Expr Expr                       -- e.g. cond ? trueVal : falseVal
  | ExprListComp Expr [CompFor]                      -- e.g. [x * 2 for x in xs if x > 0]
  | ExprDictComp Expr Expr [CompFor]                 -- e.g. {k: v for k, v in pairs}
  | ExprSetComp Expr [CompFor]                       -- e.g. {x for x in xs}
  | ExprGenerator Expr [CompFor]                     -- e.g. (x for x in xs)
  | ExprWalrus Text Expr                             -- e.g. PEP 572 (x := calc())
  | ExprAwait Expr                                   -- e.g. await coro()
  | ExprYield (Maybe Expr)                           -- e.g. yield item
  | ExprYieldFrom Expr                               -- e.g. yield from generator
  | ExprFormattedString [FStringPart]                -- e.g. f"value: {x}" / `value: ${x}`
  | ExprStarred Expr                                 -- e.g. *args / ...arr
  | ExprKwStarred Expr                               -- e.g. **kwargs
  | ExprOptChain Expr Text                           -- e.g. obj?.field
  | ExprNullish Expr Expr                            -- e.g. a ?? b
  | ExprChanRecv Expr                                -- e.g. <-ch (Go)
  | ExprTryOp Expr                                   -- e.g. expr? (Rust)
  | ExprMacroCall Text [Expr]                        -- e.g. println!(...) / vec![...]
  | ExprJSX Text [(Text, Expr)] [Expr]               -- e.g. <Component attr={v}>children</Component>
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)

data Stmt
  = StmtAssign [Expr] Expr                                      -- e.g. x = y = 10
  | StmtAnnAssign Expr Expr (Maybe Expr)                        -- e.g. x: int = 10 / let x: i32 = 10
  | StmtAugAssign Expr Op Expr                                  -- e.g. x += 1
  | StmtExpr Expr                                               -- e.g. print("hi")
  | StmtReturn (Maybe Expr)                                     -- e.g. return result
  | StmtIf Expr [Stmt] [Stmt]                                   -- e.g. if cond: ... else: ...
  | StmtWhile Expr [Stmt] [Stmt]                                -- e.g. while cond: ... else: ...
  | StmtFor Expr Expr [Stmt] [Stmt]                             -- e.g. for item in iter: ... else: ...
  | StmtAsyncFor Expr Expr [Stmt] [Stmt]                        -- e.g. async for item in aiter: ...
  | StmtTry [Stmt] [(Maybe Expr, Maybe Text, [Stmt])] [Stmt] [Stmt] -- e.g. try / except / else / finally
  | StmtWith [(Expr, Maybe Expr)] [Stmt]                        -- e.g. with open(f) as h: ...
  | StmtAsyncWith [(Expr, Maybe Expr)] [Stmt]                   -- e.g. async with lock: ...
  | StmtAssert Expr (Maybe Expr)                                -- e.g. assert x > 0, "must be positive"
  | StmtRaise (Maybe Expr) (Maybe Expr)                         -- e.g. raise ValueError() / panic!(...)
  | StmtBreak                                                   -- e.g. break
  | StmtContinue                                                -- e.g. continue
  | StmtPass                                                    -- e.g. pass
  | StmtDelete [Expr]                                           -- e.g. del obj.field
  | StmtGlobal [Text]                                           -- e.g. global state
  | StmtNonlocal [Text]                                         -- e.g. nonlocal counter
  | StmtMatch Expr [MatchCase]                                  -- e.g. match / switch pattern
  | StmtGo Expr                                                 -- e.g. go worker() (Go)
  | StmtDefer Expr                                              -- e.g. defer file.Close() (Go)
  | StmtChanSend Expr Expr                                      -- e.g. ch <- val (Go)
  | StmtSelect [(SelectCase, [Stmt])]                           -- e.g. select { case ... } (Go)
  | StmtLoop [Stmt]                                             -- e.g. loop { ... } (Rust)
  | StmtSwitch Expr [(Expr, [Stmt])] [Stmt]                     -- e.g. switch(x) { case 1: ... default: ... }
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (ToJSON, FromJSON, NFData)