microsoft/qdk
Publicmirrored fromhttps://github.com/microsoft/qdkAvailable
compiler/qsc/src/compile.rs
154lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | use miette::{Diagnostic, Report}; |
| 5 | use qsc_data_structures::{language_features::LanguageFeatures, target::TargetCapabilityFlags}; |
| 6 | pub use qsc_frontend::compile::Dependencies; |
| 7 | use qsc_frontend::{ |
| 8 | compile::{CompileUnit, PackageStore, SourceMap}, |
| 9 | error::WithSource, |
| 10 | }; |
| 11 | use qsc_passes::{run_core_passes, run_default_passes, PackageType}; |
| 12 | use thiserror::Error; |
| 13 | |
| 14 | pub type Error = WithSource<ErrorKind>; |
| 15 | |
| 16 | #[derive(Clone, Debug, Diagnostic, Error)] |
| 17 | #[error(transparent)] |
| 18 | /// `ErrorKind` represents the different kinds of errors that can occur in the compiler. |
| 19 | /// Each variant of the enum corresponds to a different stage of the compilation process. |
| 20 | pub enum ErrorKind { |
| 21 | /// `Frontend` variant represents errors that occur during the frontend stage of the compiler. |
| 22 | /// These errors are typically related to syntax and semantic checks. |
| 23 | #[diagnostic(transparent)] |
| 24 | Frontend(#[from] qsc_frontend::compile::Error), |
| 25 | |
| 26 | /// `Pass` variant represents errors that occur during the `qsc_passes` stage of the compiler. |
| 27 | /// These errors are typically related to optimization, transformation, code generation, passes, |
| 28 | /// and static analysis passes. |
| 29 | #[diagnostic(transparent)] |
| 30 | Pass(#[from] qsc_passes::Error), |
| 31 | |
| 32 | /// `Lint` variant represents lints generated during the linting stage. These diagnostics are |
| 33 | /// typically emitted from the language server and happens after all other compilation passes. |
| 34 | #[diagnostic(transparent)] |
| 35 | Lint(#[from] qsc_linter::Lint), |
| 36 | |
| 37 | #[error("Cycle in dependency graph")] |
| 38 | /// `DependencyCycle` occurs when there is a cycle in the dependency graph. |
| 39 | DependencyCycle, |
| 40 | } |
| 41 | |
| 42 | /// Compiles a package from its AST representation. |
| 43 | #[must_use] |
| 44 | #[allow(clippy::module_name_repetitions)] |
| 45 | pub fn compile_ast( |
| 46 | store: &PackageStore, |
| 47 | dependencies: &Dependencies, |
| 48 | ast_package: qsc_ast::ast::Package, |
| 49 | sources: SourceMap, |
| 50 | package_type: PackageType, |
| 51 | capabilities: TargetCapabilityFlags, |
| 52 | ) -> (CompileUnit, Vec<Error>) { |
| 53 | let unit = qsc_frontend::compile::compile_ast( |
| 54 | store, |
| 55 | dependencies, |
| 56 | ast_package, |
| 57 | sources, |
| 58 | capabilities, |
| 59 | vec![], |
| 60 | ); |
| 61 | process_compile_unit(store, package_type, unit) |
| 62 | } |
| 63 | |
| 64 | /// Compiles a package from its source representation. |
| 65 | #[must_use] |
| 66 | pub fn compile( |
| 67 | store: &PackageStore, |
| 68 | dependencies: &Dependencies, |
| 69 | sources: SourceMap, |
| 70 | package_type: PackageType, |
| 71 | capabilities: TargetCapabilityFlags, |
| 72 | language_features: LanguageFeatures, |
| 73 | ) -> (CompileUnit, Vec<Error>) { |
| 74 | let unit = qsc_frontend::compile::compile( |
| 75 | store, |
| 76 | dependencies, |
| 77 | sources, |
| 78 | capabilities, |
| 79 | language_features, |
| 80 | ); |
| 81 | process_compile_unit(store, package_type, unit) |
| 82 | } |
| 83 | |
| 84 | #[must_use] |
| 85 | #[allow(clippy::module_name_repetitions)] |
| 86 | fn process_compile_unit( |
| 87 | store: &PackageStore, |
| 88 | package_type: PackageType, |
| 89 | mut unit: CompileUnit, |
| 90 | ) -> (CompileUnit, Vec<Error>) { |
| 91 | let mut errors = Vec::new(); |
| 92 | for error in unit.errors.drain(..) { |
| 93 | errors.push(WithSource::from_map(&unit.sources, error.into())); |
| 94 | } |
| 95 | |
| 96 | if errors.is_empty() { |
| 97 | for error in run_default_passes(store.core(), &mut unit, package_type) { |
| 98 | errors.push(WithSource::from_map(&unit.sources, error.into())); |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | (unit, errors) |
| 103 | } |
| 104 | |
| 105 | #[must_use] |
| 106 | pub fn package_store_with_stdlib( |
| 107 | capabilities: TargetCapabilityFlags, |
| 108 | ) -> (qsc_hir::hir::PackageId, PackageStore) { |
| 109 | let mut store = PackageStore::new(core()); |
| 110 | let std_id = store.insert(std(&store, capabilities)); |
| 111 | (std_id, store) |
| 112 | } |
| 113 | |
| 114 | /// Compiles the core library. |
| 115 | /// |
| 116 | /// # Panics |
| 117 | /// |
| 118 | /// Panics if the core library compiles with errors. |
| 119 | #[must_use] |
| 120 | pub fn core() -> CompileUnit { |
| 121 | let mut unit = qsc_frontend::compile::core(); |
| 122 | let pass_errors = run_core_passes(&mut unit); |
| 123 | if pass_errors.is_empty() { |
| 124 | unit |
| 125 | } else { |
| 126 | for error in pass_errors { |
| 127 | let report = Report::new(WithSource::from_map(&unit.sources, error)); |
| 128 | eprintln!("{report:?}"); |
| 129 | } |
| 130 | |
| 131 | panic!("could not compile core library") |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | /// Compiles the standard library. |
| 136 | /// |
| 137 | /// # Panics |
| 138 | /// |
| 139 | /// Panics if the standard library does not compile without errors. |
| 140 | #[must_use] |
| 141 | pub fn std(store: &PackageStore, capabilities: TargetCapabilityFlags) -> CompileUnit { |
| 142 | let mut unit = qsc_frontend::compile::std(store, capabilities); |
| 143 | let pass_errors = run_default_passes(store.core(), &mut unit, PackageType::Lib); |
| 144 | if pass_errors.is_empty() { |
| 145 | unit |
| 146 | } else { |
| 147 | for error in pass_errors { |
| 148 | let report = Report::new(WithSource::from_map(&unit.sources, error)); |
| 149 | eprintln!("{report:?}"); |
| 150 | } |
| 151 | |
| 152 | panic!("could not compile standard library") |
| 153 | } |
| 154 | } |
| 155 | |