lfe_codegen.erl - Code Generator
Purpose: Generate Erlang Abstract Format from validated LFE forms. Coordinates lambda lifting and translation to Core Erlang.
Location: src/lfe_codegen.erl
Size: 499 LOC, 18KB
Module Classification: Compiler backend, orchestration
Public API
forms(Forms, CompilerInfo) ->
{ok, ErlangAST, State}
| {error, Errors, Warnings, State}
Generate Erlang AST from LFE forms. Located at lfe_codegen.erl:82-89.
Code Generation Pipeline
Process (comp_forms/2 at lines 155-235):
-
Collect Module Definitions (
collect_mod_defs/2):- Extract module name, exports, imports
- Collect attributes, records, types, specs
- Store function definitions
-
Build Struct Definition (
build_struct_def/1):- If struct defined, generate
__struct__/0and__struct__/1 - Auto-export struct functions
- If struct defined, generate
-
Build Info Function (
build_info_func/1):- Generate
__info__/1function - Returns: module, functions, macros, attributes, etc.
- Auto-export
__info__/1
- Generate
-
Compile Attributes (
compile_attributes/1):- Module name, exports, imports
- Custom attributes
- Type definitions, specs
- Records
-
Compile Functions (
compile_functions/1):- Lambda lift each function (
lfe_codelift) - Translate to Erlang AST (
lfe_translate) - Build function clauses
- Lambda lift each function (
State Record
-record(lfe_cg, {
module=[], % Module name
mline=0, % Module line
exports=ordsets, % Exported functions
imports=orddict, % Imported functions
aliases=orddict, % Module aliases
onload=[], % On-load function
records=[], % Records
struct=undefined, % Struct definition
attrs=[], % Attributes
metas=[], % Type/spec metadata
funcs=orddict, % Function definitions
opts=[], % Compiler options
file=[], % Source file
func=[], % Current function
errors=[],
warnings=[]
}).
Generated Functions
Struct Functions (build_struct_def/1 at lines 394-434):
If module defines a struct, two functions are generated:
__struct__() ->
#{__struct__ => ModuleName, field1 => undefined, ...}.
__struct__(Fields) ->
maps:merge(__struct__(), maps:from_list(Fields)).
Info Function (build_info_func/1 at lines 436-492):
__info__(module) -> ModuleName;
__info__(functions) -> [{func,arity}, ...];
__info__(macros) -> []; % Always empty (macros are compile-time)
__info__(attributes) -> [{attr, value}, ...];
...
Erlang AST Format
The generated AST uses Erlang's abstract format:
Module Attribute:
{attribute, Line, module, ModuleName}
Export Attribute:
{attribute, Line, export, [{FuncName, Arity}, ...]}
Function Definition:
{function, Line, Name, Arity, Clauses}
Clause:
{clause, Line, Patterns, Guards, Body}
Dependencies
LFE modules:
lfe_codelift- Lambda liftinglfe_translate- Core Erlang translationlfe_internal- Validationlfe_lib- Utilities
Erlang compiler:
compile:forms/2- Final compilation
Used By
lfe_comp- Compilation pipeline
Key Algorithms
Lambda Lifting (via lfe_codelift):
Nested lambdas are hoisted to module level:
(defun outer (x)
(lambda (y) (+ x y)))
; After lifting:
; outer/1: calls lifted lambda
; -lfe-outer-lambda-1/2: the lifted function taking x and y
Import Translation (build_imports/1 at lines 321-356):
LFE import forms are transformed to Erlang imports:
(import (from lists map filter))
→ -import(lists, [map/2, filter/2]).
(import (rename lists (reverse rev)))
→ Stored in context, calls to rev/1 translate to lists:reverse/1
Record Translation (compile_records/1 at lines 289-319):
(define-record person name age)
→ -record(person, {name, age}).
Special Considerations
Auto-Exports:
These functions are automatically exported:
__info__/1(always)__struct__/0,__struct__/1(if struct defined)
Compile-Time vs Runtime:
- Macros are not included in
__info__/1(they're compile-time only) - Functions include metadata from specs
OTP Compatibility:
Generated code is standard Erlang AST, fully compatible with OTP tools.