Skip to content

Commit

Permalink
various changes: rename Wesl::new_spec_compliant=>new; make resolver …
Browse files Browse the repository at this point in the history
…wrappers generic over inner type; Wesl.mangler is sync; tweaked doc comments; CLI no generics by default
  • Loading branch information
k2d222 committed Feb 3, 2025
1 parent 32423ae commit 1f89c18
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 63 deletions.
6 changes: 1 addition & 5 deletions crates/wesl/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,11 +424,7 @@ pub(crate) fn imported_resources(imports: &[syntax::Import], parent_res: &Resour
res
}

fn mangle_decls<'a>(
wgsl: &'a mut TranslationUnit,
resource: &'a Resource,
mangler: &'a impl Mangler,
) {
fn mangle_decls<'a>(wgsl: &'a mut TranslationUnit, resource: &'a Resource, mangler: &impl Mangler) {
wgsl.global_declarations
.iter_mut()
.filter_map(|decl| decl.ident_mut())
Expand Down
26 changes: 13 additions & 13 deletions crates/wesl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//!
//! See [`Wesl`] for an overview of the high-level API.
//! ```rust
//! let compiler = Wesl::new_spec_compliant("src/shaders");
//! let compiler = Wesl::new("src/shaders");
//!
//! // compile a WESL file to a WGSL string
//! let wgsl_str = compiler
Expand All @@ -36,7 +36,7 @@
//! ```rust
//! # use wesl::{Wesl, FileResolver};
//! fn main() {
//! Wesl::new_spec_compliant("src/shaders")
//! Wesl::new("src/shaders")
//! .build_artefact("main.wesl", "my_shader");
//! }
//! ```
Expand All @@ -56,7 +56,7 @@
//! Evaluate const-expressions.
//!```rust
//! # use wesl::{Wesl};
//! # let compiler = Wesl::new_spec_compliant("");
//! # let compiler = Wesl::new("");
//! // ...standalone expression
//! let wgsl_expr = compiler.eval("abs(3 - 5)").unwrap().to_string();
//!
Expand Down Expand Up @@ -181,7 +181,7 @@ pub enum ManglerKind {
None,
}

fn make_mangler(kind: ManglerKind) -> Box<dyn Mangler> {
fn make_mangler(kind: ManglerKind) -> Box<dyn Mangler + Sync + 'static> {
match kind {
ManglerKind::Escape => Box::new(EscapeMangler),
ManglerKind::Hash => Box::new(HashMangler),
Expand Down Expand Up @@ -225,14 +225,14 @@ macro_rules! wesl_pkg {
/// # Basic Usage
///
/// ```rust
/// let compiler = Wesl::new_spec_compliant("path/to/dir/containing/shaders");
/// let compiler = Wesl::new("path/to/dir/containing/shaders");
/// let wgsl_string = compiler.compile("main.wesl").unwrap().to_string();
/// ```
pub struct Wesl<R: Resolver> {
options: CompileOptions,
use_sourcemap: bool,
resolver: R,
mangler: Box<dyn Mangler>,
mangler: Box<dyn Mangler + Sync + 'static>,
}

impl Wesl<StandardResolver> {
Expand All @@ -242,13 +242,13 @@ impl Wesl<StandardResolver> {
/// It's probably what you want to use in most cases. You can customize it with other
/// functions.
///
/// See also: [`Wesl::new_barebones`], [`Wesl::new_spec_compliant`].
/// See also: [`Wesl::new_barebones`], [`Wesl::new_experimental`].
///
/// # WESL Reference
/// * (mandatory) Imports: [`Imports.md`](https://github.com/wgsl-tooling-wg/wesl-spec/blob/main/Imports.md) (specification for `imports` is not stabilized yet)
/// * (mandatory) Conditional translation: [`ConditionalTranslation.md`](https://github.com/wgsl-tooling-wg/wesl-spec/blob/main/ConditionalTranslation.md)
/// * (optional) Stripping: spec not yet available.
pub fn new_spec_compliant(base: impl AsRef<Path>) -> Self {
pub fn new(base: impl AsRef<Path>) -> Self {
Self {
options: CompileOptions {
imports: true,
Expand All @@ -270,11 +270,11 @@ impl Wesl<StandardResolver> {
/// Get a WESL compiler with all functionalities enabled, including *experimental*
/// ones.
///
/// See also: [`Wesl::new_barebones`] and [`Wesl::new_spec_compliant`].
/// See also: [`Wesl::new`] and [`Wesl::new_barebones`].
///
/// # WESL Reference
/// This Wesl compiler is *not* spec-compliant because it enables all extensions
/// including *experimental* and *non-standard* ones. See [`Wesl::new_spec_compliant`].
/// including *experimental* and *non-standard* ones. See [`Wesl::new`].
///
/// Experimental extensions: `generics`
/// Non-standard extensions: `@const`
Expand Down Expand Up @@ -342,7 +342,7 @@ impl Wesl<NoResolver> {
///
/// # WESL Reference
/// This Wesl compiler is *not* spec-compliant because it does not enable *mandatory*
/// WESL extensions. See [`Wesl::new_spec_compliant`].
/// WESL extensions. See [`Wesl::new`].
pub fn new_barebones() -> Self {
Self {
options: CompileOptions {
Expand Down Expand Up @@ -389,7 +389,7 @@ impl<R: Resolver> Wesl<R> {
/// # WESL Reference
/// All [builtin manglers](ManglerKind) are spec-compliant, except [`NoMangler`] ([`ManglerKind::None`]).
/// Spec: not yet available.
pub fn set_custom_mangler(mut self, mangler: impl Mangler + 'static) -> Self {
pub fn set_custom_mangler(mut self, mangler: impl Mangler + Sync + 'static) -> Self {
self.mangler = Box::new(mangler);
self
}
Expand All @@ -404,7 +404,7 @@ impl<R: Resolver> Wesl<R> {
/// let mut router = Router::new();
/// router.mount_fallback_resolver(FileResolver::new("src/shaders"));
/// router.mount_resolver("runtime", resolver);
/// let compiler = Wesl::new_spec_compliant("").set_custom_resolver(router);
/// let compiler = Wesl::new("").set_custom_resolver(router);
/// ```
///
/// # WESL Reference
Expand Down
14 changes: 7 additions & 7 deletions crates/wesl/src/mangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ impl<T: Mangler> Mangler for &T {
}
}

/// A mangler for the filesystem resources hashes the resource identifier.
/// e.g. `foo/bar/baz.wgsl item => item_32938483840293402930392`
/// A mangler that hashes the resource identifier.
/// e.g. `foo::bar::baz item => item_32938483840293402930392`
#[derive(Default, Clone, Debug)]
pub struct HashMangler;

Expand All @@ -69,8 +69,8 @@ impl Mangler for HashMangler {
}
}

/// A mangler for the filesystem resources that gives the escaped path to the resource.
/// e.g. `foo/bar/baz.wgsl item => foo_bar_bazwgsl_item`
/// A mangler that gives the escaped path to the resource.
/// e.g. `foo::bar_baz item => foo_bar__baz_item`
///
/// Warning: the file path segments must be valid wgsl identifiers.
#[derive(Default, Clone, Debug)]
Expand Down Expand Up @@ -119,7 +119,7 @@ impl Mangler for EscapeMangler {
}

/// A mangler that just returns the identifer as-is (no mangling).
/// e.g. `foo/bar/baz.wgsl item => item`
/// e.g. `foo::bar::baz item => item`
///
/// Warning: will break the program in case of name conflicts.
#[derive(Default, Clone, Debug)]
Expand Down Expand Up @@ -166,9 +166,9 @@ impl<'a, T: Mangler> Mangler for CacheMangler<'a, T> {
}

/// A mangler that uses cryptic unicode symbols that look like :, < and >
/// e.g. `foo/bar/baz.wgsl item => item`
/// e.g. `foo::bar::baz array<f32,2> => foo::bar::baz::arrayᐸf32ˏ2ᐳ`
///
/// Warning: will break the program in case of name conflicts.
/// Very unlikely to collide unless using U+02D0 characters
///
/// # Panics
/// if the TypeExpression is not normalized (i.e. contains only identifiers and literals)
Expand Down
42 changes: 42 additions & 0 deletions crates/wesl/src/overload.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::collections::HashMap;

use itertools::Itertools;
use wgsl_parse::syntax::{
Function, GlobalDeclaration, Ident, Import, TranslationUnit, TypeExpression,
};

use crate::{
import::{absolute_resource, imported_resources, normalize_resource},
visit::Visit,
Mangler, Resource,
};

fn normalize_ty(
ty: &TypeExpression,
parent_res: &Resource,
imports: &HashMap<Ident, (Resource, Ident)>,
) -> TypeExpression {
let mut ty = ty.clone();
if let Some(path) = &ty.path {
let res = normalize_resource(path, parent_res, imports);
ty.path = Some(res.path().to_path_buf());
} else {
ty.path = Some(parent_res.path().to_path_buf());
}
ty
}

pub(crate) fn mangle(wesl: &mut TranslationUnit, resource: &Resource, mangler: &impl Mangler) {
let imports = imported_resources(&wesl.imports, resource);

for decl in &mut wesl.global_declarations {
if let GlobalDeclaration::Function(decl) = decl {
// TODO: type aliases
let sig = decl
.parameters
.iter()
.map(|p| normalize_ty(&p.ty, resource, &imports)).collect_vec()
let res = mangler.mangle_signature(decl.ident.name().as_str(), &sig);
}
}
}
53 changes: 20 additions & 33 deletions crates/wesl/src/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{Diagnostic, Error, SyntaxUtil};

use itertools::Itertools;
use wgsl_parse::syntax::{Ident, TranslationUnit};
use wgsl_parse::syntax::TranslationUnit;

use std::{
borrow::Cow,
Expand Down Expand Up @@ -33,16 +33,6 @@ pub struct Resource {
path: PathBuf,
}

/// An importable uniquely identify a declaration.
///
/// Each declaration must be associated with a unique `Importable`, and an `Importable` must
/// identify a unique declaration.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Importable {
pub resource: Resource,
pub ident: Ident,
}

fn clean_path(path: impl AsRef<Path>) -> PathBuf {
let mut res = PathBuf::new();
for comp in path.as_ref().with_extension("").components() {
Expand Down Expand Up @@ -202,21 +192,21 @@ impl Resolver for NoResolver {
}

/// A resolver that remembers to avoid multiple fetches.
pub struct CacheResolver<'a> {
resolver: Box<dyn Resolver + 'a>,
pub struct CacheResolver<R: Resolver> {
resolver: R,
cache: RefCell<HashMap<Resource, String>>,
}

impl<'a> CacheResolver<'a> {
pub fn new(resolver: Box<dyn Resolver + 'a>) -> Self {
impl<R: Resolver> CacheResolver<R> {
pub fn new(resolver: R) -> Self {
Self {
resolver,
cache: Default::default(),
}
}
}

impl<'a> Resolver for CacheResolver<'a> {
impl<R: Resolver> Resolver for CacheResolver<R> {
fn resolve_source<'b>(&'b self, resource: &Resource) -> Result<Cow<'b, str>, E> {
let mut cache = self.cache.borrow_mut();

Expand All @@ -242,8 +232,6 @@ impl<'a> Resolver for CacheResolver<'a> {
}

/// A resolver that looks for files in the filesystem.
///
/// This is the default resolver.
#[derive(Default)]
pub struct FileResolver {
base: PathBuf,
Expand Down Expand Up @@ -307,10 +295,9 @@ impl Resolver for FileResolver {
}
}

/// A resolver that resolves WESL modules added with [`VirtualResolver::add_module`].
/// A resolver that resolves WESL in-memory modules added with [`Self::add_module`].
///
/// This can be used in platforms that lack a filesystem (e.g. WASM) or for
/// runtime-generated files.
/// Use-cases are platforms that lack a filesystem (e.g. WASM) or for runtime-generated files.
#[derive(Default)]
pub struct VirtualResolver {
files: HashMap<Resource, String>,
Expand Down Expand Up @@ -349,26 +336,23 @@ impl<T: Fn(&mut TranslationUnit) -> Result<(), Error>> ResolveFn for T {}

/// A WESL module preprocessor.
///
/// The preprocess function will be called each time the WESL compiler tries accesses a
/// module. The preprocessor can modify the module syntax tree at will.
///
/// The preprocess function *must* always return the same syntax tree for a given module
/// path.
pub struct Preprocessor<'a, F: ResolveFn> {
pub resolver: Box<dyn Resolver + 'a>,
/// The preprocess function will be called each time the WESL compiler tries to load a module.
/// The preprocess function *must* always return the same syntax tree for a given module path.
pub struct Preprocessor<R: Resolver, F: ResolveFn> {
pub resolver: R,
pub preprocess: F,
}

impl<'a, F: ResolveFn> Preprocessor<'a, F> {
pub fn new(resolver: Box<dyn Resolver + 'a>, preprocess: F) -> Self {
impl<R: Resolver, F: ResolveFn> Preprocessor<R, F> {
pub fn new(resolver: R, preprocess: F) -> Self {
Self {
resolver,
preprocess,
}
}
}

impl<'a, F: ResolveFn> Resolver for Preprocessor<'a, F> {
impl<R: Resolver, F: ResolveFn> Resolver for Preprocessor<R, F> {
fn resolve_source<'b>(&'b self, resource: &Resource) -> Result<Cow<'b, str>, E> {
let res = self.resolver.resolve_source(resource)?;
Ok(res)
Expand All @@ -395,7 +379,9 @@ impl<'a, F: ResolveFn> Resolver for Preprocessor<'a, F> {
/// A router is a resolver that can dispatch imports to several sub-resolvers based on the
/// import path prefix.
///
/// Add sub-resolvers with [`Router::mount_resolver`].
/// Add sub-resolvers with [`Self::mount_resolver`].
///
/// This resolver is not thread-safe ([`Sync`]).
pub struct Router {
mount_points: Vec<(PathBuf, Box<dyn Resolver>)>,
fallback: Option<(PathBuf, Box<dyn Resolver>)>,
Expand Down Expand Up @@ -427,7 +413,7 @@ impl Router {
self.mount_resolver("", resolver);
}

fn route(&self, resource: &Resource) -> Result<(&Box<dyn Resolver>, Resource), E> {
fn route(&self, resource: &Resource) -> Result<(&dyn Resolver, Resource), E> {
let (mount_path, resolver) = self
.mount_points
.iter()
Expand Down Expand Up @@ -536,6 +522,7 @@ impl Resolver for PkgResolver {
}
}

/// The resolver that implements the WESL standard.
pub struct StandardResolver {
pkg: PkgResolver,
router: Router,
Expand Down
2 changes: 1 addition & 1 deletion examples/wesl-consumer/build.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fn main() {
#[cfg(feature = "build-time")]
wesl::Wesl::new_spec_compliant("src/shaders")
wesl::Wesl::new("src/shaders")
.add_package(&wesl_random::random::Mod)
.build_artefact("main", "main");
}
2 changes: 1 addition & 1 deletion examples/wesl-consumer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ fn main() {
};

#[cfg(not(feature = "build-time"))]
let source = wesl::Wesl::new_spec_compliant("src/shaders")
let source = wesl::Wesl::new("src/shaders")
.add_package(&wesl_random::random::Mod)
.compile("main")
.inspect_err(|e| {
Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ struct CompOptsArgs {
/// Disable conditional compilation
#[arg(long)]
no_cond_comp: bool,
/// Disable generics
/// Enable generics
#[arg(long)]
no_generics: bool,
generics: bool,
/// Disable stripping unused declarations
#[arg(long)]
no_strip: bool,
Expand Down Expand Up @@ -127,7 +127,7 @@ impl From<&CompOptsArgs> for CompileOptions {
Self {
imports: !opts.no_imports,
condcomp: !opts.no_cond_comp,
generics: !opts.no_generics,
generics: opts.generics,
strip: !opts.no_strip,
lower: !opts.no_lower,
validate: !opts.no_validate,
Expand Down

0 comments on commit 1f89c18

Please sign in to comment.