Skip to main content

Codegen

Struct Codegen 

Source
pub struct Codegen {
    pub ast: Option<Contract>,
    pub artifact: Option<Artifact>,
    pub main_bytecode: Option<String>,
    pub constructor_bytecode: Option<String>,
}
Expand description

Compiles Huff contracts into EVM bytecode.

Transforms a Contract AST into executable bytecode, handling macro expansion, label resolution, and bytecode optimization.

use huff_neo_codegen::Codegen;
let cg = Codegen::new();

Fields§

§ast: Option<Contract>

The Input AST

§artifact: Option<Artifact>

A cached codegen output artifact

§main_bytecode: Option<String>

Intermediate main bytecode store

§constructor_bytecode: Option<String>

Intermediate constructor bytecode store

Implementations§

Source§

impl Codegen

Source

pub fn new() -> Self

Public associated function to instantiate a new Codegen instance.

Source

pub fn generate_main_bytecode( evm_version: &EVMVersion, contract: &Contract, alternative_main: Option<String>, relax_jumps: bool, ) -> Result<String, CodegenError>

Compiles the contract’s main macro into executable bytecode.

§Arguments
  • evm_version - Target EVM version
  • contract - The contract to compile
  • alternative_main - Optional alternative entry point (defaults to “MAIN”)
  • relax_jumps - Enable jump optimization to reduce bytecode size
Source

pub fn generate_main_bytecode_with_sourcemap( evm_version: &EVMVersion, contract: &Contract, alternative_main: Option<String>, relax_jumps: bool, ) -> Result<MainBytecodeOutput, CodegenError>

Compiles the contract’s main macro into bytecode with source map.

Returns the full main bytecode (body + appended tables), its source map, the length of the body section (offset at which the runtime tables begin), and the per-table runtime offsets. build_artifact uses the body length and table offsets to dedupe constructor-side __tablestart references into the runtime copy.

Source

pub(crate) fn generate_main_bytecode_inner( evm_version: &EVMVersion, contract: &Contract, alternative_main: Option<&str>, relax_jumps: bool, codesize_hints: Option<&BTreeMap<String, usize>>, ) -> Result<(MainBytecodeOutput, Option<BTreeMap<String, usize>>), CodegenError>

Compiles MAIN once, with the macro sizes of the previous pass. Also returns the macro sizes of this pass when a __codesize needed them, so they must reach a fixed point.

Source

pub fn reject_args_start(res: &BytecodeRes) -> Result<(), CodegenError>

Rejects __argsstart() in code that runs as the runtime, such as MAIN or a test, since constructor arguments are only part of the deployment code.

Source

pub fn generate_constructor_bytecode( evm_version: &EVMVersion, contract: &Contract, alternative_constructor: Option<String>, relax_jumps: bool, ) -> Result<(String, bool), CodegenError>

Generates the constructor section in isolation: macro body with all __tablestart placeholders resolved against locally-emitted tables.

This standalone form (tables sitting directly after the body) does not include the deployment-time auto-bootstrap and is not the layout that ends up in the deployed artifact — use Codegen::churn for the final assembly. This function exists for tools and tests that want to inspect just the constructor section. __argsstart() stays a placeholder here, as the offset of the arguments depends on the deployment layout.

Source

pub fn generate_constructor_macro_bytecode( evm_version: &EVMVersion, contract: &Contract, alternative_constructor: Option<String>, relax_jumps: bool, ) -> Result<(ConstructorMacroBytecode, Contract), CodegenError>

Generates constructor macro bytecode without resolving __tablestart placeholders.

This is phase 1 of constructor codegen. Table positions and __tablestart resolution depend on the auto-bootstrap size and the runtime layout, which are only known once build_artifact has both the constructor body and the compiled main bytecode in hand. Phase 2 runs inside build_artifact via Codegen::gen_table_bytecode.

Source

pub fn update_table_size( _evm_version: &EVMVersion, contract: &Contract, ) -> Result<Contract, CodegenError>

Update the table size in the contract that was not know at the time of parsing

Source

pub(crate) fn get_macro_by_name<'a>( name: &str, contract: &'a Contract, ) -> Result<&'a MacroDefinition, CodegenError>

Helper function to find a macro or generate a CodegenError

Source

pub fn gen_constant_value( contract: &Contract, name: &str, span: &AstSpan, ) -> Result<Option<PushValue>, CodegenError>

Resolves a constant to the value [NAME] pushes, or None for a __NOOP constant

Source

