Skip to content

Commit

Permalink
Support parsing all variants of ByStr including ByStr20 with (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
saeed-zil authored Nov 13, 2024
1 parent c29cfae commit 7384a40
Show file tree
Hide file tree
Showing 6 changed files with 430 additions and 130 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,28 +52,28 @@ Here is the code to parse [SendZil.scilla](./tests/contracts/SendZil.scilla) con
Transition::new(
"fundUserWithTag",
FieldList(vec![
Field::new("user", Type::ByStr(20)),
Field::new("user", Type::ByStr20),
Field::new("amount", Type::Uint128)
])
),
Transition::new(
"fundUser",
FieldList(vec![
Field::new("user", Type::ByStr(20)),
Field::new("user", Type::ByStr20),
Field::new("amount", Type::Uint128)
])
),
Transition::new(
"fundContract",
FieldList(vec![
Field::new("contract_address", Type::ByStr(20)),
Field::new("contract_address", Type::ByStr20),
Field::new("amount", Type::Uint128)
])
),
Transition::new(
"callOtherContract",
FieldList(vec![
Field::new("contract_address", Type::ByStr(20)),
Field::new("contract_address", Type::ByStr20),
Field::new("tag", Type::String),
Field::new("value", Type::Uint256)
])
Expand Down
32 changes: 28 additions & 4 deletions src/simplified_representation/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ impl AstConverting for SrEmitter {
let map = SrType {
main_type: "Map".to_string(),
sub_types: vec![key.into(), value.into()],
address_type: None,
};
self.stack.push(StackObject::TypeDefinition(map));
}
Expand All @@ -190,6 +191,7 @@ impl AstConverting for SrEmitter {
let map = SrType {
main_type: "Map".to_string(),
sub_types: vec![key.into(), value],
address_type: None,
};
self.stack.push(StackObject::TypeDefinition(map));
}
Expand Down Expand Up @@ -282,16 +284,38 @@ impl AstConverting for SrEmitter {
fn emit_address_type_field(
&mut self,
_mode: TreeTraversalMode,
_node: &NodeAddressTypeField,
node: &NodeAddressTypeField,
) -> Result<TraversalResult, String> {
Ok(TraversalResult::Continue)
if let NodeVariableIdentifier::VariableName(n) = &node.identifier.node {
node.type_name.visit(self)?;
let typename = self.pop_type_definition()?;
let s = StackObject::VariableDeclaration(Field::new(&n.node, typename.into()));
self.stack.push(s);
}
Ok(TraversalResult::SkipChildren)
}
fn emit_address_type(
&mut self,
_mode: TreeTraversalMode,
_node: &NodeAddressType,
node: &NodeAddressType,
) -> Result<TraversalResult, String> {
Ok(TraversalResult::Continue)
node.identifier.visit(self)?;
let identifier = self.pop_ir_identifier()?;
self.stack
.push(StackObject::TypeDefinition(identifier.into()));
let mut main_type = self.pop_type_definition()?;
let mut fields = vec![];
for field in &node.address_fields {
field.visit(self)?;
let field = self.pop_variable_declaration()?;
fields.push(field);
}
main_type.address_type = Some(AddressType {
type_name: node.type_name.node.clone(),
fields: FieldList(fields),
});
self.stack.push(StackObject::TypeDefinition(main_type));
Ok(TraversalResult::SkipChildren)
}

fn emit_full_expression(
Expand Down
10 changes: 10 additions & 0 deletions src/simplified_representation/primitives.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::FieldList;

/// Enum representing the different kinds of identifiers in the simplified representation.
#[derive(Debug, Clone, PartialEq)]
pub enum SrIdentifierKind {
Expand Down Expand Up @@ -36,10 +38,17 @@ pub struct SrIdentifier {
pub is_definition: bool,
}

#[derive(Debug, Clone)]
pub struct AddressType {
pub type_name: String,
pub fields: FieldList,
}

#[derive(Debug, Clone)]
pub struct SrType {
pub main_type: String,
pub sub_types: Vec<SrType>,
pub address_type: Option<AddressType>, // For types like `ByStr20 with contract field f1 : t1, field f2 : t2, ... end`
}

impl SrType {
Expand All @@ -53,6 +62,7 @@ impl From<SrIdentifier> for SrType {
Self {
main_type: value.unresolved,
sub_types: vec![],
address_type: None,
}
}
}
Expand Down
50 changes: 42 additions & 8 deletions src/type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt::Display;

use crate::simplified_representation::primitives::SrType;
use crate::{simplified_representation::primitives::SrType, FieldList};

/// Represents all different scilla types.
#[derive(Debug, PartialEq, Clone)]
Expand All @@ -20,7 +20,14 @@ pub enum Type {
BNum,
Map(Box<Type>, Box<Type>),

ByStr(usize),
ByStr,
ByStrX(usize),
ByStr20,
/// See https://scilla.readthedocs.io/en/latest/scilla-in-depth.html#addresses-1
ByStr20With {
type_name: String, // contract, library, ...
fields: FieldList,
},

// ADT
Bool,
Expand Down Expand Up @@ -49,7 +56,17 @@ impl Display for Type {
Type::Option(ref k) => write!(f, "(Option {})", k),
Type::List(ref k) => write!(f, "(List {})", k),
Type::Pair(ref k, ref v) => write!(f, "(Pair {} {})", k, v),
Type::ByStr(n) => write!(f, "ByStr{}", n),
Type::ByStr => write!(f, "ByStr"),
Type::ByStrX(n) => write!(f, "ByStr{}", n),
Type::ByStr20 => write!(f, "ByStr20"),
Type::ByStr20With { type_name, fields } => {
let fields = fields
.iter()
.map(|field| format!("field {}: {}", field.name, field.r#type))
.collect::<Vec<String>>()
.join(", ");
write!(f, "ByStr20 with {type_name}{fields} end")
}
Type::Other(ref s) => write!(f, "{}", s),
}
}
Expand All @@ -67,7 +84,8 @@ impl From<SrType> for Type {
"Uint128" => Type::Uint128,
"Uint256" => Type::Uint256,
"String" => Type::String,
"ByStr20" => Type::ByStr(20),
"ByStr" => Type::ByStr,
"ByStrX" => todo!(),
"BNum" => Type::BNum,
"Bool" => Type::Bool,
// TODO: Remove unwrap
Expand All @@ -83,6 +101,22 @@ impl From<SrType> for Type {
let key = type_definition.sub_types.pop().unwrap();
Type::Map(Box::new(key.into()), Box::new(value.into()))
}
"ByStr20" => type_definition
.address_type
.map_or(Type::ByStr20, |address_type| Type::ByStr20With {
type_name: address_type.type_name,
fields: address_type.fields,
}),
t if t.starts_with("ByStr") => {
if let Some(number) = t
.strip_prefix("ByStr")
.and_then(|s| s.parse::<usize>().ok())
{
Type::ByStrX(number)
} else {
Type::Other(type_definition.main_type)
}
}
_ => Type::Other(type_definition.main_type),
}
}
Expand All @@ -96,9 +130,9 @@ mod tests {
fn test_type_to_string() {
//(List (Pair ByStr20 (List (Pair ByStr20 Uint32))))
let list_type = Type::List(Box::new(Type::Pair(
Box::new(Type::ByStr(20)),
Box::new(Type::ByStrX(20)),
Box::new(Type::List(Box::new(Type::Pair(
Box::new(Type::ByStr(20)),
Box::new(Type::ByStrX(20)),
Box::new(Type::Uint32),
)))),
)));
Expand All @@ -110,9 +144,9 @@ mod tests {

// (List (Pair ByStr20 (List (Pair ByStr20 (List (Pair Uint32 Uint128))))))
let list_type = Type::List(Box::new(Type::Pair(
Box::new(Type::ByStr(20)),
Box::new(Type::ByStrX(20)),
Box::new(Type::List(Box::new(Type::Pair(
Box::new(Type::ByStr(20)),
Box::new(Type::ByStrX(20)),
Box::new(Type::List(Box::new(Type::Pair(
Box::new(Type::Uint32),
Box::new(Type::Uint128),
Expand Down
15 changes: 15 additions & 0 deletions tests/contracts/ByStr.scilla
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
scilla_version 0

contract AllByStrVariants
(
bystr32 : ByStr32,
raw_address: ByStr20,
library_address : ByStr20 with library end,
contract_address : ByStr20 with contract end,
detailed_contract_address :
ByStr20 with contract
field allowances : Map ByStr20 (Map ByStr20 Uint128),
field balances : Map ByStr20 Uint128,
field total_supply : Uint128
end
)
Loading

0 comments on commit 7384a40

Please sign in to comment.