packages feed

tala-core-0.1.0: src/Progmasoft/Tala/Core/Symbols.hs

-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com>
-- SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1

{- | Complete SymbolId inventory for Core.

Optimization passes sometimes have to introduce compiler-owned binders.  They
must not guess a starting value from function names alone: parameters, local
bindings, expression-local lets, closure captures, and lifted closure
parameters all inhabit the same resolved identity space.  This module owns the
structural traversal used to find a collision-free fresh-symbol frontier.

The inventory includes definitions and uses.  Including uses is intentional.
A verified module cannot contain a dangling use, but transformation helpers are
also exercised on partially built fixtures.  Starting above every observed id
keeps those transformations deterministic and prevents a secondary diagnostic
from obscuring the original malformed reference.
-}
module Progmasoft.Tala.Core.Symbols
    ( coreModuleSymbols
    , coreFunctionSymbols
    , coreStatementSymbols
    , coreExpressionSymbols
    , maximumCoreSymbolValue
    , nextCoreSymbolValue
    ) where

import Progmasoft.Tala.AST (ResolvedName, resolvedSymbol, symbolIdValue)
import Progmasoft.Tala.Core

-- | Return every resolved name observed in deterministic source order.
coreModuleSymbols :: CoreModule -> [ResolvedName]
coreModuleSymbols = concatMap coreFunctionSymbols . coreModuleFunctions

-- | Include the function definition before its parameter and body identities.
coreFunctionSymbols :: CoreFunction -> [ResolvedName]
coreFunctionSymbols function =
    coreFunctionName function
        : map fst (coreFunctionParameters function)
        ++ concatMap coreStatementSymbols (coreFunctionBody function)

-- | Traverse a statement, including both targets and expression references.
coreStatementSymbols :: CoreStatement -> [ResolvedName]
coreStatementSymbols statement = case statement of
    CoreBind binding ->
        coreBindingName binding : coreExpressionSymbols (coreBindingValue binding)
    CoreAssign name value -> name : coreExpressionSymbols value
    CoreReturn value -> coreExpressionSymbols value
    CoreEvaluate value -> coreExpressionSymbols value
    CoreIf condition whenTrue whenFalse ->
        coreExpressionSymbols condition
            ++ concatMap coreStatementSymbols whenTrue
            ++ concatMap coreStatementSymbols whenFalse
    CoreWhile condition body -> coreExpressionSymbols condition ++ concatMap coreStatementSymbols body
    CoreDoWhile body condition -> concatMap coreStatementSymbols body ++ coreExpressionSymbols condition
    CoreFor condition body update ->
        coreExpressionSymbols condition
            ++ concatMap coreStatementSymbols body
            ++ concatMap coreStatementSymbols update
    CoreBreak -> []
    CoreContinue -> []

-- | Traverse all expression-owned scopes, including closure bodies.
coreExpressionSymbols :: CoreExpression -> [ResolvedName]
coreExpressionSymbols expression = case expression of
    CoreVariable name _ -> [name]
    CoreLiteral {} -> []
    CoreApply callee arguments _ ->
        coreExpressionSymbols callee ++ concatMap coreExpressionSymbols arguments
    CorePrimitive _ arguments _ -> concatMap coreExpressionSymbols arguments
    CoreLet name _ value body _ ->
        name : coreExpressionSymbols value ++ coreExpressionSymbols body
    CoreConditional condition whenTrue whenFalse _ ->
        coreExpressionSymbols condition ++ coreExpressionSymbols whenTrue ++ coreExpressionSymbols whenFalse
    CoreClosure captures parameters _ body _ ->
        map coreCaptureName captures
            ++ map fst parameters
            ++ concatMap (coreExpressionSymbols . coreCaptureValue) captures
            ++ concatMap coreStatementSymbols body

-- | Largest numeric identity observed in the complete Core tree.
maximumCoreSymbolValue :: CoreModule -> Int
maximumCoreSymbolValue moduleValue =
    maximum
        ( 0
            : map
                (symbolIdValue . resolvedSymbol)
                (coreModuleSymbols moduleValue)
        )

-- | First positive identity that is guaranteed not to collide with the module.
nextCoreSymbolValue :: CoreModule -> Int
nextCoreSymbolValue moduleValue = maximumCoreSymbolValue moduleValue + 1