packages feed

phino-0.0.0.46: src/CST.hs

{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}

-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT
-- This module represents concrete syntax tree for phi-calculus program
module CST where

import AST
import Data.List (intercalate)
import Misc

data LSB = LSB | LSB'
  deriving (Eq, Show)

data RSB = RSB | RSB'
  deriving (Eq, Show)

data COMMA = COMMA | NO_COMMA
  deriving (Eq, Show)

data ARROW = ARROW | ARROW'
  deriving (Eq, Show)

data DASHED_ARROW = DASHED_ARROW
  deriving (Eq, Show)

data VOID = EMPTY | QUESTION
  deriving (Eq, Show)

data PHI = PHI | AT
  deriving (Eq, Show)

data RHO = RHO | CARET
  deriving (Eq, Show)

data DELTA = DELTA
  deriving (Eq, Show)

data XI = XI | DOLLAR
  deriving (Eq, Show)

data LAMBDA = LAMBDA
  deriving (Eq, Show)

data GLOBAL = Φ | Q
  deriving (Eq, Show)

data DEF_PACKAGE = Φ̇ | QQ
  deriving (Eq, Show)

data TERMINATION = DEAD | T
  deriving (Eq, Show)

data SPACE = SPACE
  deriving (Eq, Show)

data EOL = EOL | NO_EOL
  deriving (Eq, Show)

data BYTES = BT_EMPTY | BT_ONE String | BT_MANY [String]
  deriving (Eq, Show)

data TAB
  = TAB {indent :: Integer}
  | TAB'
  | NO_TAB
  deriving (Eq, Show)

data ALPHA = ALPHA | ALPHA'
  deriving (Eq, Show)

data PROGRAM
  = PR_SWEET {expr :: EXPRESSION}
  | PR_SALTY {global :: GLOBAL, arrow :: ARROW, expr :: EXPRESSION}
  deriving (Eq, Show)

data PAIR
  = PA_TAU {attr :: ATTRIBUTE, arrow :: ARROW, expr :: EXPRESSION}
  | PA_VOID {attr :: ATTRIBUTE, arrow :: ARROW, void :: VOID}
  | PA_LAMBDA {func :: String}
  | PA_LAMBDA' {func :: String} -- ASCII version of PA_LAMBDA
  | PA_DELTA {bytes :: BYTES}
  | PA_DELTA' {bytes :: BYTES} -- ASCII version of PA_DELTA
  deriving (Eq, Show)

data BINDING
  = BI_PAIR {pair :: PAIR, bindings :: BINDINGS, tab :: TAB}
  | BI_EMPTY {tab :: TAB}
  deriving (Eq, Show)

data BINDINGS
  = BDS_PAIR {eol :: EOL, tab :: TAB, pair :: PAIR, bindings :: BINDINGS}
  | BDS_EMPTY {tab :: TAB}
  deriving (Eq, Show)

-- Arguments for application with default α attributes
-- which are not necessary to be printed
data APP_ARG = APP_ARG {expr :: EXPRESSION, args :: APP_ARGS}
  deriving (Eq, Show)

data APP_ARGS
  = AAS_EXPR {eol :: EOL, tab :: TAB, expr :: EXPRESSION, args :: APP_ARGS}
  | AAS_EMPTY
  deriving (Eq, Show)

data EXPRESSION
  = EX_GLOBAL {global :: GLOBAL}
  | EX_DEF_PACKAGE {pckg :: DEF_PACKAGE}
  | EX_XI {xi :: XI}
  | EX_ATTR {attr :: ATTRIBUTE} -- sugar for $.x -> just x
  | EX_TERMINATION {termination :: TERMINATION}
  | EX_FORMATION {lsb :: LSB, eol :: EOL, tab :: TAB, binding :: BINDING, eol' :: EOL, tab' :: TAB, rsb :: RSB}
  | EX_DISPATCH {expr :: EXPRESSION, attr :: ATTRIBUTE}
  | EX_APPLICATION {expr :: EXPRESSION, eol :: EOL, tab :: TAB, bindings :: BINDING, eol' :: EOL, tab' :: TAB}
  | EX_APPLICATION' {expr :: EXPRESSION, eol :: EOL, tab :: TAB, args :: APP_ARG, eol' :: EOL, tab' :: TAB}
  | EX_STRING {str :: String, tab :: TAB}
  | EX_NUMBER {num :: Either Integer Double, tab :: TAB}
  deriving (Eq, Show)