pub fn gen_builtin_bytecode( contract: &Contract, bf: &BuiltinFunctionCall, span: AstSpan, ) -> Result<PushValue, CodegenError>

Generates bytecode for a builtin function call used for constants, code tables, etc. Returns a PushValue that can be converted to bytecode with or without opcode

Source

pub fn gen_table_bytecode_builtin( contract: &Contract, table_definition: &TableDefinition, ) -> Result<String, CodegenError>

Generates bytecode for a code table with builtin functions

Source

pub fn gen_table_bytecode( contract: &Contract, res: BytecodeRes, base_offset: usize, external_table_offsets: &HashMap<String, usize>, ) -> Result<TableBytecodeOutput, CodegenError>

Appends table bytecode for tables referenced by res and fills __tablestart placeholders.

base_offset is added to every locally-emitted table’s offset before resolution — used by the constructor pathway to push tables past the auto-bootstrap and main bytecode.

external_table_offsets lets the caller resolve __tablestart to a table emitted somewhere else (e.g. shared with the runtime). Tables found here are not emitted locally; their offset is used directly when filling placeholders.

Source

pub fn macro_to_bytecode<'a>( evm_version: &EVMVersion, macro_def: &'a MacroDefinition, contract: &'a Contract, scope_mgr: &mut ScopeManager<'a>, offset: usize, relax_jumps: bool, ) -> Result<BytecodeRes, CodegenError>

Generates bytecode from a macro definition.

Expands the macro body into bytecode, resolving labels, arguments, and nested macro calls.

§Arguments
  • evm_version - Target EVM version for opcode compatibility
  • macro_def - The macro to compile
  • contract - Contract context for macro and constant lookups
  • scope_mgr - Call stack for tracking macro invocations and scope
  • offset - Starting bytecode offset
  • relax_jumps - Enable jump size optimization
§Returns

Bytecode with label indices, unresolved jumps, and source map information.

Source

pub fn relax_jump_offsets( bytes: BytecodeSegments, jump_table: &JumpTable, label_indices: &LabelIndices, ) -> ResizedBytecode

Shrinks PUSH2 jumps to PUSH1 where the target fits in one byte.

Jump relaxation for span-dependent instructions (“start big and shrink”), an iterative variant of the technique described in Thomas G. Szymanski, “Assembling Code for Machines with Span-Dependent Instructions”, CACM 21(4), 1978, p. 300-308. See also: https://www.complang.tuwien.ac.at/anton/assembling-span-dependent.html

Shrinking only moves code backwards, so it never pushes a target out of range of a jump that was widened before.

Returns the relaxed bytecode, updated label indices, and a mapping from original to new segment offsets.

Source

pub fn widen_jump_offsets( bytes: BytecodeSegments, jump_table: &JumpTable, label_indices: &LabelIndices, ) -> ResizedBytecode

Widens jumps and self-referencing __codesize pushes whose value no longer fits.

Jumps start as PUSH2 and self-referencing __codesize pushes as PUSH1. Code beyond 64 KiB (possible in initcode from Amsterdam) needs PUSH3 targets, and a macro’s own size can need a wider push than first assumed. Widening moves all following code, so this repeats until no push changes (“start small and grow”); it always terminates because pushes only grow.

Returns the widened bytecode, updated label indices, and a mapping from original to new segment offsets.

Source

pub(crate) fn resize_span_dependent_pushes( bytes: BytecodeSegments, jump_table: &JumpTable, label_indices: &LabelIndices, mode: ResizeMode, ) -> ResizedBytecode

Repeatedly resizes span-dependent pushes until their widths are stable.

After every round that changed a width, segment offsets and label positions are recomputed, since a different width moves all code that follows.

Source

pub fn fill_unmatched( bytes: BytecodeSegments, jump_table: &JumpTable, label_indices: &LabelIndices, relax_jumps: bool, ) -> Result<FilledJumps, CodegenError>

Resolves jump placeholders to their target offsets with optional size optimization.

Replaces jump placeholders with actual bytecode offsets by looking up labels in the label index. Jumps whose target does not fit in PUSH2 are widened first; when relax_jumps is enabled, PUSH2 jumps are then shrunk to PUSH1 where targets fit within a single byte (0-255).

§Arguments
  • bytes - Bytecode segments with jump placeholders
  • jump_table - Jump metadata indexed by bytecode offset
  • label_indices - Scoped label positions
  • relax_jumps - Enable jump size optimization
§Returns

Returns resolved bytecode, any unmatched jumps, the final label positions, and a mapping from original to final segment offsets, or an error for label conflicts or invalid jump targets.

