Skip to content

Commit

Permalink
Add conditional compilation by program_type (FuelLabs#4393)
Browse files Browse the repository at this point in the history
This is a followup for FuelLabs#4292 which adds the `program_type` argument for
the `cfg` attribute.

Should unblock
FuelLabs#3829 (comment)
  • Loading branch information
AlicanC authored Apr 7, 2023
1 parent a28b5eb commit f2c01fa
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 10 deletions.
8 changes: 7 additions & 1 deletion sway-core/src/language/parsed/program.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use strum::EnumString;

use super::ParseModule;

/// A parsed, but not yet type-checked, Sway program.
Expand All @@ -12,11 +14,15 @@ pub struct ParseProgram {
/// A Sway program can be either a contract, script, predicate, or a library.
///
/// All submodules declared with `dep` should be `Library`s.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, EnumString)]
pub enum TreeType {
#[strum(serialize = "predicate")]
Predicate,
#[strum(serialize = "script")]
Script,
#[strum(serialize = "contract")]
Contract,
#[strum(serialize = "library")]
Library,
}

Expand Down
7 changes: 5 additions & 2 deletions sway-core/src/transform/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use sway_ast::Literal;
use sway_types::{
constants::{ALLOW_DEAD_CODE_NAME, CFG_TARGET_ARG_NAME},
constants::{ALLOW_DEAD_CODE_NAME, CFG_PROGRAM_TYPE_ARG_NAME, CFG_TARGET_ARG_NAME},
Ident, Span, Spanned,
};

Expand Down Expand Up @@ -90,7 +90,10 @@ impl AttributeKind {
AttributeKind::Test => None,
AttributeKind::Payable => None,
AttributeKind::Allow => Some(vec![ALLOW_DEAD_CODE_NAME.to_string()]),
AttributeKind::Cfg => Some(vec![CFG_TARGET_ARG_NAME.to_string()]),
AttributeKind::Cfg => Some(vec![
CFG_TARGET_ARG_NAME.to_string(),
CFG_PROGRAM_TYPE_ARG_NAME.to_string(),
]),
}
}
}
Expand Down
15 changes: 14 additions & 1 deletion sway-core/src/transform/to_parsed_lang/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::BuildTarget;
use crate::{language::parsed::TreeType, BuildTarget};

