tala-frontend-0.1.0: src/Progmasoft/Tala/Frontend.hs
-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com>
-- SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
{- | Reusable, target-independent frontend analysis boundaries.
Compiler-adjacent tools must observe exactly the same tokens, parsed tree, and
semantic names as a build. Keeping these boundaries in the compiler package
prevents an analyzer, formatter, or linter from growing a second language
implementation merely to stop before Core lowering.
-}
module Progmasoft.Tala.Frontend
( CompilerInput (..)
, SyntaxArtifacts (..)
, SemanticArtifacts (..)
, analyzeSyntax
, analyzeSemantics
, analyzeParsedSemantics
) where
import Progmasoft.Tala.AST
import Progmasoft.Tala.Diagnostic
import Progmasoft.Tala.Lexer
import Progmasoft.Tala.NestingLimits
import Progmasoft.Tala.Parser
import Progmasoft.Tala.Resolver.NameResolution
import Progmasoft.Tala.Resolver.Renamer
import Progmasoft.Tala.TypeChecker
-- | Source identity and decoded text supplied to the frontend.
data CompilerInput = CompilerInput
{ compilerSourceFile :: FilePath
-- ^ Path used in diagnostics and source spans.
, compilerSourceText :: String
-- ^ Source characters after caller-owned decoding.
}
deriving (Eq, Ord, Read, Show)
-- | Shared lexer and parser products, before name or type analysis.
data SyntaxArtifacts = SyntaxArtifacts
{ syntaxTokens :: [Token]
-- ^ Tokens, including trivia policy from the lexer.
, syntaxParsedAST :: ParsedAST
-- ^ Parsed source tree with unresolved names.
}
deriving (Eq, Ord, Read, Show)
-- | Intermediate ASTs produced by the ordered semantic frontend passes.
data SemanticArtifacts = SemanticArtifacts
{ semanticParsedAST :: ParsedAST
-- ^ Original parser output.
, semanticRenamedAST :: RenamedAST
-- ^ AST with unique local/declaration IDs.
, semanticResolvedAST :: ResolvedAST
-- ^ AST with references bound to symbols.
, semanticTypedAST :: TypedAST
-- ^ Type-checked AST consumed by later tools.
}
deriving (Eq, Ord, Read, Show)
-- | Lex and parse source without invoking semantic analysis or Core lowering.
analyzeSyntax :: CompilerInput -> Either [Diagnostic] SyntaxArtifacts
analyzeSyntax input = do
tokens <- runLexer defaultLexer (LexerInput (compilerSourceFile input) (compilerSourceText input))
parsed <- runParser defaultParser (ParserInput (compilerSourceFile input) tokens)
pure (SyntaxArtifacts tokens parsed)
-- | Run syntax analysis followed by renaming, resolution, and type checking.
analyzeSemantics :: CompilerInput -> Either [Diagnostic] SemanticArtifacts
analyzeSemantics input = syntaxParsedAST <$> analyzeSyntax input >>= analyzeParsedSemantics
-- | Run semantic passes on an existing parsed AST without lexing or parsing.
analyzeParsedSemantics :: ParsedAST -> Either [Diagnostic] SemanticArtifacts
analyzeParsedSemantics parsed = do
-- Every later pass, and every stage after the frontend, recurses along
-- the nesting of the tree. A tree that nests beyond the limits is
-- rejected here, with the place where it becomes too deep.
case nestingProblems parsed of
[] -> pure ()
problems -> Left problems
renamed <- runRenamer defaultRenamer parsed
resolved <- runNameResolution defaultNameResolution renamed
typed <- runTypeChecker defaultTypeChecker resolved
pure (SemanticArtifacts parsed renamed resolved typed)