Skip to content

Commit

Permalink
feat(soroban): Soroban storage types
Browse files Browse the repository at this point in the history
Signed-off-by: salaheldinsoliman <[email protected]>
  • Loading branch information
salaheldinsoliman committed Sep 19, 2024
1 parent 420fbb8 commit 9a9733a
Show file tree
Hide file tree
Showing 29 changed files with 288 additions and 43 deletions.
9 changes: 8 additions & 1 deletion fmt/src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
};
use alloy_primitives::Address;
use itertools::{Either, Itertools};
use solang_parser::pt::{PragmaDirective, VersionComparator};
use solang_parser::pt::{PragmaDirective, StorageType, VersionComparator};
use std::{fmt::Write, str::FromStr};
use thiserror::Error;

Expand Down Expand Up @@ -3333,6 +3333,13 @@ impl<'a, W: Write> Visitor for Formatter<'a, W> {
self.visit_list("", idents, Some(loc.start()), Some(loc.end()), false)?;
None
}
VariableAttribute::StorageType(s) => {
match s {
StorageType::Instance(_) => Some("instance".to_string()),
StorageType::Temporary(_) => Some("temporary".to_string()),
StorageType::Persistent(_) => Some("persistent".to_string()),
}
}
};
if let Some(token) = token {
let loc = attribute.loc();
Expand Down
13 changes: 13 additions & 0 deletions fmt/src/solang_ext/ast_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ impl AstEq for VariableDefinition {
}
}

impl AstEq for StorageType {
fn ast_eq(&self, other: &Self) -> bool {
match (self, other) {
(StorageType::Instance(_), StorageType::Instance(_)) => true,
(StorageType::Persistent(_), StorageType::Persistent(_)) => true,
(StorageType::Temporary(_), StorageType::Temporary(_)) => true,
_ => false,

}
}
}

impl AstEq for FunctionDefinition {
fn ast_eq(&self, other: &Self) -> bool {
// attributes
Expand Down Expand Up @@ -726,5 +738,6 @@ derive_ast_eq! { enum VariableAttribute {
Constant(loc),
Immutable(loc),
Override(loc, idents),
StorageType(s)
_
}}
9 changes: 8 additions & 1 deletion solang-parser/src/helpers/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//!
//! [ref]: https://docs.soliditylang.org/en/latest/style-guide.html

use crate::pt;
use crate::pt::{self, StorageType};
use std::{
borrow::Cow,
fmt::{Display, Formatter, Result, Write},
Expand Down Expand Up @@ -1169,6 +1169,13 @@ impl Display for pt::VariableAttribute {
}
Ok(())
}
Self::StorageType(storage) => {
match storage {
StorageType::Instance(_) => f.write_str("instance"),
StorageType::Temporary(_) => f.write_str("temporary"),
StorageType::Persistent(_) => f.write_str("persistent"),
}
}
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions solang-parser/src/helpers/loc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ impl OptionalCodeLocation for pt::Visibility {
}
}

impl OptionalCodeLocation for pt::StorageType {
fn loc_opt(&self) -> Option<Loc> {
match self {
Self::Persistent(l) | Self::Temporary(l) | Self::Instance(l) => *l,
}
}
}

impl OptionalCodeLocation for pt::SourceUnit {
#[inline]
fn loc_opt(&self) -> Option<Loc> {
Expand Down Expand Up @@ -431,6 +439,7 @@ impl_for_enums! {

pt::VariableAttribute: match self {
Self::Visibility(ref l, ..) => l.loc_opt().unwrap_or_default(),
Self::StorageType(ref l, ..) => l.loc_opt().unwrap_or_default(),
Self::Constant(l, ..)
| Self::Immutable(l, ..)
| Self::Override(l, ..) => l,
Expand Down
11 changes: 11 additions & 0 deletions solang-parser/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ pub enum Token<'input> {
Default,
YulArrow,

// Storage types for Soroban
Persistent,
Temporary,
Instance,

Annotation(&'input str),
}

Expand Down Expand Up @@ -316,6 +321,9 @@ impl<'input> fmt::Display for Token<'input> {
Token::Default => write!(f, "default"),
Token::YulArrow => write!(f, "->"),
Token::Annotation(name) => write!(f, "@{name}"),
Token::Persistent => write!(f, "persistent"),
Token::Temporary => write!(f, "temporary"),
Token::Instance => write!(f, "instance"),
}
}
}
Expand Down Expand Up @@ -553,6 +561,9 @@ static KEYWORDS: phf::Map<&'static str, Token> = phf_map! {
"unchecked" => Token::Unchecked,
"assembly" => Token::Assembly,
"let" => Token::Let,
"persistent" => Token::Persistent,
"temporary" => Token::Temporary,
"instance" => Token::Instance,
};

impl<'input> Lexer<'input> {
Expand Down
18 changes: 18 additions & 0 deletions solang-parser/src/pt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,24 @@ pub enum VariableAttribute {

/// `ovveride(<1>,*)`
Override(Loc, Vec<IdentifierPath>),

/// Storage type.
StorageType(StorageType),
}

/// Soroban storage types.
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "pt-serde", derive(Serialize, Deserialize))]
#[repr(u8)] // for cmp; order of variants is important
pub enum StorageType {
/// `persistent`
Persistent(Option<Loc>),

/// `Instance`
Instance(Option<Loc>),

/// `Temporary`
Temporary(Option<Loc>),
}

/// A variable definition.
Expand Down
10 changes: 10 additions & 0 deletions solang-parser/src/solidity.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,15 @@ Visibility: Visibility = {
<l:@L> "private" <r:@R> => Visibility::Private(Some(Loc::File(file_no, l, r))),
}

StorageType: StorageType = {
<l:@L> "persistent" <r:@R> => StorageType::Persistent(Some(Loc::File(file_no, l, r))),
<l:@R> "temporary" <r:@R> => StorageType::Temporary(Some(Loc::File(file_no, l, r))),
<l:@R> "instance" <r:@R> => StorageType::Instance(Some(Loc::File(file_no, l, r))),
}

VariableAttribute: VariableAttribute = {
Visibility => VariableAttribute::Visibility(<>),
StorageType => VariableAttribute::StorageType(<>),
<l:@L> "constant" <r:@R> => VariableAttribute::Constant(Loc::File(file_no, l, r)),
<l:@L> "immutable" <r:@R> => VariableAttribute::Immutable(Loc::File(file_no, l, r)),
<l:@L> "override" <r:@R> => VariableAttribute::Override(Loc::File(file_no, l, r), Vec::new()),
Expand Down Expand Up @@ -1312,5 +1319,8 @@ extern {
"switch" => Token::Switch,
"case" => Token::Case,
"default" => Token::Default,
"persistent" => Token::Persistent,
"temporary" => Token::Temporary,
"instance" => Token::Instance,
}
}
16 changes: 16 additions & 0 deletions solang-parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ contract 9c {
}
}