#[derive(Default)]
pub struct Context {
Expand All @@ -16,6 +16,9 @@ pub struct Context {

/// The build target
build_target: BuildTarget,

/// The build target
program_type: Option<TreeType>,
}

impl Context {
Expand Down Expand Up @@ -60,4 +63,14 @@ impl Context {
pub fn build_target(&self) -> BuildTarget {
self.build_target
}

/// Returns the build target
pub fn program_type(&self) -> Option<TreeType> {
self.program_type.clone()
}

/// Update the value of `program_type`
pub fn set_program_type(&mut self, program_type: TreeType) {
self.program_type = Some(program_type);
}
}
47 changes: 41 additions & 6 deletions sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ use sway_error::handler::{ErrorEmitted, Handler};
use sway_error::warning::{CompileWarning, Warning};
use sway_types::{
constants::{
ALLOW_ATTRIBUTE_NAME, CFG_ATTRIBUTE_NAME, DESTRUCTURE_PREFIX, DOC_ATTRIBUTE_NAME,
DOC_COMMENT_ATTRIBUTE_NAME, INLINE_ATTRIBUTE_NAME, MATCH_RETURN_VAR_NAME_PREFIX,
PAYABLE_ATTRIBUTE_NAME, STORAGE_PURITY_ATTRIBUTE_NAME, STORAGE_PURITY_READ_NAME,
STORAGE_PURITY_WRITE_NAME, TEST_ATTRIBUTE_NAME, TUPLE_NAME_PREFIX, VALID_ATTRIBUTE_NAMES,
ALLOW_ATTRIBUTE_NAME, CFG_ATTRIBUTE_NAME, CFG_PROGRAM_TYPE_ARG_NAME, CFG_TARGET_ARG_NAME,
DESTRUCTURE_PREFIX, DOC_ATTRIBUTE_NAME, DOC_COMMENT_ATTRIBUTE_NAME, INLINE_ATTRIBUTE_NAME,
MATCH_RETURN_VAR_NAME_PREFIX, PAYABLE_ATTRIBUTE_NAME, STORAGE_PURITY_ATTRIBUTE_NAME,
STORAGE_PURITY_READ_NAME, STORAGE_PURITY_WRITE_NAME, TEST_ATTRIBUTE_NAME,
TUPLE_NAME_PREFIX, VALID_ATTRIBUTE_NAMES,
},
integer_bits::IntegerBits,
};
Expand All @@ -49,6 +50,7 @@ pub fn convert_parse_tree(
module: Module,
) -> Result<(TreeType, ParseTree), ErrorEmitted> {
let tree_type = convert_module_kind(&module.kind);
context.set_program_type(tree_type.clone());
let tree = module_to_sway_parse_tree(context, handler, engines, module)?;
Ok((tree_type, tree))
}
Expand Down Expand Up @@ -3985,8 +3987,9 @@ pub fn cfg_eval(
if let Some(cfg_attrs) = attrs_map.get(&AttributeKind::Cfg) {
for cfg_attr in cfg_attrs {
for arg in &cfg_attr.args {
dbg!(arg.name.as_str());
match arg.name.as_str() {
"target" => {
CFG_TARGET_ARG_NAME => {
if let Some(value) = &arg.value {
if let sway_ast::Literal::String(value_str) = value {
if let Ok(target) = BuildTarget::from_str(value_str.parsed.as_str())
Expand Down Expand Up @@ -4015,9 +4018,41 @@ pub fn cfg_eval(
return Err(handler.emit_err(error.into()));
}
}
CFG_PROGRAM_TYPE_ARG_NAME => {
if let Some(value) = &arg.value {
if let sway_ast::Literal::String(value_str) = value {
if let Ok(program_type) =
TreeType::from_str(value_str.parsed.as_str())
{
dbg!("kek", &program_type, &context.program_type().unwrap());
if program_type != context.program_type().unwrap() {
return Ok(false);
}
} else {
let error =
ConvertParseTreeError::InvalidCfgProgramTypeArgValue {
span: value.span(),
value: value.span().str(),
};
return Err(handler.emit_err(error.into()));
}
} else {
let error = ConvertParseTreeError::InvalidCfgProgramTypeArgValue {
span: value.span(),
value: value.span().str(),
};
return Err(handler.emit_err(error.into()));
}
} else {
let error = ConvertParseTreeError::ExpectedCfgTargetArgValue {
span: arg.span(),
};
return Err(handler.emit_err(error.into()));
}
}
_ => {
// Already checked with `AttributeKind::expected_args_*`
unreachable!("cfg attribute should only have the target argument");
unreachable!("cfg attribute should only have the `target` or the `program_type` argument");
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions sway-error/src/convert_parse_tree_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ pub enum ConvertParseTreeError {
InvalidCfgTargetArgValue { span: Span, value: String },
#[error("Expected a value for the target argument")]
ExpectedCfgTargetArgValue { span: Span },
#[error("Invalid value \"{value}\"")]
InvalidCfgProgramTypeArgValue { span: Span, value: String },
#[error("Expected a value for the program_type argument")]
ExpectedCfgProgramTypeArgValue { span: Span },
}

impl Spanned for ConvertParseTreeError {
Expand Down Expand Up @@ -176,6 +180,8 @@ impl Spanned for ConvertParseTreeError {
ConvertParseTreeError::ConstantRequiresTypeAscription { span } => span.clone(),
ConvertParseTreeError::InvalidCfgTargetArgValue { span, .. } => span.clone(),
ConvertParseTreeError::ExpectedCfgTargetArgValue { span } => span.clone(),
ConvertParseTreeError::InvalidCfgProgramTypeArgValue { span, .. } => span.clone(),
ConvertParseTreeError::ExpectedCfgProgramTypeArgValue { span } => span.clone(),
}
}
}
1 change: 1 addition & 0 deletions sway-types/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub const ALLOW_DEAD_CODE_NAME: &str = "dead_code";
/// The valid attribute strings related to conditional compilation.
pub const CFG_ATTRIBUTE_NAME: &str = "cfg";
pub const CFG_TARGET_ARG_NAME: &str = "target";
pub const CFG_PROGRAM_TYPE_ARG_NAME: &str = "program_type";

/// The list of valid attributes.
pub const VALID_ATTRIBUTE_NAMES: &[&str] = &[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'conditional_compilation_bad_program_type'
source = 'member'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
implicit-std = false
license = "Apache-2.0"
name = "conditional_compilation_bad_program_type"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
script;

#[cfg(program_type = "scriptz")]
fn main() {
()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
category = "fail"

# check: $()#[cfg(program_type = "scriptz")]
# nextln: $()Invalid value ""scriptz""
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[package]]
name = 'conditional_compilation_mismatching_program_type'
source = 'member'
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
implicit-std = false
license = "Apache-2.0"
name = "conditional_compilation_mismatching_program_type"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
script;

#[cfg(program_type = "predicate")]
fn foo() {
()
}

fn main() {
foo()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
category = "fail"

# check: $()foo()
# nextln: $()Could not find symbol "foo" in this scope.
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
script;

// These baddies should not be compiled
#[cfg(program_type = "predicate")]
const VALUE: str[3] = "bad";
#[cfg(program_type = "contract")]
const VALUE: str[3] = "bad";
#[cfg(program_type = "library")]
const VALUE: str[3] = "bad";

configurable {
// Only compiles for FVM
#[cfg(target = "fuel")]
Expand All @@ -13,10 +21,13 @@ configurable {
CFG_VALUE: () = (),
}

#[cfg(program_type = "script")]
#[cfg(target = "fuel")]
const VALUE: u64 = 40;
#[cfg(program_type = "script")]
#[cfg(target = "evm")]
const VALUE: () = ();
#[cfg(program_type = "script")]
#[cfg(target = "fuel")]
#[cfg(target = "evm")]
const VALUE: () = ();
Expand Down

0 comments on commit f2c01fa

Please sign in to comment.