pub struct CodeBuilder<'a> {
pub state: &'a mut CodeGenState,
pub builder: &'a mut InstructionBuilder<'a>,
pub variable_registers: SeqMap<usize, TypedRegister>,
pub temp_registers: HwmTempRegisterPool,
pub frame_allocator: StackFrameAllocator,
pub debug_line_tracker: KeepTrackOfSourceLine,
pub source_map_lookup: &'a SourceMapWrapper<'a>,
pub options: CodeBuilderOptions,
pub errors: Vec<Error>,
}
Fields§
§state: &'a mut CodeGenState
§builder: &'a mut InstructionBuilder<'a>
§variable_registers: SeqMap<usize, TypedRegister>
§temp_registers: HwmTempRegisterPool
§frame_allocator: StackFrameAllocator
§debug_line_tracker: KeepTrackOfSourceLine
§source_map_lookup: &'a SourceMapWrapper<'a>
§options: CodeBuilderOptions
§errors: Vec<Error>
Implementations§
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_block_copy_with_size_from_location( &mut self, destination_location: &MemoryLocation, source_location: &MemoryLocation, node: &Node, comment: &str, )
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn spill_required_registers( &mut self, node: &Node, comment: &str, ) -> ArgumentAndTempScope
pub fn emit_restore_region( &mut self, region: SpilledRegisterRegion, output_destination_registers: &HashSet<u8>, node: &Node, comment: &str, )
Source§impl<'a> CodeBuilder<'a>
impl<'a> CodeBuilder<'a>
pub fn new( state: &'a mut CodeGenState, builder: &'a mut InstructionBuilder<'a>, variable_registers: SeqMap<usize, TypedRegister>, temp_registers: HwmTempRegisterPool, temp_allocator: StackFrameAllocator, options: CodeBuilderOptions, source_map_lookup: &'a SourceMapWrapper<'a>, ) -> Self
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn total_aligned_frame_size(&self) -> FrameMemorySize
pub fn patch_enter(&mut self, patch_position: PatchPosition)
pub fn allocate_frame_space_and_return_absolute_pointer_reg( &mut self, ty: &BasicTypeRef, clear_it: bool, node: &Node, comment: &str, ) -> TypedRegister
pub fn allocate_frame_space_and_return_pointer_location( &mut self, ty: &BasicTypeRef, clear_it: bool, node: &Node, comment: &str, ) -> PointerLocation
pub fn allocate_frame_space_and_return_memory_location( &mut self, ty: &BasicTypeRef, clear_it: bool, node: &Node, comment: &str, ) -> MemoryLocation
pub fn allocate_frame_space_and_return_destination_to_it( &mut self, ty: &BasicTypeRef, clear_it: bool, node: &Node, comment: &str, ) -> Place
pub fn debug_expression(&mut self, expr: &Expression, description: &str)
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_enum_variant_to_memory_location( &mut self, target_memory_location: &AggregateMemoryLocation, enum_type: &TypeRef, variant_type: &EnumVariantType, sorted_expressions: &EnumLiteralExpressions, node: &Node, ctx: &Context, )
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_equality_to_bool_target( &mut self, dest_bool_reg: &TypedRegister, left_source: &TypedRegister, is_equal: bool, right_source: &TypedRegister, node: &Node, ctx: &Context, ) -> FlagState
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
Sourcepub fn emit_expression(
&mut self,
output: &Place,
expr: &Expression,
ctx: &Context,
)
pub fn emit_expression( &mut self, output: &Place, expr: &Expression, ctx: &Context, )
The expression materializer! Transforms high-level expressions into their code representation, making sure each value finds its proper home in either a register or memory location.
§Optimization Magic
Uses Destination-Passing Style (DPS) to optimize code generation. Instead of creating temporary values and copying them around, we tell each expression exactly where its result should end up. This means we can often construct values directly in their final location, avoiding unnecessary copies and temporary allocations.
§Arguments
output
- Where should our expression’s result live? (register or memory location)expr
- The expression we’re bringing to lifectx
- The context with all our compilation knowledge
If something needs temporary storage, we’ll handle that too.
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
Sourcepub fn emit_initialize_memory_for_any_type(
&mut self,
memory_location: &MemoryLocation,
node: &Node,
comment: &str,
)
pub fn emit_initialize_memory_for_any_type( &mut self, memory_location: &MemoryLocation, node: &Node, comment: &str, )
Initialize memory for any type that might contain collections
This is the main public interface for memory initialization. It handles:
- Direct collections: Initializes the collection metadata (capacity, etc.)
- Container types: Recursively initializes any collections they contain
- Scalar types: Does nothing (no initialization needed)
Use this function whenever you need to ensure that memory is properly initialized for any type that might contain collections, either directly or nested.
Sourcepub fn emit_initialize_collection_metadata(
&mut self,
memory_location: &MemoryLocation,
node: &Node,
comment: &str,
)
pub fn emit_initialize_collection_metadata( &mut self, memory_location: &MemoryLocation, node: &Node, comment: &str, )
Initialize memory for a collection type at the specified location
This function is responsible for initializing the metadata for collection types:
- For collections (Vec, Map, etc.), it sets the capacity field based on the type definition
- Does NOT handle nested collections - use
emit_initialize_collections_in_type
for that
This is a specialized function for direct collection initialization only.
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_map_like_init_from_initialization_pair_list( &mut self, output_destination: &Place, elements: &[(Expression, Expression)], node: &Node, ctx: &Context, )
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_single_intrinsic_call( &mut self, target_reg: &Place, node: &Node, intrinsic_fn: &IntrinsicFunction, arguments: &[ArgumentExpression], ctx: &Context, )
pub fn emit_intrinsic_map( &mut self, output_destination: &Place, intrinsic_fn: &IntrinsicFunction, self_ptr_reg: &PointerLocation, arguments: &[Expression], node: &Node, comment: &str, ctx: &Context, )
pub fn emit_intrinsic_sparse( &mut self, output_destination: &Place, intrinsic_fn: &IntrinsicFunction, self_ptr_reg: &PointerLocation, arguments: &[Expression], node: &Node, comment: &str, ctx: &Context, )
pub fn emit_intrinsic_grid( &mut self, target_destination: &Place, intrinsic_fn: &IntrinsicFunction, self_ptr_reg: &PointerLocation, arguments: &[Expression], node: &Node, comment: &str, ctx: &Context, )
pub fn emit_intrinsic_transformer( &mut self, target_destination: &Place, intrinsic_fn: &IntrinsicFunction, self_addr: &PointerLocation, lambda: (Vec<VariableRef>, &Expression), node: &Node, ctx: &Context, )
pub fn emit_single_intrinsic_call_with_self_destination( &mut self, target_destination: &Place, node: &Node, intrinsic_fn: &IntrinsicFunction, self_destination: Option<&Place>, arguments: &[ArgumentExpression], ctx: &Context, comment: &str, )
pub fn emit_single_intrinsic_call_with_self( &mut self, target_destination: &Place, node: &Node, intrinsic_fn: &IntrinsicFunction, self_reg: Option<&TypedRegister>, arguments: &[ArgumentExpression], ctx: &Context, comment: &str, )
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
Sourcepub fn emit_iterate_over_collection_with_lambda(
&mut self,
target_destination: &Place,
node: &Node,
source_collection_type: Collection,
transformer: Transformer,
source_collection_reg: &TypedRegister,
lambda_tuple: (Vec<VariableRef>, &Expression),
ctx: &Context,
)
pub fn emit_iterate_over_collection_with_lambda( &mut self, target_destination: &Place, node: &Node, source_collection_type: Collection, transformer: Transformer, source_collection_reg: &TypedRegister, lambda_tuple: (Vec<VariableRef>, &Expression), ctx: &Context, )
Generates code to iterate over a collection using a transformer (e.g., map, filter, filter_map
)
and a lambda expression. Handles creation of result vectors, iterator setup, lambda invocation,
early exit logic, and result collection.
Steps:
- (Optional) Initialize a target vector for the result, if the transformer produces one.
- Initialize the iterator for the collection.
- Generate code to fetch the next element from the iterator.
- Spill lambda variables to protect them from being clobbered by function calls
- Inline the lambda code for the current element.
- Restore lambda variables from stack after lambda execution
- If the transformer supports early exit (e.g., filter, find), set the P flag based on the lambda result.
- Conditionally skip result insertion if early exit is triggered.
- (Optional) If applicable, insert the (possibly unwrapped) result into the target vector.
- Loop back to fetch the next element.
- Finalize iteration, handling any post-processing (e.g., normalizing boolean results).
§Parameters
node
: The AST node for error reporting and code location.collection_type
: The type of collection being iterated.transformer
: The transformer operation (map, filter, find, fold, etc.).collection_self_region
: Memory region of the collection.lambda_expression
: The lambda expression to apply.ctx
: Code generation context. Contains the result target.
§Returns
Ok(())
on success, or an error if code generation fails.
§Errors
// TODO:
§Panics
- If the lambda expression or its kind is not as expected (internal error).
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_unary_operator_logical( &mut self, dest_bool_reg: &TypedRegister, unary_operator: &UnaryOperator, ctx: &Context, ) -> FlagState
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
Sourcepub fn map_subscript_helper(
&mut self,
map_header_location: &Place,
map_type: &MapType,
key_expression: &Expression,
should_create_if_needed: bool,
ctx: &Context,
) -> Place
pub fn map_subscript_helper( &mut self, map_header_location: &Place, map_type: &MapType, key_expression: &Expression, should_create_if_needed: bool, ctx: &Context, ) -> Place
Emits Swamp VM opcodes to calculate the memory address of an element within a map.
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_binary_operator_relational_i32_to_t_flag_only( &mut self, dest_bool_reg: &TypedRegister, left_source: &TypedRegister, binary_operator: &BinaryOperator, right_source: &TypedRegister, ) -> FlagState
pub fn emit_binary_operator_relational_u8( &mut self, dest_bool_reg: &TypedRegister, left_source: &TypedRegister, binary_operator: &BinaryOperator, right_source: &TypedRegister, ) -> FlagState
pub fn emit_binary_operator_relational_f32_to_t_flag_only( &mut self, dest_bool_reg: &TypedRegister, left_source: &TypedRegister, binary_operator: &BinaryOperator, right_source: &TypedRegister, ) -> FlagState
pub fn emit_binary_operator_relational( &mut self, dest_bool_reg: &TypedRegister, left_source: &TypedRegister, binary_operator: &BinaryOperator, right_source: &TypedRegister, ) -> FlagState
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
Sourcepub fn emit_aggregate_pointer_or_pointer_to_scalar_memory(
&mut self,
aggregate_or_scalar_expr: &Expression,
ctx: &Context,
) -> TypedRegister
pub fn emit_aggregate_pointer_or_pointer_to_scalar_memory( &mut self, aggregate_or_scalar_expr: &Expression, ctx: &Context, ) -> TypedRegister
Make sure we have a pointer to something, no matter if it is a scalar or aggregate
Mostly (only?) used for making sure we have a key value memory region for
Map
to calculate a hash for (and copy this memory for inserting)
Sourcepub fn emit_scalar_rvalue_or_pointer_to_temporary(
&mut self,
expr: &Expression,
ctx: &Context,
allow_temporary: bool,
) -> TypedRegister
pub fn emit_scalar_rvalue_or_pointer_to_temporary( &mut self, expr: &Expression, ctx: &Context, allow_temporary: bool, ) -> TypedRegister
Emits code to evaluate an expression and return a pointer register.
This function handles both regular expressions that can be materialized as scalar rvalues and expressions that need temporary memory storage (like initializer lists).
For expressions that need memory materialization:
- If
allow_temporary
is true: Allocates temporary frame space, initializes it, and returns pointer - If
allow_temporary
is false: Falls back toemit_scalar_rvalue
(may fail for some expressions)
For regular expressions:
- Uses
emit_scalar_rvalue
to get the pointer directly
§Parameters
expr
: The expression to evaluatectx
: Code generation contextallow_temporary
: Whether temporary storage is acceptable (false for mutable iteration)
Sourcepub fn emit_scalar_rvalue(
&mut self,
expr: &Expression,
ctx: &Context,
) -> TypedRegister
pub fn emit_scalar_rvalue( &mut self, expr: &Expression, ctx: &Context, ) -> TypedRegister
Emits code to evaluate an expression into a scalar rvalue.
In compiler terminology:
- “emit” means to generate the machine code
- “scalar” refers to single-value types (numbers, booleans, pointers) as opposed to aggregates
- “rvalue” is a value-producing expression that can appear on the right side of an assignment
This method provides an optimized path for scalar values, avoiding the complexity
of aggregate type handling in the general emit_expression
. It’s particularly
important for efficient code generation of expressions that must produce values
(rvalues) rather than storage locations (lvalues).
Basically, for aggregate types, it shouldn’t to materialize (copy) the aggregate value to a destination, but instead just provide a register pointing to the source location.
§Direct Register Access
The following cases can return a register without materialization:
- Variable access (returns the existing register)
- Constants (the memory location can be materialized into a register)
- Some scalar literals (can be materialized directly into a register)
§Register Allocation
For other expressions that can’t provide a direct register, a temporary register is allocated and the expression is evaluated into it.
§Examples in Compiler Terms
// Binary operations need rvalues for both operands
let left_reg = emit_scalar_rvalue(&binary_op.left); // rvalue needed
let right_reg = emit_scalar_rvalue(&binary_op.right); // rvalue needed
// Assignment needs an lvalue on left, rvalue on right
let target = emit_lvalue(&assign.left); // lvalue needed
let value = emit_scalar_rvalue(&assign.right); // rvalue needed
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn sparse_subscript_helper( &mut self, vec_header_location: &Place, analyzed_element_type: &TypeRef, int_expr: &Expression, ctx: &Context, ) -> Place
pub fn sparse_subscript_helper_helper( &mut self, sparse_header_location: &Place, analyzed_element_type: &TypeRef, int_expr: &Expression, ctx: &Context, ) -> PointerLocation
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_statement(&mut self, expr: &Expression, ctx: &Context)
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn emit_check_that_known_len_is_less_or_equal_to_capacity( &mut self, destination_memory_location: &MemoryLocation, len: usize, node: &Node, comment: &str, ) -> TypedRegister
pub fn emit_copy_value_between_places( &mut self, output_place: &Place, value_source: &Place, node: &Node, comment: &str, )
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
pub fn initialize_variable_the_first_time(&mut self, variable: &VariableRef)
Source§impl CodeBuilder<'_>
impl CodeBuilder<'_>
Sourcepub fn vec_subscript_helper(
&mut self,
vec_header_location: &Place,
analyzed_element_type: &TypeRef,
int_expr: &Expression,
ctx: &Context,
) -> Place
pub fn vec_subscript_helper( &mut self, vec_header_location: &Place, analyzed_element_type: &TypeRef, int_expr: &Expression, ctx: &Context, ) -> Place
Emits Swamp VM opcodes to calculate the memory address of an element within an array.
The function targets a vec-like structured with a u16
length prefix followed by
contiguous element data in memory. It uses the provided int_expression
as the
index for the lookup. Calls the subscript_helper_from_location_to_location
to
emit the bounds checking.
pub fn emit_vec_subscript_range_helper( &mut self, destination_memory_location: &Place, source_memory_location: &Place, range_expr: &Expression, node: &Node, comment: &str, ctx: &Context, )
pub fn grid_subscript_helper_helper( &mut self, grid_header_location: &Place, analyzed_element_type: &TypeRef, x_int_expr: &Expression, y_int_expr: &Expression, ctx: &Context, ) -> PointerLocation
pub fn vec_subscript_helper_helper( &mut self, vec_header_location: &Place, analyzed_element_type: &TypeRef, int_expr: &Expression, ctx: &Context, ) -> PointerLocation
Auto Trait Implementations§
impl<'a> Freeze for CodeBuilder<'a>
impl<'a> RefUnwindSafe for CodeBuilder<'a>
impl<'a> !Send for CodeBuilder<'a>
impl<'a> !Sync for CodeBuilder<'a>
impl<'a> Unpin for CodeBuilder<'a>
impl<'a> !UnwindSafe for CodeBuilder<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self
with the foreground set to
value
.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red()
and
green()
, which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg()
:
use yansi::{Paint, Color};
painted.fg(Color::White);
Set foreground color to white using white()
.
use yansi::Paint;
painted.white();
Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self
with the background set to
value
.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red()
and
on_green()
, which have the same functionality but
are pithier.
§Example
Set background color to red using fg()
:
use yansi::{Paint, Color};
painted.bg(Color::Red);
Set background color to red using on_red()
.
use yansi::Paint;
painted.on_red();
Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute
value
.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold()
and
underline()
, which have the same functionality
but are pithier.
§Example
Make text bold using attr()
:
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);
Make text bold using using bold()
.
use yansi::Paint;
painted.bold();
Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi
Quirk
value
.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask()
and
wrap()
, which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk()
:
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);
Enable wrapping using wrap()
.
use yansi::Paint;
painted.wrap();
Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting()
due to conflicts with Vec::clear()
.
The clear()
method will be removed in a future release.
fn clear(&self) -> Painted<&T>
resetting()
due to conflicts with Vec::clear()
.
The clear()
method will be removed in a future release.Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition
value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted
only when both stdout
and stderr
are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);