The Abstract Syntax Tree (AST) is a crucial intermediate representation in the Frost compiler. It captures the structure and semantics of the source code, serving as the foundation for subsequent compilation stages. This document outlines the process of building the AST in Frost.
Parser Structure
The AST construction begins in the Ast.Parser module, which orchestrates the parsing process:
parse :: String -> String -> IO (Either String AT.Program)
parse sourceFile input = do
(result, _) <- S.runStateT (M.runParserT (PP.parseProgram sourceFile) sourceFile input) PS.parserState
case result of
(Left err) -> return $ Left (M.errorBundlePretty err)
(Right program) -> return $ Right program
This function takes the source file name and input string, runs the parser, and returns either an error message or the parsed AST.
AST Node Types
The AST is composed of various node types defined in Ast.Types. Key components include:
Source Location: For error reporting and debugging.
data SrcLoc = SrcLoc
{ srcFile :: String,
srcLine :: Int,
srcCol :: Int
}
Tokenization: The input string is broken down into tokens.
Recursive Descent: The parser uses recursive descent to build the AST bottom-up.
Node Construction: As language constructs are recognized, corresponding AST nodes are created.
Type Annotation: Types are inferred or explicitly annotated during parsing.
Error Handling: Syntax errors are caught and reported with precise source locations.
AST Traversal and Manipulation
After construction, the AST can be traversed and manipulated. The Shared.Utils module provides utility functions for this purpose:
getLoc :: AT.Expr -> AT.SrcLoc
getLoc expr = case expr of
AT.Lit loc _ -> loc
AT.Var loc _ _ -> loc
-- ... (other cases)
This function extracts the source location from an AST node, which is crucial for error reporting and code generation.
Building the AST is a critical step in the Frost compilation process. It transforms the flat text of the source code into a structured representation that captures the semantics of the program. This representation serves as the foundation for subsequent stages such as type checking, optimization, and code generation.