#[test]
fn parse_storage_type() {
let src = r#"contract counter {
uint64 instance count = 1;
function decrement() public returns (uint64){
//count -= 1;
return count;
}
}"#;

let res = crate::parse(src, 0);

println!("{:?}", res);
}

#[test]
fn parse_test() {
let src = r#"/// @title Foo
Expand Down
6 changes: 4 additions & 2 deletions src/codegen/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub enum Instr {
res: usize,
ty: Type,
storage: Expression,
storage_type: Option<pt::StorageType>,
},
/// Clear storage at slot for ty (might span multiple slots)
ClearStorage { ty: Type, storage: Expression },
Expand All @@ -78,6 +79,7 @@ pub enum Instr {
ty: Type,
value: Expression,
storage: Expression,
storage_type: Option<pt::StorageType>,
},
/// In storage slot, set the value at the offset
SetStorageBytes {
Expand Down Expand Up @@ -1027,7 +1029,7 @@ impl ControlFlowGraph {
true_block,
false_block,
),
Instr::LoadStorage { ty, res, storage } => format!(
Instr::LoadStorage { ty, res, storage, .. } => format!(
"%{} = load storage slot({}) ty:{}",
self.vars[res].id.name,
self.expr_to_string(contract, ns, storage),
Expand All @@ -1038,7 +1040,7 @@ impl ControlFlowGraph {
self.expr_to_string(contract, ns, storage),
ty.to_string(ns),
),
Instr::SetStorage { ty, value, storage } => format!(
Instr::SetStorage { ty, value, storage, .. } => format!(
"store storage slot({}) ty:{} = {}",
self.expr_to_string(contract, ns, storage),
ty.to_string(ns),
Expand Down
11 changes: 9 additions & 2 deletions src/codegen/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,12 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
};
}
}
Instr::SetStorage { ty, storage, value } => {
Instr::SetStorage {
ty,
storage,
value,
storage_type,
} => {
let (storage, _) = expression(storage, Some(&vars), cfg, ns);
let (value, _) = expression(value, Some(&vars), cfg, ns);

Expand All @@ -138,17 +143,19 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
ty: ty.clone(),
storage,
value,
storage_type: storage_type.clone(),
};
}
}
Instr::LoadStorage { ty, storage, res } => {
Instr::LoadStorage { ty, storage, res, storage_type } => {
let (storage, _) = expression(storage, Some(&vars), cfg, ns);

if !dry_run {
cfg.blocks[block_no].instr[instr_no] = Instr::LoadStorage {
ty: ty.clone(),
storage,
res: *res,
storage_type: storage_type.clone(),
};
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/dead_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ pub fn dead_storage(cfg: &mut ControlFlowGraph, _ns: &mut Namespace) {
let vars = &block_vars[&block_no][instr_no];

match &cfg.blocks[block_no].instr[instr_no] {
Instr::LoadStorage { res, ty, storage } => {
Instr::LoadStorage { res, ty, storage, .. } => {
// is there a definition which has the same storage expression
let mut found = None;

Expand Down
1 change: 1 addition & 0 deletions src/codegen/dispatch/solana.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ fn check_magic(magic_value: u32, cfg: &mut ControlFlowGraph, vartab: &mut Vartab
ty: Type::Uint(32),
value: 0.into(),
},
storage_type: None,
},
);

Expand Down
4 changes: 3 additions & 1 deletion src/codegen/encoding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ fn calculate_size_args(
vartab: &mut Vartable,
cfg: &mut ControlFlowGraph,
) -> Expression {
println!("calculate_size_args");
let mut size = encoder.get_expr_size(0, &args[0], ns, vartab, cfg);
for (i, item) in args.iter().enumerate().skip(1) {
let additional = encoder.get_expr_size(i, item, ns, vartab, cfg);
Expand Down Expand Up @@ -1422,7 +1423,8 @@ pub(crate) trait AbiEncoding {
self.get_expr_size(arg_no, &loaded, ns, vartab, cfg)
}
Type::StorageRef(_, r) => {
let var = load_storage(&Codegen, r, expr.clone(), cfg, vartab);
println!("EH DAH BA@A A&A");
let var = load_storage(&Codegen, r, expr.clone(), cfg, vartab, None);
let size = self.get_expr_size(arg_no, &var, ns, vartab, cfg);
self.storage_cache_insert(arg_no, var.clone());
size
Expand Down
Loading

0 comments on commit 9a9733a

Please sign in to comment.