Skip to content

Commit

Permalink
Implement a prototype name mangler
Browse files Browse the repository at this point in the history
This commit adds the `hieratika-mangler` crate, responsible for
implementing the hieratika name mangling scheme in a centralized
fashion.

As it exists, the name mangling scheme implemented is _not final_, and
is likely to change and evolve as the requirements are clarified. To
that end, the mangling design docs have not been updated, as no coherent
design process has yet taken place for the mangling scheme.
  • Loading branch information
iamrecursion committed Jan 23, 2025
1 parent 525a2bb commit 9cea036
Show file tree
Hide file tree
Showing 10 changed files with 408 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"crates/cairoc",
"crates/flo",
"crates/test-utils",
"crates/mangler",
]

# Cairo is excluded because it is imported as git submodule and it has its own Cargo workspace.
Expand Down Expand Up @@ -55,6 +56,7 @@ hieratika-compiler = { path = "crates/compiler" }
hieratika-driver = { path = "crates/driver" }
hieratika-errors = { path = "crates/error" }
hieratika-flo = { path = "crates/flo" }
hieratika-mangler = { path = "crates/mangler" }
hieratika-test-utils = { path = "crates/test-utils" }
miette = { version = "7.4.0", features = ["fancy"] }
starknet-types-core = "0.1.7"
Expand Down
9 changes: 8 additions & 1 deletion crates/error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
pub mod backtrace;
pub mod compile;
pub mod mangle;

use thiserror::Error;

Expand All @@ -28,9 +29,15 @@ pub type Result<T> = miette::Result<T, WithBacktrace<Error>>;
/// _truly_ public interface of this library should return this error type.
#[derive(Debug, Error)]
pub enum Error {
/// Errors in the compilation of cairo code to FLO.
#[error(transparent)]
CairoCompile(#[from] compile::cairo::Error),

/// Errors in the compilation of LLVM code to FLO.
#[error(transparent)]
LLVMCompile(#[from] compile::llvm::Error),

/// Errors in the mangling or de-mangling of names.
#[error(transparent)]
CairoCompile(#[from] compile::cairo::Error),
Mangle(#[from] mangle::Error),
}
24 changes: 24 additions & 0 deletions crates/error/src/mangle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Errors in the mangling process.
use thiserror::Error;

use crate::backtrace::WithBacktrace;

/// The result type for use in the mangler.
pub type Result<T> = miette::Result<T, WithBacktrace<Error>>;

/// This error type is for use during the process of compilation from LLVM IR to
/// the Cairo IR.
#[derive(Debug, Error)]
pub enum Error {
#[error("The input {_0} is not a valid mangle input")]
InvalidInput(String),
}

impl Error {
/// Constructs [`Error::InvalidInput`] while allowing conversion from a
/// [`str`].
pub fn invalid_input(mangle_input: &str) -> Self {
Self::InvalidInput(mangle_input.to_string())
}
}
20 changes: 20 additions & 0 deletions crates/mangler/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "hieratika-mangler"
version.workspace = true
homepage.workspace = true
repository.workspace = true
license-file.workspace = true

authors.workspace = true
description = "A crate implementing the Hieratika internal mangling scheme."
keywords.workspace = true
categories.workspace = true

edition.workspace = true
rust-version.workspace = true

[dependencies]
hieratika-errors.workspace = true
hieratika-flo.workspace = true

[dev-dependencies]
4 changes: 4 additions & 0 deletions crates/mangler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Hieratika Mangler

This crate is responsible for implementing the name mangling algorithm used by Hieratika. For more
information, please see the [docs](../../docs/Name%20Mangling.md) on name mangling.
17 changes: 17 additions & 0 deletions crates/mangler/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! This module contains constants that specify portions of the mangling
//! behavior.
/// A marker used to separate sections in the mangled string.
pub const SECTION_SEPARATOR: &str = "$";

/// A marker used to signify the beginning of a snapshot mangle segment.
pub const BEGIN_SNAPSHOT: &str = "m";

/// A marker used to signify the beginning of an array.
pub const BEGIN_ARRAY: &str = "A";

/// A marker used to signify the beginning of a struct.
pub const BEGIN_STRUCT: &str = "S";

/// A marker used to signify the end of a struct.
pub const END_STRUCT: &str = "s";
101 changes: 101 additions & 0 deletions crates/mangler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! This crate implements Hieratika's name mangling scheme, providing a
//! centralized place for the mangling functionality to live that can be
//! accessed by all the other crates.
//!
//! See [`mangle`] for the primary interface to the crate and for usage
//! examples.
//!
//! # Mangling Scheme
//!
//! The mangling scheme is designed to ensure a compact and unique
//! representation for functions across different modules that may share name
//! and/or type information. Please note that the current design of this
//! mangling scheme is **not final** and is subject to change.
#![warn(clippy::all, clippy::cargo, clippy::pedantic)]
#![expect(clippy::multiple_crate_versions)] // Enforced by our dependencies

pub mod constants;
pub mod mapping;
mod util;

use hieratika_flo::types::Type;

use crate::{
constants::SECTION_SEPARATOR,
mapping::{mangle_params, mangle_returns},
};

/// The result type for the library.
pub type Result<T> = hieratika_errors::mangle::Result<T>;

/// The error type for the library.
pub type Error = hieratika_errors::mangle::Error;

/// Generates the mangled form of the provided `name`.
///
/// A mangled name consists of the return types string, followed by the function
/// name, followed by the params string, followed by the function's module, all
/// separated using the [`SECTION_SEPARATOR`].
///
/// ```
/// use hieratika_flo::types::Type;
/// use hieratika_mangler::{NameInfo, mangle};
///
/// let func_name = NameInfo::new(
/// "my_func",
/// "my_module",
/// vec![Type::Double, Type::Bool],
/// vec![Type::Float, Type::Bool],
/// );
///
/// assert_eq!(mangle(func_name).unwrap(), "fc$my_func$dc$my_module");
/// ```
///
/// # Errors
///
/// - [`Error::InvalidInput`] if any of the types in the input `name` cannot be
/// mangled.
pub fn mangle(name: NameInfo) -> Result<String> {
let returns_string = mangle_returns(&name.return_types)?;
let params_string = mangle_params(&name.parameter_types)?;
let func_name = name.name;
let func_module = name.module;
Ok([returns_string, func_name, params_string, func_module].join(SECTION_SEPARATOR))
}

/// The inputs to the name mangling process.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NameInfo {
/// The name of the symbol to be mangled.
pub name: String,

/// The name of the module in which the symbol was found.
pub module: String,

/// The types of the parameters to the function to be mangled.
pub parameter_types: Vec<Type>,

/// The types of the returns from the function to be mangled.
pub return_types: Vec<Type>,
}

impl NameInfo {
/// Creates a new [`NameInfo`] instance from the provided information.
#[must_use]
pub fn new(
name: &str,
module: &str,
parameter_types: Vec<Type>,
return_types: Vec<Type>,
) -> Self {
let name = name.into();
let module = module.into();
NameInfo {
name,
module,
parameter_types,
return_types,
}
}
}
Loading

0 comments on commit 9cea036

Please sign in to comment.