Source

pub fn append_functions<'a>( evm_version: &EVMVersion, contract: &'a Contract, scope_mgr: &mut ScopeManager<'a>, offset: &mut usize, jump_table: &mut JumpTable, label_indices: &mut LabelIndices, table_instances: &mut Jumps, bytes: BytecodeSegments, ) -> Result<BytecodeSegments, CodegenError>

Helper associated function to append functions to the end of the bytecode.

§Overview

Iterates over the contract’s functions, generates their bytecode, fills unmatched jumps & label indices, and appends the functions’ bytecode to the end of the contract’s bytecode.

On success, passes ownership of bytes back to the caller. On failure, returns a CodegenError.

Source

pub fn churn( &mut self, evm_version: &EVMVersion, file: Arc<FileSource>, args: Vec<DynSolValue>, main_bytecode: &str, constructor_bytecode: &str, has_custom_bootstrap: bool, main_source_map: Option<Vec<SourceMapEntry>>, constructor_source_map: Option<Vec<SourceMapEntry>>, no_size_limit: bool, ) -> Result<Artifact, CodegenError>

Back-compat shim for assembly from raw bytecode strings.

Synthesizes MainBytecodeOutput and ConstructorMacroBytecode from raw hex strings and forwards to Codegen::assemble_artifact. Use this when you have pre-baked main and constructor bytecode (e.g. existing snapshot tests) and do not need the table-dedup pathway.

Behaves identically to the structured API for inputs that contain no tables.

Source

pub fn assemble_artifact( &mut self, evm_version: &EVMVersion, file: Arc<FileSource>, contract: &Contract, args: Vec<DynSolValue>, main: MainBytecodeOutput, constructor: Option<ConstructorMacroBytecode>, no_size_limit: bool, ) -> Result<Artifact, CodegenError>

Generate a codegen artifact.

Deployment bytecode is laid out as: [ctor_body][bootstrap?][main_bytecode][ctor_only_tables][constructor_args]

A __tablestart(T) reference inside the constructor is resolved against a runtime-resident copy of T when main already emits one (no duplicate); otherwise the table is appended once to the deployment tail and the constructor’s reference points there.

§Arguments
  • evm_version — target EVM version; selects the runtime and initcode size limits.
  • contract — contract AST with table sizes populated by update_table_size. Used to read table definitions during constructor table finalization.
  • args — encoded constructor arguments, appended at the very end of the deployment bytes.
  • main — main/runtime bytecode plus its body length and per-table offsets within the runtime.
  • constructor — phase-1 constructor macro output; None when the contract has no CONSTRUCTOR macro (deployment becomes just bootstrap + main).
  • no_size_limit — skip the runtime and initcode size checks.
Source

pub fn encode_constructor_args( args: &[String], types: Option<&[String]>, ) -> Result<Vec<DynSolValue>, CodegenError>

Reads constructor arguments given as text. With the declared constructor parameter types, each argument is read as its type and the count must match; otherwise each type is guessed from the text. Without arguments nothing is appended, so the deployer can append them later.

Source

pub fn declared_constructor_types(contract: &Contract) -> Option<Vec<String>>

The parameter types of the contract’s #define function constructor(...), if it declares one

Source

pub fn abi_encode_constructor_args(args: Vec<DynSolValue>) -> String

Encodes constructor arguments as hex, the way Solidity’s abi.encode does

Source

pub fn export(output: String, art: &Artifact) -> Result<(), CodegenError>

Export

Writes a Codegen Artifact out to the specified file.

§Arguments
  • out - Output location to write the serialized json artifact to.
Source

pub fn abi_gen( &mut self, ast: Contract, output: Option<String>, ) -> Result<Abi, CodegenError>

Abi Generation

Generates an ABI for the given Ast. Stores the generated ABI in the Codegen artifact.

§Arguments
  • ast - The Contract Abstract Syntax Tree
  • output - An optional output path

Trait Implementations§

Source§

impl Clone for Codegen

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Codegen

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Codegen

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Upcast<T> for S
where T: UpcastFrom<S> + ?Sized, S: ?Sized,

Source§

fn upcast(&self) -> &T
where Self: ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider ref type within the Wasm bindgen generics type system. Read more
Source§

fn upcast_into(self) -> T
where Self: Sized + ErasableGeneric, T: Sized + ErasableGeneric<Repr = Self::Repr>,

Perform a zero-cost type-safe upcast to a wider type within the Wasm bindgen generics type system. Read more
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more

Layout§

Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...) attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.

Size: 672 bytes