Skip to content

Commit

Permalink
feat: 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 12, 2024
1 parent 06798cd commit 230019e
Show file tree
Hide file tree
Showing 28 changed files with 252 additions and 35 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
4 changes: 3 additions & 1 deletion 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 @@ -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
8 changes: 7 additions & 1 deletion 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,6 +143,7 @@ pub fn constant_folding(cfg: &mut ControlFlowGraph, dry_run: bool, ns: &mut Name
ty: ty.clone(),
storage,
value,
storage_type: storage_type.clone(),
};
}
}
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
52 changes: 52 additions & 0 deletions src/codegen/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,21 @@ fn post_incdec(
},
);

let mut storage_type = None;
if let ast::Expression::StorageVariable {
loc: _,
ty: _,
var_no,
contract_no,
} = var
{
let var = ns.contracts[*contract_no].variables.get(*var_no).unwrap();

storage_type = var.storage_type.clone();

println!("storage_type {:?}", var);
}

match var.ty() {
Type::StorageRef(..) => {
cfg.add(
Expand All @@ -1298,6 +1313,7 @@ fn post_incdec(
},
ty: ty.clone(),
storage: dest,
storage_type,
},
);
}
Expand Down Expand Up @@ -1379,6 +1395,23 @@ fn pre_incdec(
expr,
},
);


let mut storage_type = None;
if let ast::Expression::StorageVariable {
loc: _,
ty: _,
var_no,
contract_no,
} = var
{
let var = ns.contracts[*contract_no].variables.get(*var_no).unwrap();

storage_type = var.storage_type.clone();

println!("storage_type {:?}", var);
}

match var {
ast::Expression::Variable { loc, var_no, .. } => {
cfg.add(
Expand Down Expand Up @@ -1409,6 +1442,7 @@ fn pre_incdec(
},
ty: ty.clone(),
storage: dest,
storage_type
},
);
}
Expand Down Expand Up @@ -2660,6 +2694,23 @@ pub fn assign_single(
},
);



let mut storage_type = None;
if let ast::Expression::StorageVariable {
loc: _,
ty: _,
var_no,
contract_no,
} = left
{
let var = ns.contracts[*contract_no].variables.get(*var_no).unwrap();

storage_type = var.storage_type.clone();

println!("storage_type {:?}", var);
}

match left_ty {
Type::StorageRef(..) if set_storage_bytes => {
if let Expression::Subscript {
Expand Down Expand Up @@ -2694,6 +2745,7 @@ pub fn assign_single(
},
ty: ty.deref_any().clone(),
storage: dest,
storage_type
},
);
}
Expand Down
1 change: 1 addition & 0 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ fn storage_initializer(contract_no: usize, ns: &mut Namespace, opt: &Options) ->
value,
ty: var.ty.clone(),
storage,
storage_type: var.storage_type.clone(),
},
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/polkadot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl RetCodeCheckBuilder<usize> {

impl RetCodeCheck {
/// Handles all cases from the [RetBlock] accordingly.
/// * On success, nothing is done and the execution continues at the success block.
/// On success, nothing is done and the execution continues at the success block.
/// If the callee reverted and output was supplied, it will be bubble up.
/// Otherwise, a revert without data will be inserted.
pub(crate) fn handle_cases(
Expand Down
2 changes: 2 additions & 0 deletions src/codegen/solana_deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ pub(super) fn solana_deploy(
ty: Type::Uint(64),
value: BigInt::zero(),
},
storage_type: None,
},
);

Expand All @@ -663,6 +664,7 @@ pub(super) fn solana_deploy(
ty: Type::Uint(64),
value: BigInt::from(12),
},
storage_type: None,
},
);
}
Loading

0 comments on commit 230019e

Please sign in to comment.