data ATTRIBUTE
  = AT_LABEL {label :: String}
  | AT_ALPHA {alpha :: ALPHA, idx :: Integer}
  | AT_RHO {rho :: RHO}
  | AT_PHI {phi :: PHI}
  | AT_LAMBDA {lambda :: LAMBDA}
  | AT_DELTA {delta :: DELTA}
  deriving (Eq, Show)

programToCST :: Program -> PROGRAM
programToCST prog = toCST prog 0

expressionToCST :: Expression -> EXPRESSION
expressionToCST expr = toCST expr 0

-- This class is used to convert AST to CST
-- CST is created with sugar and unicode
-- All further transformations much consider that
class ToCST a b where
  toCST :: a -> Integer -> b

instance ToCST Program PROGRAM where
  toCST (Program expr) tabs = PR_SWEET (toCST expr tabs)

instance ToCST Expression EXPRESSION where
  toCST ExGlobal _ = EX_GLOBAL Φ
  toCST ExThis _ = EX_XI XI
  toCST ExTermination _ = EX_TERMINATION DEAD
  toCST (ExFormation [BiVoid AtRho]) _ = toCST (ExFormation []) 0
  toCST (ExFormation []) _ = EX_FORMATION LSB NO_EOL NO_TAB (BI_EMPTY NO_TAB) NO_EOL NO_TAB RSB
  toCST (ExFormation bds) tabs =
    let next = tabs + 1
        bds' = toCST (withoutLastVoidRho bds) next :: BINDING
     in EX_FORMATION
          LSB
          EOL
          (TAB next)
          bds'
          EOL
          (TAB tabs)
          RSB
    where
      withoutLastVoidRho :: [Binding] -> [Binding]
      withoutLastVoidRho [] = []
      withoutLastVoidRho [BiVoid AtRho] = []
      withoutLastVoidRho (bd : [BiVoid AtRho]) = [bd]
      withoutLastVoidRho (bd : bds') = bd : withoutLastVoidRho bds'
  toCST (DataString bts) tabs = EX_STRING (btsToStr bts) (TAB tabs)
  toCST (DataNumber bts) tabs = EX_NUMBER (btsToNum bts) (TAB tabs)
  toCST (ExDispatch (ExDispatch ExGlobal (AtLabel "org")) (AtLabel "eolang")) _ = EX_DEF_PACKAGE Φ̇
  toCST (ExDispatch ExThis attr) tabs = EX_ATTR (toCST attr tabs)
  toCST (ExDispatch expr attr) tabs = EX_DISPATCH (toCST expr tabs) (toCST attr tabs)
  toCST app@(ExApplication (ExApplication expr tau) tau') tabs =
    let (expr', taus, exprs) = complexApplication app
        next = tabs + 1
        expr'' = toCST expr' tabs :: EXPRESSION
     in if null exprs
          then
            EX_APPLICATION
              (toCST expr' tabs)
              EOL
              (TAB next)
              (toCST (reverse taus) next)
              EOL
              (TAB tabs)
          else
            EX_APPLICATION'
              (toCST expr' tabs)
              EOL
              (TAB next)
              (toCST (reverse exprs) next)
              EOL
              (TAB tabs)
    where
      -- Here we unroll nested application sequence into flat structure
      -- The returned tuple consists of:
      -- 1. deepest start expression
      -- 2. list of tau bindings which are applied to start expression
      -- 3. list of expressions which are applied to start expression with default
      --    alpha attributes (~0 -> e1, ~1 -> e2, ...)
      complexApplication :: Expression -> (Expression, [Binding], [Expression])
      complexApplication (ExApplication (ExApplication expr tau) tau') =
        let (before, taus, exprs) = complexApplication (ExApplication expr tau)
            taus' = tau' : taus
         in if null exprs
              then (before, taus', [])
              else case tau' of
                BiTau (AtAlpha idx) expr' ->
                  if idx == fromIntegral (length exprs)
                    then (before, taus', expr' : exprs)
                    else (before, taus', [])
                _ -> (before, taus', [])
      complexApplication (ExApplication expr (BiTau (AtAlpha 0) expr')) = (expr, [BiTau (AtAlpha 0) expr'], [expr'])
      complexApplication (ExApplication expr tau) = (expr, [tau], [])
  toCST (ExApplication expr tau) tabs =
    let next = tabs + 1
     in EX_APPLICATION (toCST expr tabs) EOL (TAB next) (toCST [tau] next) EOL (TAB tabs)

instance ToCST [Expression] APP_ARG where
  toCST (expr : exprs) tabs = APP_ARG (toCST expr tabs) (toCST exprs tabs)

instance ToCST [Expression] APP_ARGS where
  toCST [] _ = AAS_EMPTY
  toCST (expr : exprs) tabs = AAS_EXPR EOL (TAB tabs) (toCST expr tabs) (toCST exprs tabs)

instance ToCST [Binding] BINDING where
  toCST [] tabs = BI_EMPTY (TAB tabs)
  toCST (bd : bds) tabs = BI_PAIR (toCST bd tabs) (toCST bds tabs) (TAB tabs)

instance ToCST [Binding] BINDINGS where
  toCST [] tabs = BDS_EMPTY (TAB tabs)
  toCST (bd : bds) tabs = BDS_PAIR EOL (TAB tabs) (toCST bd tabs) (toCST bds tabs)

instance ToCST Binding PAIR where
  toCST (BiTau attr exp) tabs = PA_TAU (toCST attr tabs) ARROW (toCST exp tabs)
  toCST (BiVoid attr) tabs = PA_VOID (toCST attr tabs) ARROW EMPTY
  toCST (BiDelta bts) tabs = PA_DELTA (toCST bts tabs)
  toCST (BiLambda func) _ = PA_LAMBDA func

instance ToCST Bytes BYTES where
  toCST BtEmpty _ = BT_EMPTY
  toCST (BtOne byte) _ = BT_ONE byte
  toCST (BtMany bts) _ = BT_MANY bts

instance ToCST Attribute ATTRIBUTE where
  toCST (AtLabel label) _ = AT_LABEL label
  toCST (AtAlpha idx) _ = AT_ALPHA ALPHA idx
  toCST AtPhi _ = AT_PHI PHI
  toCST AtRho _ = AT_RHO RHO
  toCST AtDelta _ = AT_DELTA DELTA
  toCST AtLambda _ = AT_LAMBDA LAMBDA

class HasEOL a where
  hasEOL :: a -> Bool

instance HasEOL EXPRESSION where
  hasEOL EX_FORMATION {eol = NO_EOL, binding, eol' = NO_EOL} = hasEOL binding
  hasEOL EX_FORMATION {..} = True
  hasEOL EX_DISPATCH {..} = hasEOL expr
  hasEOL EX_APPLICATION {eol = NO_EOL, expr, bindings, eol' = NO_EOL} = hasEOL expr || hasEOL bindings
  hasEOL EX_APPLICATION {..} = True
  hasEOL EX_APPLICATION' {eol = NO_EOL, expr, args, eol' = NO_EOL} = hasEOL expr || hasEOL args
  hasEOL EX_APPLICATION' {..} = True
  hasEOL _ = False

instance HasEOL BINDING where
  hasEOL BI_EMPTY {..} = False
  hasEOL BI_PAIR {..} = hasEOL pair || hasEOL bindings

instance HasEOL BINDINGS where
  hasEOL BDS_PAIR {eol = NO_EOL, pair, bindings} = hasEOL pair || hasEOL bindings
  hasEOL BDS_PAIR {..} = True
  hasEOL BDS_EMPTY {..} = False

instance HasEOL PAIR where
  hasEOL PA_TAU {..} = hasEOL expr
  hasEOL _ = False

instance HasEOL APP_ARG where
  hasEOL APP_ARG {..} = hasEOL expr || hasEOL args

instance HasEOL APP_ARGS where
  hasEOL AAS_EMPTY = False
  hasEOL AAS_EXPR {eol = NO_EOL, expr, args} = hasEOL expr || hasEOL args
  hasEOL AAS_EXPR {..} = True