packages feed

phino-0.0.0.53: src/Sugar.hs

{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}

-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT

module Sugar (toSalty, withSugarType, SugarType (..)) where

import AST
import CST
import Misc

withSugarType :: (ToSalty a) => SugarType -> a -> a
withSugarType SWEET prog = prog
withSugarType SALTY prog = toSalty prog

voidRho :: PAIR
voidRho = PA_VOID (AT_RHO RHO) ARROW EMPTY

bdWithVoidRho :: BINDING -> BINDING
bdWithVoidRho BI_EMPTY{..} = BI_PAIR voidRho (BDS_EMPTY tab) tab
bdWithVoidRho bd@BI_PAIR{pair = PA_VOID{attr = AT_RHO _}} = bd
bdWithVoidRho bd@BI_PAIR{pair = PA_TAU{attr = AT_RHO _}} = bd
bdWithVoidRho BI_PAIR{..} = BI_PAIR pair (bdsWithVoidRho bindings) tab
  where
    bdsWithVoidRho :: BINDINGS -> BINDINGS
    bdsWithVoidRho BDS_EMPTY{..} = BDS_PAIR EOL tab voidRho (BDS_EMPTY tab)
    bdsWithVoidRho bds@BDS_PAIR{pair = PA_VOID{attr = AT_RHO _}} = bds
    bdsWithVoidRho bds@BDS_PAIR{pair = PA_TAU{attr = AT_RHO _}} = bds
    bdsWithVoidRho BDS_PAIR{..} = BDS_PAIR eol tab pair (bdsWithVoidRho bindings)

data SugarType = SWEET | SALTY
  deriving (Eq, Show)

-- By default CST is generated with all possible syntax sugar
-- The main purpose of this class is to get rid of syntax sugar
--  |----------------------------|-------------------------------------------------------|
--  | sugar                      | verbose version                                       |
--  |----------------------------|-------------------------------------------------------|
--  | {e}                        | Q -> e                                                |
--  | QQ                         | Q.org.eolang                                          |
--  | a1 -> a2                   | a1 ↦ $.a2                                             |
--  | a -> 42                    | QQ.number(QQ.bytes([[ D> 40-45-00-00-00-00-00-00 ]])) |
--  | a -> "Hey"                 | QQ.number(QQ.bytes([[ D> 48-65-79 ]]))                |
--  | [[ B ]]                    | [[ B, ^ -> ? ]], if rho is absent in 'B'              |
--  | a1(a2, a3, ...) -> [[ B ]] | a1 -> [[ a2 -> ?, a3 -> ?, ..., B ]]                  |
--  | e(e0, e1, ...)             | e(~0 -> e0, ~1 -> e1, ...)                            |
--  | e(a1 -> e1, a2 -> e2, ...) | e(a1 -> e1)(a2 -> e2)...                              |
--  |----------------------------|-------------------------------------------------------|
class ToSalty a where
  toSalty :: a -> a

instance ToSalty PROGRAM where
  toSalty PR_SWEET{..} = PR_SALTY Φ ARROW (toSalty expr)
  toSalty prog = prog

