miden_assembly/project/providers.rs
1mod masm;
2
3use miden_assembly_syntax::debuginfo::SourceManager;
4use miden_project::ProjectDependencyGraph;
5
6pub use self::masm::MasmSourceProvider;
7use super::*;
8
9/// This struct provides important context about the current target being assembled to
10/// implementations of the [ProjectSourceProvider] trait.
11pub struct TargetAssemblyContext<'a> {
12 /// The package manifest for the target being assembled
13 pub package: &'a ProjectPackage,
14 /// The resolved/canonicalized package manifest path
15 pub manifest_path: &'a std::path::Path,
16 /// The resolved/canonicalized path to the directory containing `manifest_path`
17 pub project_root: &'a std::path::Path,
18 /// The resolved/canonicalized path to the root source file of `target`
19 pub resolved_target_root: Box<std::path::Path>,
20 /// The target being assembled
21 pub target: &'a Target,
22 /// The build profile selected for this assembly session
23 pub profile: &'a Profile,
24 /// The dependency graph computed for this assembly session
25 pub dependency_graph: &'a ProjectDependencyGraph,
26 /// The current source manager
27 pub source_manager: Arc<dyn SourceManager>,
28 /// The assembler-wide `warnings_as_errors` flag
29 pub warnings_as_errors: bool,
30}
31
32impl<'a> TargetAssemblyContext<'a> {
33 pub fn new(
34 package: &'a ProjectPackage,
35 manifest_path: &'a std::path::Path,
36 target: &'a Target,
37 profile: &'a Profile,
38 dependency_graph: &'a ProjectDependencyGraph,
39 source_manager: Arc<dyn SourceManager>,
40 ) -> Result<Self, Report> {
41 let project_root = manifest_path.parent().ok_or_else(|| {
42 Report::msg(format!("manifest '{}' has no parent directory", manifest_path.display()))
43 })?;
44 let target_path = target.path.to_path().ok_or_else(|| {
45 Report::msg(format!(
46 "invalid target '{}': '{}' is not a valid file path",
47 target.name.inner(),
48 target.path
49 ))
50 })?;
51 let root_path = project_root.join(&target_path);
52 let root_path = root_path.canonicalize().map_err(|error| {
53 Report::msg(format!(
54 "failed to resolve target source '{}': {error}",
55 root_path.display()
56 ))
57 })?;
58 Ok(TargetAssemblyContext {
59 package,
60 manifest_path,
61 project_root,
62 resolved_target_root: root_path.into_boxed_path(),
63 target,
64 profile,
65 dependency_graph,
66 source_manager,
67 warnings_as_errors: false,
68 })
69 }
70
71 #[inline]
72 pub fn with_warnings_as_errors(&mut self, yes: bool) -> &mut Self {
73 self.warnings_as_errors = yes;
74 self
75 }
76}
77
78/// This trait provides source file inputs for a Miden Assembly project, regardless of the source
79/// language it was derived from.
80///
81/// For Miden Assembly source projects this is straightforward, see [MasmSourceProvider].
82///
83/// For languages other than MASM, which require a compilation step to produce Miden Assembly AST
84/// from the source language prior to assembly, this trait provides the necessary hooks so that
85/// the project assembler can request compilation of a project in source form on-demand.
86/// Implementors are given all available information needed to compile to MASM, and are expected
87/// to return requested artifacts to the project assembler.
88///
89/// Source providers are registered by the file type (i.e. file extension used by the source file)
90/// with the assembler when it is created. Only one source provider per-file-type is allowed.
91pub trait ProjectSourceProvider {
92 /// Returns the file extension this provider should be registered as handling, e.g. `rs`
93 fn file_type(&self) -> &'static str;
94 /// Called to request the compiled/parsed Miden Assembly AST corresponding to the current target
95 /// being assembled.
96 fn provide_sources(
97 &self,
98 context: &TargetAssemblyContext<'_>,
99 ) -> Result<ProjectSourceInputs, Report>;
100 /// Called to request the source files that are inputs to assembly of the current target, so
101 /// that source provenance hash for the target can be computed.
102 ///
103 /// It is expected that all source files that contribute to the build be included in the set
104 /// of source inputs returned, otherwise package identity for the assembled target will be
105 /// incomplete, and another instance of the same package may be used from the cache if the
106 /// source provenance appears unchanged, even when the artifacts produced would be different.
107 ///
108 /// For MASM packages, the above is already guaranteed - but for compilation of packages in
109 /// other languages, such as Rust, the toolchain invoking the assembler must ensure that all
110 /// build inputs are accounted for. Note that you _do not_ need to include the sources of
111 /// your Miden dependencies, and non-Miden dependencies can be accounted for by hashing a
112 /// dependency lock file if present (e.g. `Cargo.toml`).
113 fn provide_source_provenance(
114 &self,
115 context: &TargetAssemblyContext<'_>,
116 ) -> Result<ProjectSourceProvenanceInputs, Report>;
117}