packages feed

phino-0.0.145: src/Dataize.hs

{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}

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

module Dataize (dataize, dataize', reduction, Outcome (..)) where

import AST
import Control.Exception (throwIO, try)
import Control.Monad (unless)
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Maybe (listToMaybe)
import qualified Data.Text as T
import Deps (Evaluation (..), Judgment (..), State (..))
import Engine (Engine (..))
import qualified Inference as In
import Locator (locatedExpression)
import Morph (Morphed, ReduceContext (..), ReduceException (..), ReductionFunc, boxed, deeper, entering, inferred, insideUniverse, leadsTo, onward, parking, universed)
import Rewriter (Rewritten)

type Dataized = (Bytes, [Rewritten])

type Dataizable = Morphed

data Outcome
  = Dataized Bytes
  | Residual Expression
  deriving stock (Eq, Show)

dataize :: Expression -> State -> ReduceContext -> IO (Outcome, [Rewritten], State)
dataize universe state ctx@ReduceContext{..} = do
  expr <- locatedExpression _locator universe
  result <- try (dataize' (expr, (universe, Nothing) :| []) universe state ctx)
  case result of
    Right ((bytes, seq), state') -> pure (Dataized bytes, reverse seq, state')
    Left (StuckAt func seq parked) | _partial -> pure (Residual (fst (NE.head seq)), reverse (NE.toList seq), parked{_stuck = Just func})
    Left (OutOfStepsAt _ seq parked) | _partial -> pure (Residual (fst (NE.head seq)), reverse (NE.toList seq), parked)
    Left (LoopingAt _ seq parked) | _partial -> pure (Residual (fst (NE.head seq)), reverse (NE.toList seq), parked)
    Left failure -> throwIO (failure :: ReduceException)

dataize' :: Dataizable -> Expression -> State -> ReduceContext -> IO (Dataized, State)
dataize' (expr, seq) univ state caller = do
  guarded <- deeper =<< entering expr =<< universed univ caller{_judgment = Dataization}
  ctx <- inside guarded expr
  parking seq state $ case unknown expr of
    Just idx -> manufactured idx ctx
    Nothing -> do
      reached <- inferred expr univ state ctx ctx._engine._dataization
      case reached of
        Just (In.Answered step bts, state') -> do
          seq' <- leadsTo seq step (ExBytes bts) ctx
          pure ((bts, NE.toList seq'), state'{_manufactured = Nothing})
        Just (In.Onward way built world, state') -> do
          (dataizable, state'') <- onward seq state' way built ctx
          dataize' dataizable world state'' ctx
        Nothing -> throwIO (Undataizable expr state)
  where
    inside :: ReduceContext -> Expression -> IO ReduceContext
    inside ctx (ExFormation bds)
      | boxed bds = do
          ctx._saveEval (EvFormation ctx._nesting expr ctx._site)
          pure ctx{_nesting = ctx._nesting + 1}
    inside ctx _ = pure ctx
    unknown :: Expression -> Maybe Int
    unknown (ExFormation bds) = listToMaybe [idx | BiLambda (FnSymbol idx) <- bds]
    unknown _ = Nothing
    manufactured :: Int -> ReduceContext -> IO (Dataized, State)
    manufactured idx ctx = do
      seq' <- leadsTo seq (Dataization, "symbol") (ExBytes datum) ctx
      pure ((datum, NE.toList seq'), state{_manufactured = Just idx})

reduction :: ReductionFunc
reduction univ ctx expr state = do
  (universe, aiming) <- insideUniverse expr univ ctx
  result <- try (dataize universe state aiming)
  case result of
    Right (outcome, _, state') -> pure (reached outcome, state')
    Left (Undataizable term state') | ctx._partial -> do
      unless (dead `elem` ctx._parked) (ctx._saveEval (EvStuck ctx._nesting dead Dataization term))
      pure (Nothing, state'{_stuck = Just dead})
    Left failure -> throwIO failure
  where
    dead :: T.Text
    dead = "⊥"
    reached :: Outcome -> Maybe Bytes
    reached (Dataized bytes) = Just bytes
    reached (Residual _) = Nothing

datum :: Bytes
datum = BtMany ["40", "45", "00", "00", "00", "00", "00", "00"]