Skip to content

Commit

Permalink
parse storage declarations (FuelLabs#439)
Browse files Browse the repository at this point in the history
  • Loading branch information
sezna authored Dec 7, 2021
1 parent d1a4e9c commit e467795
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 15 deletions.
6 changes: 5 additions & 1 deletion core_lang/src/hll.pest
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var_decl_keyword = {"let"}
fn_decl_keyword = {"fn"}
trait_decl_keyword = {"trait"}
return_keyword = {"return"}
storage_keyword = {"storage"}
use_keyword = {"use"}
as_keyword = {"as"}
enum_keyword = @{"enum"}
Expand Down Expand Up @@ -108,7 +109,7 @@ array_elems = {literal_value ~ ";" ~ u64_integer|expr ~ ("," ~ expr)*}

// declarations
declaration = {(non_var_decl|var_decl|reassignment)}
non_var_decl = {(enum_decl|fn_decl|trait_decl|abi_decl|struct_decl|impl_trait|impl_self|const_decl)}
non_var_decl = {(enum_decl|storage_decl|fn_decl|trait_decl|abi_decl|struct_decl|impl_trait|impl_self|const_decl)}
var_decl = {var_decl_keyword ~ mut_keyword? ~ var_name ~ type_ascription? ~ assign ~ expr ~ ";"}
type_ascription = {":" ~ type_name}
fn_decl = {visibility ~ fn_signature ~ code_block}
Expand All @@ -122,6 +123,9 @@ const_decl = {visibility ~ const_decl_keyword ~ var_name ~ type_
visibility = {"pub"?}

struct_decl = {visibility ~ struct_keyword ~ struct_name ~ type_params? ~ trait_bounds? ~ "{" ~ struct_fields ~ "}"}
storage_decl = {storage_keyword ~ "{" ~ storage_fields ~ "}"}
storage_fields = {storage_field ~ ("," ~ storage_field)* ~ ","?}
storage_field = {ident ~ ":" ~ type_name ~ assign ~ expr}
struct_name = {ident}
struct_fields = {struct_field_name ~ ":" ~ type_name ~ ("," ~ struct_field_name ~ ":" ~ type_name)* ~ ","?}
struct_field_name = {ident}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
mod abi_declaration;
mod constant_declaration;
mod enum_declaration;
pub mod function_declaration;
mod abi;
mod constant;
mod r#enum;
pub mod function;
mod impl_trait;
mod reassignment;
mod struct_declaration;
mod trait_declaration;
mod storage;
mod r#struct;
mod r#trait;
mod type_parameter;
mod variable_declaration;
mod variable;

pub(crate) use abi_declaration::*;
pub(crate) use constant_declaration::*;
pub(crate) use enum_declaration::*;
pub use function_declaration::*;
pub(crate) use abi::*;
pub(crate) use constant::*;
pub use function::*;
pub(crate) use impl_trait::*;
pub(crate) use r#enum::*;
pub use r#struct::*;
pub use r#trait::*;
pub(crate) use reassignment::*;
pub use struct_declaration::*;
pub use trait_declaration::*;
pub use storage::*;
pub(crate) use type_parameter::*;
pub use variable_declaration::*;
pub use variable::*;

use crate::build_config::BuildConfig;
use crate::error::*;
Expand All @@ -38,6 +40,7 @@ pub enum Declaration<'sc> {
ImplSelf(ImplSelf<'sc>),
AbiDeclaration(AbiDeclaration<'sc>),
ConstantDeclaration(ConstantDeclaration<'sc>),
StorageDeclaration(StorageDeclaration<'sc>),
}
impl<'sc> Declaration<'sc> {
pub(crate) fn parse_non_var_from_pair(
Expand Down Expand Up @@ -115,6 +118,12 @@ impl<'sc> Declaration<'sc> {
warnings,
errors
)),
Rule::storage_decl => Declaration::StorageDeclaration(check!(
StorageDeclaration::parse_from_pair(decl_inner, config),
return err(warnings, errors),
warnings,
errors
)),
a => unreachable!("declarations don't have any other sub-types: {:?}", a),
};
ok(parsed_declaration, warnings, errors)
Expand Down
File renamed without changes.
99 changes: 99 additions & 0 deletions core_lang/src/parse_tree/declaration/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use crate::{
error::*, ident::Ident, parse_tree::Expression, parser::Rule, type_engine::*, BuildConfig, Span,
};
use pest::iterators::Pair;

#[derive(Debug, Clone)]
/// A declaration of contract storage. Only valid within contract contexts.
/// All values in this struct are mutable and persistent among executions of the same contract deployment.
pub struct StorageDeclaration<'sc> {
pub fields: Vec<StorageField<'sc>>,
pub span: Span<'sc>,
}

/// An individual field in a storage declaration.
/// A type annotation _and_ initializer value must be provided. The initializer value must be a
/// constant expression. For now, that basically means just a literal, but as constant folding
/// improves, we can update that.
#[derive(Debug, Clone)]
pub struct StorageField<'sc> {
pub name: Ident<'sc>,
pub r#type: TypeInfo,
pub initializer: Expression<'sc>,
}

impl<'sc> StorageField<'sc> {
pub(crate) fn parse_from_pair(
pair: Pair<'sc, Rule>,
conf: Option<&BuildConfig>,
) -> CompileResult<'sc, Self> {
let mut errors = vec![];
let mut warnings = vec![];
let mut iter = pair.into_inner();
let name = iter.next().expect("guaranteed by grammar");
let r#type = iter.next().expect("guaranteed by grammar");
let initializer = iter.next().expect("guaranteed by grammar");

let name = check!(
Ident::parse_from_pair(name, conf),
return err(warnings, errors),
warnings,
errors
);
let r#type = check!(
TypeInfo::parse_from_pair(r#type, conf),
return err(warnings, errors),
warnings,
errors
);
let initializer = check!(
Expression::parse_from_pair(initializer, conf),
return err(warnings, errors),
warnings,
errors
);
ok(
StorageField {
name,
r#type,
initializer,
},
warnings,
errors,
)
}
}

impl<'sc> StorageDeclaration<'sc> {
pub(crate) fn parse_from_pair(
pair: Pair<'sc, Rule>,
config: Option<&BuildConfig>,
) -> CompileResult<'sc, Self> {
debug_assert_eq!(pair.as_rule(), Rule::storage_decl);
let path = config.map(|c| c.path());
let mut errors = vec![];
let mut warnings = vec![];
let span = Span {
span: pair.as_span(),
path,
};
let mut iter = pair.into_inner();
let storage_keyword = iter.next();
debug_assert_eq!(
storage_keyword.map(|x| x.as_rule()),
Some(Rule::storage_keyword)
);
let fields_results: Vec<CompileResult<'sc, StorageField>> = iter
.next()
.unwrap()
.into_inner()
.map(|x| StorageField::parse_from_pair(x, config))
.collect();
let mut fields: Vec<StorageField> = Vec::with_capacity(fields_results.len());
for res in fields_results {
let ok = check!(res, continue, warnings, errors);
fields.push(ok);
}
ok(StorageDeclaration { fields, span }, warnings, errors)
}
}
7 changes: 7 additions & 0 deletions core_lang/src/semantic_analysis/ast_node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,13 @@ impl<'sc> TypedAstNode<'sc> {
namespace.inner.insert(name, decl.clone());
decl
}
Declaration::StorageDeclaration(StorageDeclaration { span, .. }) => {
errors.push(CompileError::Unimplemented(
"Storage declarations are not supported yet. Coming soon!",
span.clone(),
));
return err(warnings, errors);
}
})
}
AstNodeContent::Expression(a) => {
Expand Down
15 changes: 15 additions & 0 deletions core_lang/src/semantic_analysis/node_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,19 @@ impl<'sc> Dependencies<'sc> {
.gather_from_iter(methods.iter(), |deps, fn_decl| {
deps.gather_from_fn_decl(fn_decl)
}),
Declaration::StorageDeclaration(StorageDeclaration { fields, .. }) => self
.gather_from_iter(
fields.iter(),
|deps,
StorageField {
r#type,
initializer,
..
}| {
deps.gather_from_typeinfo(r#type)
.gather_from_expr(initializer)
},
),
}
}

Expand Down Expand Up @@ -559,6 +572,8 @@ fn decl_name<'sc>(decl: &Declaration<'sc>) -> Option<DependentSymbol<'sc>> {
// These don't have declaration dependencies.
Declaration::VariableDeclaration(_) => None,
Declaration::Reassignment(_) => None,
// Storage cannot be depended upon or exported
Declaration::StorageDeclaration(_) => None,
}
}

Expand Down

0 comments on commit e467795

Please sign in to comment.