Skip to content

Commit

Permalink
Unify AST compilation code between core and forc. (FuelLabs#4670)
Browse files Browse the repository at this point in the history
## Description

This unifies the AST compilation step between forc and core, so both are
running througn the same code path.
Working on this as a prerequisite towards AST caching.

## Checklist

- [ ] I have linked to any relevant issues.
- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [ ] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [ ] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [ ] I have requested a review from the relevant team or maintainers.

Co-authored-by: Joshua Batty <[email protected]>
  • Loading branch information
tritao and JoshuaBatty authored Jun 27, 2023
1 parent 9bfae12 commit f246d97
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 152 deletions.
177 changes: 63 additions & 114 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use std::{
sync::Arc,
};
use sway_core::fuel_prelude::fuel_tx::ConsensusParameters;
pub use sway_core::Programs;
use sway_core::{
abi_generation::{
evm_json_abi,
Expand All @@ -37,11 +38,7 @@ use sway_core::{
fuel_crypto,
fuel_tx::{self, Contract, ContractId, StorageSlot},
},
language::{
lexed::LexedProgram,
parsed::{ParseProgram, TreeType},
ty, Visibility,
},
language::{parsed::TreeType, Visibility},
semantic_analysis::namespace,
source_map::SourceMap,
transform::AttributeKind,
Expand Down Expand Up @@ -322,13 +319,6 @@ pub struct MemberFilter {
pub build_libraries: bool,
}

/// Contains the lexed, parsed, and typed compilation stages of a program.
pub struct Programs {
pub lexed: LexedProgram,
pub parsed: ParseProgram,
pub typed: Option<ty::TyProgram>,
}

impl Default for MemberFilter {
fn default() -> Self {
Self {
Expand Down Expand Up @@ -826,20 +816,6 @@ impl BuildPlan {
}
}

impl Programs {
pub fn new(
lexed: LexedProgram,
parsed: ParseProgram,
typed: Option<ty::TyProgram>,
) -> Programs {
Programs {
lexed,
parsed,
typed,
}
}
}

/// Given a graph and the known project name retrieved from the manifest, produce an iterator
/// yielding any nodes from the graph that might potentially be a project node.
fn potential_proj_nodes<'a>(g: &'a Graph, proj_name: &'a str) -> impl 'a + Iterator<Item = NodeIx> {
Expand Down Expand Up @@ -1750,33 +1726,6 @@ fn find_core_dep(graph: &Graph, node: NodeIx) -> Option<NodeIx> {
None
}

/// Compiles the package to an AST.
pub fn compile_ast(
pkg: &PackageDescriptor,
build_profile: &BuildProfile,
engines: &Engines,
namespace: namespace::Module,
package_name: &str,
metrics: &mut PerformanceData,
) -> Result<CompileResult<ty::TyProgram>> {
let source = pkg.manifest_file.entry_string()?;
let sway_build_config = sway_build_config(
pkg.manifest_file.dir(),
&pkg.manifest_file.entry_path(),
pkg.target,
build_profile,
)?;
let ast_res = sway_core::compile_to_ast(
engines,
source,
namespace,
Some(&sway_build_config),
package_name,
metrics,
);
Ok(ast_res)
}

/// Compiles the given package.
///
/// ## Program Types
Expand Down Expand Up @@ -1813,16 +1762,28 @@ pub fn compile(
print_on_failure(engines.se(), terse_mode, warnings, errors, reverse_results);
bail!("Failed to compile {}", pkg.name);
};
let source = pkg.manifest_file.entry_string()?;

// First, compile to an AST. We'll update the namespace and check for JSON ABI output.
let ast_res = time_expr!(
"compile to ast",
"compile_to_ast",
compile_ast(pkg, profile, engines, namespace, &pkg.name, &mut metrics)?,
sway_core::compile_to_ast(
engines,
source,
namespace,
Some(&sway_build_config),
&pkg.name,
&mut metrics,
),
Some(sway_build_config.clone()),
metrics
);
let typed_program = match ast_res.value.as_ref() {
let programs = match ast_res.value.as_ref() {
None => return fail(&ast_res.warnings, &ast_res.errors),
Some(programs) => programs,
};
let typed_program = match programs.typed.as_ref() {
None => return fail(&ast_res.warnings, &ast_res.errors),
Some(typed_program) => typed_program,
};
Expand Down Expand Up @@ -2610,7 +2571,7 @@ fn update_json_type_declaration(
}

/// Compile the entire forc package and return the lexed, parsed and typed programs
/// of the dependancies and project.
/// of the dependencies and project.
/// The final item in the returned vector is the project.
pub fn check(
plan: &BuildPlan,
Expand Down Expand Up @@ -2638,52 +2599,63 @@ pub fn check(
)
.expect("failed to create dependency namespace");

let CompileResult {
value,
mut warnings,
mut errors,
} = parse(manifest, build_target, terse_mode, include_tests, engines)?;
let profile = BuildProfile {
terse: terse_mode,
..BuildProfile::debug()
};

let (lexed, parsed) = match value {
None => {
results.push(CompileResult::new(None, warnings, errors));
let build_config = sway_build_config(
manifest.dir(),
&manifest.entry_path(),
build_target,
&profile,
)?
.include_tests(include_tests);

let mut metrics = PerformanceData::default();
let programs_res = sway_core::compile_to_ast(
engines,
manifest.entry_string()?,
dep_namespace,
Some(&build_config),
&pkg.name,
&mut metrics,
);

let programs = match programs_res.value.as_ref() {
Some(programs) => programs,
_ => {
results.push(programs_res);
return Ok(results);
}
Some(modules) => modules,
};

let ast_result = sway_core::parsed_to_ast(engines, &parsed, dep_namespace, None, &pkg.name);
warnings.extend(ast_result.warnings);
errors.extend(ast_result.errors);
match programs.typed.as_ref() {
Some(typed_program) => {
if let TreeType::Library = typed_program.kind.tree_type() {
let mut namespace = typed_program.root.namespace.clone();
namespace.name = Some(Ident::new_no_span(pkg.name.clone()));
namespace.span = Some(
Span::new(
manifest.entry_string()?,
0,
0,
Some(engines.se().get_source_id(&manifest.entry_path())),
)
.unwrap(),
);
lib_namespace_map.insert(node, namespace.module().clone());
}

let typed_program = match ast_result.value {
source_map.insert_dependency(manifest.dir());
}
None => {
let value = Some(Programs::new(lexed, parsed, None));
results.push(CompileResult::new(value, warnings, errors));
results.push(programs_res);
return Ok(results);
}
Some(typed_program) => typed_program,
};

if let TreeType::Library = typed_program.kind.tree_type() {
let mut namespace = typed_program.root.namespace.clone();
namespace.name = Some(Ident::new_no_span(pkg.name.clone()));
namespace.span = Some(
Span::new(
manifest.entry_string()?,
0,
0,
Some(engines.se().get_source_id(&manifest.entry_path())),
)
.unwrap(),
);
lib_namespace_map.insert(node, namespace.module().clone());
}

source_map.insert_dependency(manifest.dir());

let value = Some(Programs::new(lexed, parsed, Some(typed_program)));
results.push(CompileResult::new(value, warnings, errors));
results.push(programs_res)
}

if results.is_empty() {
Expand All @@ -2693,29 +2665,6 @@ pub fn check(
Ok(results)
}

/// Returns a parsed AST from the supplied [PackageManifestFile]
pub fn parse(
manifest: &PackageManifestFile,
build_target: BuildTarget,
terse_mode: bool,
include_tests: bool,
engines: &Engines,
) -> anyhow::Result<CompileResult<(LexedProgram, ParseProgram)>> {
let profile = BuildProfile {
terse: terse_mode,
..BuildProfile::debug()
};
let source = manifest.entry_string()?;
let sway_build_config = sway_build_config(
manifest.dir(),
&manifest.entry_path(),
build_target,
&profile,
)?
.include_tests(include_tests);
Ok(sway_core::parse(source, engines, Some(&sway_build_config)))
}

/// Format an error message for an absent `Forc.toml`.
pub fn manifest_file_missing(dir: &Path) -> anyhow::Error {
let message = format!(
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/language/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod lexed;
mod literal;
mod module;
pub mod parsed;
pub mod programs;
mod purity;
pub mod ty;
mod visibility;
Expand All @@ -16,5 +17,6 @@ pub use inline::*;
pub use lazy_op::*;
pub use literal::*;
pub use module::*;
pub use programs::*;
pub use purity::*;
pub use visibility::*;
18 changes: 18 additions & 0 deletions sway-core/src/language/programs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use super::{lexed::LexedProgram, parsed::ParseProgram, ty::TyProgram};

/// Contains the lexed, parsed, and typed compilation stages of a program.
pub struct Programs {
pub lexed: LexedProgram,
pub parsed: ParseProgram,
pub typed: Option<TyProgram>,
}

impl Programs {
pub fn new(lexed: LexedProgram, parsed: ParseProgram, typed: Option<TyProgram>) -> Programs {
Programs {
lexed,
parsed,
typed,
}
}
}
Loading

0 comments on commit f246d97

Please sign in to comment.