instance ToSalty EXPRESSION where
  toSalty EX_DEF_PACKAGE{..} = EX_DISPATCH (EX_DISPATCH (EX_GLOBAL Φ) (AT_LABEL "org")) (AT_LABEL "eolang")
  toSalty EX_ATTR{..} = EX_DISPATCH (EX_XI XI) attr
  toSalty EX_DISPATCH{..} = EX_DISPATCH (toSalty expr) attr
  toSalty EX_FORMATION{lsb, binding = bd@BI_EMPTY{..}, rsb} = EX_FORMATION lsb NO_EOL TAB' (toSalty (bdWithVoidRho bd)) NO_EOL TAB' rsb
  toSalty EX_FORMATION{..} = EX_FORMATION lsb eol tab (toSalty (bdWithVoidRho binding)) eol' tab' rsb
  toSalty EX_APPLICATION{..} = EX_APPLICATION (toSalty expr) EOL (TAB indent) (toSalty tau) EOL (TAB (indent - 1)) indent
  toSalty EX_APPLICATION_TAUS{..} =
    foldl
      toApplication
      expr
      (tauToPairs taus)
    where
      toApplication :: EXPRESSION -> PAIR -> EXPRESSION
      toApplication exp pair =
        EX_APPLICATION (toSalty exp) EOL (TAB indent) (APP_BINDING (toSalty pair)) EOL (TAB (indent - 1)) indent
      tauToPairs :: BINDING -> [PAIR]
      tauToPairs BI_PAIR{..} = pair : tausToPairs bindings
      tausToPairs :: BINDINGS -> [PAIR]
      tausToPairs BDS_EMPTY{..} = []
      tausToPairs BDS_PAIR{..} = pair : tausToPairs bindings
  toSalty EX_APPLICATION_EXPRS{..} = toSalty (EX_APPLICATION_TAUS expr EOL (TAB indent) (argToBinding args tab) EOL (TAB (indent - 1)) indent)
    where
      argToBinding :: APP_ARG -> TAB -> BINDING
      argToBinding APP_ARG{..} =
        BI_PAIR
          (PA_TAU (AT_ALPHA ALPHA 0) ARROW expr)
          (argsToBindings args 1 tab)
      argsToBindings :: APP_ARGS -> Int -> TAB -> BINDINGS
      argsToBindings AAS_EMPTY _ tab = BDS_EMPTY tab
      argsToBindings AAS_EXPR{..} idx tb = BDS_PAIR eol tb (PA_TAU (AT_ALPHA ALPHA idx) ARROW expr) (argsToBindings args (idx + 1) tb)
  toSalty EX_NUMBER{num, tab = tab@TAB{..}, rhos} =
    saltifyPrimitive
      (toCST (BaseObject "number") (indent + 1) EOL)
      (toCST (BaseObject "bytes") (indent + 2) EOL)
      (toCST (ExFormation [BiDelta (numToBts (either toDouble id num))]) (indent + 2) EOL)
      tab
      rhos
  toSalty EX_STRING{str, tab = tab@TAB{..}, rhos} =
    saltifyPrimitive
      (toCST (BaseObject "string") (indent + 1) EOL)
      (toCST (BaseObject "bytes") (indent + 2) EOL)
      (toCST (ExFormation [BiDelta (strToBts str)]) (indent + 2) EOL)
      tab
      rhos
  toSalty EX_PHI_MEET{..} = EX_PHI_MEET idx (toSalty expr)
  toSalty EX_PHI_AGAIN{..} = EX_PHI_AGAIN idx (toSalty expr)
  toSalty expr = expr

saltifyPrimitive :: EXPRESSION -> EXPRESSION -> EXPRESSION -> TAB -> [Binding] -> EXPRESSION
saltifyPrimitive base bytes data' tb@TAB{..} rhos =
  let next = TAB (indent + 1)
   in toSalty
        ( EX_APPLICATION_TAUS
            base
            EOL
            next
            ( BI_PAIR
                ( PA_TAU
                    (AT_ALPHA ALPHA 0)
                    ARROW
                    ( EX_APPLICATION_EXPRS
                        bytes
                        EOL
                        (TAB (indent + 2))
                        (APP_ARG data' AAS_EMPTY)
                        EOL
                        next
                        (indent + 2)
                    )
                )
                (toCST rhos (indent + 1) EOL)
                next
            )
            EOL
            tb
            (indent + 1)
        )

instance ToSalty BINDING where
  toSalty BI_PAIR{..} = BI_PAIR (toSalty pair) (toSalty bindings) tab
  toSalty bd = bd

instance ToSalty APP_BINDING where
  toSalty APP_BINDING{..} = APP_BINDING (toSalty pair)

instance ToSalty BINDINGS where
  toSalty BDS_PAIR{..} = BDS_PAIR eol tab (toSalty pair) (toSalty bindings)
  toSalty bds = bds

instance ToSalty PAIR where
  toSalty PA_TAU{..} = PA_TAU attr arrow (toSalty expr)
  toSalty PA_FORMATION{voids, attr, arrow, expr = expr@EX_FORMATION{..}} =
    PA_TAU attr arrow (toSalty (EX_FORMATION lsb eol tab (joinToBinding voids binding) eol' tab' rsb))
    where
      joinToBinding :: [ATTRIBUTE] -> BINDING -> BINDING
      joinToBinding [] bd = bd
      joinToBinding (attr : rest) bd = BI_PAIR (PA_VOID attr arrow EMPTY) (joinToBindings rest bd) tab
      joinToBindings :: [ATTRIBUTE] -> BINDING -> BINDINGS
      joinToBindings [] BI_EMPTY{..} = BDS_EMPTY tab
      joinToBindings [] BI_PAIR{..} = BDS_PAIR eol tab pair bindings
      joinToBindings (attr : rest) bd = BDS_PAIR eol tab (PA_VOID attr arrow EMPTY) (joinToBindings rest bd)
  toSalty pair = pair