Skip to content

Commit 2fe647d

Browse files
committed
Add support for custom types; implement struct and enum handling in AST
1 parent ec232d5 commit 2fe647d

File tree

9 files changed

+156
-43
lines changed

9 files changed

+156
-43
lines changed

sdk/src/ast/build.rs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,74 @@
33
use std::{cell::RefCell, rc::Rc};
44

55
use quote::ToTokens;
6+
use syn::{ItemEnum, ItemStruct};
67
use uuid::Uuid;
78

89
use crate::{location, Codebase, OpenState};
910

1011
use super::{
12+
contract::Contract,
13+
custom_type::{CustomType, EnumType, StructType, Type},
1114
expression::{
1215
Array, Assign, BinEx, Binary, Break, Cast, ConstBlock, EBlock, Expression, FunctionCall,
1316
Identifier, MemberAccess, MethodCall, Reference,
1417
},
15-
inner_type::Type,
1618
statement::{Block, Statement},
1719
};
1820

21+
pub(crate) fn build_contract(struct_item: &ItemStruct) -> Rc<Contract> {
22+
let mut fields = Vec::new();
23+
for field in &struct_item.fields {
24+
let field_name = match &field.ident {
25+
Some(ident) => ident.to_string(),
26+
None => "unnamed".to_string(),
27+
};
28+
let field_type = Type::T(field.ty.to_token_stream().to_string());
29+
fields.push((field_name, field_type));
30+
}
31+
Rc::new(Contract {
32+
id: Uuid::new_v4().as_u128(),
33+
location: location!(struct_item),
34+
name: Contract::contract_name_from_syn_item(struct_item),
35+
fields,
36+
children: RefCell::new(Vec::new()),
37+
})
38+
}
39+
40+
pub(crate) fn build_struct_custom_type(struct_item: &ItemStruct) -> CustomType {
41+
let mut fields = Vec::new();
42+
for field in &struct_item.fields {
43+
let field_name = match &field.ident {
44+
Some(ident) => ident.to_string(),
45+
None => "unnamed".to_string(),
46+
};
47+
let field_type = Type::T(field.ty.to_token_stream().to_string());
48+
fields.push((field_name, field_type));
49+
}
50+
CustomType::Struct(Rc::new(StructType {
51+
id: Uuid::new_v4().as_u128(),
52+
location: location!(struct_item),
53+
name: struct_item.ident.to_string(),
54+
fields,
55+
children: RefCell::new(Vec::new()),
56+
}))
57+
}
58+
59+
pub(crate) fn build_enum_custom_type(enum_item: &ItemEnum) -> CustomType {
60+
let mut variants = Vec::new();
61+
for variant in &enum_item.variants {
62+
let variant_name = variant.ident.to_string();
63+
variants.push(variant_name);
64+
}
65+
CustomType::Enum(Rc::new(EnumType {
66+
id: Uuid::new_v4().as_u128(),
67+
location: location!(enum_item),
68+
name: enum_item.ident.to_string(),
69+
variants,
70+
children: RefCell::new(Vec::new()),
71+
}))
72+
}
73+
1974
pub(crate) fn build_array_expression(
2075
codebase: &mut Codebase<OpenState>,
2176
array_expr: &syn::ExprArray,

sdk/src/ast/contract.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![warn(clippy::pedantic)]
2+
use super::custom_type::Type;
23
use super::function::Function;
34
use super::node::{Location, Node, TLocation};
45
use super::node_type::ContractChildType;
@@ -13,6 +14,7 @@ pub struct Contract {
1314
pub id: u128,
1415
pub location: Location,
1516
pub name: String,
17+
pub fields: Vec<(String, Type)>,
1618
pub children: RefCell<Vec<ContractChildType>>,
1719
}
1820

sdk/src/ast/custom_type.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use std::{cell::RefCell, rc::Rc};
2+
3+
use soroban_security_rules_macro_lib::node_location;
4+
5+
use super::{
6+
node::{Location, TLocation},
7+
node_type::CustomTypeChildType,
8+
};
9+
10+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
11+
pub enum Type {
12+
T(String), //TODO: Implement this
13+
}
14+
15+
#[derive(Clone, serde::Serialize, serde::Deserialize)]
16+
pub enum CustomType {
17+
Struct(Rc<StructType>),
18+
Enum(Rc<EnumType>),
19+
}
20+
21+
impl CustomType {
22+
#[must_use = "This function creates a new instance of CustomType"]
23+
pub fn id(&self) -> u128 {
24+
match self {
25+
CustomType::Struct(struct_type) => struct_type.id,
26+
CustomType::Enum(enum_type) => enum_type.id,
27+
}
28+
}
29+
30+
#[must_use = "This function creates a new instance of CustomType"]
31+
pub fn location(&self) -> Location {
32+
match self {
33+
CustomType::Struct(struct_type) => struct_type.location.clone(),
34+
CustomType::Enum(enum_type) => enum_type.location.clone(),
35+
}
36+
}
37+
}
38+
39+
#[node_location]
40+
#[derive(serde::Serialize, serde::Deserialize)]
41+
pub struct StructType {
42+
pub id: u128,
43+
pub location: Location,
44+
pub name: String,
45+
pub fields: Vec<(String, Type)>,
46+
pub children: RefCell<Vec<CustomTypeChildType>>,
47+
}
48+
49+
#[node_location]
50+
#[derive(serde::Serialize, serde::Deserialize)]
51+
pub struct EnumType {
52+
pub id: u128,
53+
pub location: Location,
54+
pub name: String,
55+
pub variants: Vec<String>,
56+
pub children: RefCell<Vec<CustomTypeChildType>>,
57+
}

sdk/src/ast/expression.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![warn(clippy::pedantic)]
2+
use super::custom_type::Type;
23
use super::function::Function;
3-
use super::inner_type::Type;
44
use super::node::{Location, Node, TLocation};
55
use super::node_type::{FunctionCallChildType, MemberAccessChildType, MethodCallChildType};
66
use super::statement::Block;

sdk/src/ast/inner_type.rs

Lines changed: 0 additions & 23 deletions
This file was deleted.

sdk/src/ast/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Semantic types for the AST.
22
pub mod build;
33
pub mod contract;
4+
pub mod custom_type;
45
pub mod expression;
56
pub mod file;
67
pub mod function;
7-
pub mod inner_type;
88
pub mod node;
99
pub mod node_type;
1010
pub mod statement;

sdk/src/ast/node_type.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
44

55
use super::{
66
contract::Contract,
7+
custom_type::CustomType,
78
expression::{Expression, ExpressionParentType, FunctionCall, MethodCall},
89
file::File,
910
function::{FnParameter, Function},
@@ -36,6 +37,7 @@ impl TypeNode {
3637
pub enum NodeKind {
3738
File(Rc<File>),
3839
Contract(RcContract),
40+
CustomType(CustomType),
3941
Function(RcFunction),
4042
FnParameter(RcFnParameter),
4143
Statement(Statement),
@@ -46,6 +48,7 @@ pub enum NodeKind {
4648
#[derive(Clone, serde::Serialize, serde::Deserialize)]
4749
pub enum FileChildType {
4850
Contract(RcContract),
51+
CustomType(CustomType),
4952
}
5053

5154
#[derive(Clone, serde::Serialize, serde::Deserialize)]
@@ -110,6 +113,7 @@ pub fn get_node_kind_node_id(node: &NodeKind) -> u128 {
110113
match node {
111114
NodeKind::File(f) => f.id,
112115
NodeKind::Contract(c) => c.id,
116+
NodeKind::CustomType(c) => c.id(),
113117
NodeKind::Function(f) => f.id,
114118
NodeKind::FnParameter(p) => p.id,
115119
NodeKind::Statement(s) => s.id(),
@@ -137,6 +141,7 @@ pub fn get_node_location(node: &NodeKind) -> Location {
137141
end_col: f.source_code.len(),
138142
},
139143
NodeKind::Contract(c) => c.location(),
144+
NodeKind::CustomType(c) => c.location(),
140145
NodeKind::Function(f) => f.location(),
141146
NodeKind::FnParameter(p) => p.location(),
142147
NodeKind::Statement(s) => s.location(),

sdk/src/codebase.rs

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ use crate::ast::node_type::NodeKind;
55
use crate::build::{
66
build_array_expression, build_assign_expresison, build_binary_expression,
77
build_block_statement, build_break_expression, build_cast_expression,
8-
build_const_block_expression, build_eblock_expression, build_identifier,
9-
build_member_access_expression, build_method_call_expression, build_reference_expression,
8+
build_const_block_expression, build_contract, build_eblock_expression, build_enum_custom_type,
9+
build_identifier, build_member_access_expression, build_method_call_expression,
10+
build_reference_expression, build_struct_custom_type,
1011
};
12+
use crate::custom_type::Type;
1113
use crate::errors::SDKErr;
1214
use crate::expression::{Closure, Continue, Expression, Identifier};
1315
use crate::file::File;
1416
use crate::function::{FnParameter, Function};
15-
use crate::inner_type::Type;
1617
use crate::node_type::{ContractChildType, FileChildType, FunctionChildType, TypeNode};
1718
use crate::statement::Statement;
1819
use crate::{location, source_code, NodesStorage};
@@ -114,26 +115,40 @@ impl Codebase<OpenState> {
114115
.iter()
115116
.any(|attr| attr.path().is_ident("contract"))
116117
{
117-
let contract = Contract {
118-
id: Uuid::new_v4().as_u128(),
119-
location: location!(struct_item),
120-
name: Contract::contract_name_from_syn_item(struct_item),
121-
children: RefCell::new(Vec::new()),
122-
};
123-
let rc_contract = Rc::new(contract);
118+
let rc_contract = build_contract(struct_item);
124119
rc_file
125120
.children
126121
.borrow_mut()
127122
.push(FileChildType::Contract(rc_contract.clone()));
128123
codebase.add_node(NodeKind::Contract(rc_contract.clone()), rc_file.id);
124+
} else if struct_item
125+
.attrs
126+
.iter()
127+
.any(|attr| attr.path().is_ident("contracttype"))
128+
{
129+
let rc_custom_type = build_struct_custom_type(struct_item);
130+
rc_file
131+
.children
132+
.borrow_mut()
133+
.push(FileChildType::CustomType(rc_custom_type.clone()));
134+
codebase
135+
.add_node(NodeKind::CustomType(rc_custom_type.clone()), rc_file.id);
136+
}
137+
}
138+
syn::Item::Enum(enum_item) => {
139+
if enum_item
140+
.attrs
141+
.iter()
142+
.any(|attr| attr.path().is_ident("contracttype"))
143+
{
144+
let rc_custom_type = build_enum_custom_type(enum_item);
145+
rc_file
146+
.children
147+
.borrow_mut()
148+
.push(FileChildType::CustomType(rc_custom_type.clone()));
149+
codebase
150+
.add_node(NodeKind::CustomType(rc_custom_type.clone()), rc_file.id);
129151
}
130-
// else if struct_item
131-
// .attrs
132-
// .iter()
133-
// .any(|attr| attr.path().is_ident("contracttype"))
134-
// {
135-
// items_to_revisit.push(syn::Item::Struct(struct_item.clone()));
136-
// }
137152
}
138153
syn::Item::Impl(impl_item) => {
139154
if impl_item

sdk/src/utils/test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub(crate) fn create_mock_contract(id: u128) -> Contract {
8686
id,
8787
name: "TestContract".to_string(),
8888
location: create_mock_location(),
89+
fields: vec![],
8990
children: RefCell::new(vec![]),
9091
}
9192
}
@@ -100,6 +101,7 @@ pub(crate) fn create_mock_contract_with_inner_struct(
100101
id,
101102
name,
102103
location,
104+
fields: vec![],
103105
children: RefCell::new(vec![]),
104106
}
105107
}

0 commit comments

Comments
 (0)