@@ -20,6 +20,8 @@ use crate::vm::{ClarityVersion, Value};
2020// type-checking
2121// lookups
2222// unwrap evaluates both branches (https://github.com/clarity-lang/reference/issues/59)
23+ // possibly use ContractContext? Enviornment? we need to use this somehow to
24+ // provide full view of a contract, rather than passing in source
2325
2426const STRING_COST_BASE : u64 = 36 ;
2527const STRING_COST_MULTIPLIER : u64 = 3 ;
@@ -28,6 +30,15 @@ const STRING_COST_MULTIPLIER: u64 = 3;
2830/// cost includes their processing
2931const FUNCTIONS_WITH_ZERO_STRING_ARG_COST : & [ & str ] = & [ "concat" , "len" ] ;
3032
33+ /// Function definition keywords in Clarity
34+ const FUNCTION_DEFINITION_KEYWORDS : & [ & str ] =
35+ & [ "define-public" , "define-private" , "define-read-only" ] ;
36+
37+ /// Check if a function name is a function definition keyword
38+ fn is_function_definition ( function_name : & str ) -> bool {
39+ FUNCTION_DEFINITION_KEYWORDS . contains ( & function_name)
40+ }
41+
3142#[ derive( Debug , Clone ) ]
3243pub enum CostExprNode {
3344 // Native Clarity functions
@@ -204,7 +215,7 @@ fn static_cost_native(
204215 let exprs = & ast. expressions ;
205216 let user_args = UserArgumentsContext :: new ( ) ;
206217 let expr = & exprs[ 0 ] ;
207- let cost_analysis_tree =
218+ let ( _ , cost_analysis_tree) =
208219 build_cost_analysis_tree ( & expr, & user_args, cost_map, clarity_version) ?;
209220
210221 let summing_cost = calculate_total_cost_with_branching ( & cost_analysis_tree) ;
@@ -225,7 +236,7 @@ pub fn static_cost(
225236 let user_args = UserArgumentsContext :: new ( ) ;
226237 let mut costs = HashMap :: new ( ) ;
227238 for expr in exprs {
228- let cost_analysis_tree =
239+ let ( _ , cost_analysis_tree) =
229240 build_cost_analysis_tree ( expr, & user_args, & costs, clarity_version) ?;
230241
231242 let summing_cost = calculate_total_cost_with_branching ( & cost_analysis_tree) ;
@@ -239,57 +250,71 @@ pub fn static_cost(
239250 Ok ( costs)
240251}
241252
242- fn build_cost_analysis_tree (
253+ pub fn build_cost_analysis_tree (
243254 expr : & SymbolicExpression ,
244255 user_args : & UserArgumentsContext ,
245256 cost_map : & HashMap < String , StaticCost > ,
246257 clarity_version : & ClarityVersion ,
247- ) -> Result < CostAnalysisNode , String > {
258+ ) -> Result < ( Option < String > , CostAnalysisNode ) , String > {
248259 match & expr. expr {
249260 SymbolicExpressionType :: List ( list) => {
250261 if let Some ( function_name) = list. first ( ) . and_then ( |first| first. match_atom ( ) ) {
251- if function_name. as_str ( ) == "define-public"
252- || function_name. as_str ( ) == "define-private"
253- || function_name. as_str ( ) == "define-read-only"
254- {
255- return build_function_definition_cost_analysis_tree (
262+ if is_function_definition ( function_name. as_str ( ) ) {
263+ let ( returned_function_name, cost_analysis_tree) =
264+ build_function_definition_cost_analysis_tree (
265+ list,
266+ user_args,
267+ cost_map,
268+ clarity_version,
269+ ) ?;
270+ Ok ( ( Some ( returned_function_name) , cost_analysis_tree) )
271+ } else {
272+ let cost_analysis_tree = build_listlike_cost_analysis_tree (
256273 list,
257274 user_args,
258275 cost_map,
259276 clarity_version,
260- ) ;
277+ ) ?;
278+ Ok ( ( None , cost_analysis_tree) )
261279 }
280+ } else {
281+ let cost_analysis_tree =
282+ build_listlike_cost_analysis_tree ( list, user_args, cost_map, clarity_version) ?;
283+ Ok ( ( None , cost_analysis_tree) )
262284 }
263- build_listlike_cost_analysis_tree ( list, user_args, cost_map, clarity_version)
264285 }
265286 SymbolicExpressionType :: AtomValue ( value) => {
266287 let cost = calculate_value_cost ( value) ?;
267- Ok ( CostAnalysisNode :: leaf (
268- CostExprNode :: AtomValue ( value . clone ( ) ) ,
269- cost,
288+ Ok ( (
289+ None ,
290+ CostAnalysisNode :: leaf ( CostExprNode :: AtomValue ( value . clone ( ) ) , cost) ,
270291 ) )
271292 }
272293 SymbolicExpressionType :: LiteralValue ( value) => {
273294 let cost = calculate_value_cost ( value) ?;
274- Ok ( CostAnalysisNode :: leaf (
275- CostExprNode :: AtomValue ( value . clone ( ) ) ,
276- cost,
295+ Ok ( (
296+ None ,
297+ CostAnalysisNode :: leaf ( CostExprNode :: AtomValue ( value . clone ( ) ) , cost) ,
277298 ) )
278299 }
279300 SymbolicExpressionType :: Atom ( name) => {
280301 let expr_node = parse_atom_expression ( name, user_args) ?;
281- Ok ( CostAnalysisNode :: leaf ( expr_node, StaticCost :: ZERO ) )
302+ Ok ( ( None , CostAnalysisNode :: leaf ( expr_node, StaticCost :: ZERO ) ) )
282303 }
283- SymbolicExpressionType :: Field ( field_identifier) => Ok ( CostAnalysisNode :: leaf (
284- CostExprNode :: FieldIdentifier ( field_identifier. clone ( ) ) ,
285- StaticCost :: ZERO ,
304+ SymbolicExpressionType :: Field ( field_identifier) => Ok ( (
305+ None ,
306+ CostAnalysisNode :: leaf (
307+ CostExprNode :: FieldIdentifier ( field_identifier. clone ( ) ) ,
308+ StaticCost :: ZERO ,
309+ ) ,
286310 ) ) ,
287- SymbolicExpressionType :: TraitReference ( trait_name, _trait_definition) => {
288- Ok ( CostAnalysisNode :: leaf (
311+ SymbolicExpressionType :: TraitReference ( trait_name, _trait_definition) => Ok ( (
312+ None ,
313+ CostAnalysisNode :: leaf (
289314 CostExprNode :: TraitReference ( trait_name. clone ( ) ) ,
290315 StaticCost :: ZERO ,
291- ) )
292- }
316+ ) ,
317+ ) ) ,
293318 }
294319}
295320
@@ -316,13 +341,14 @@ fn build_function_definition_cost_analysis_tree(
316341 _user_args : & UserArgumentsContext ,
317342 cost_map : & HashMap < String , StaticCost > ,
318343 clarity_version : & ClarityVersion ,
319- ) -> Result < CostAnalysisNode , String > {
344+ ) -> Result < ( String , CostAnalysisNode ) , String > {
320345 let define_type = list[ 0 ]
321346 . match_atom ( )
322347 . ok_or ( "Expected atom for define type" ) ?;
323348 let signature = list[ 1 ]
324349 . match_list ( )
325350 . ok_or ( "Expected list for function signature" ) ?;
351+ println ! ( "signature: {:?}" , signature) ;
326352 let body = & list[ 2 ] ;
327353
328354 let mut children = Vec :: new ( ) ;
@@ -360,14 +386,23 @@ fn build_function_definition_cost_analysis_tree(
360386 }
361387
362388 // Process the function body with the function's user arguments context
363- let body_tree = build_cost_analysis_tree ( body, & function_user_args, cost_map, clarity_version) ?;
389+ let ( _, body_tree) =
390+ build_cost_analysis_tree ( body, & function_user_args, cost_map, clarity_version) ?;
364391 children. push ( body_tree) ;
365392
393+ // Get the function name from the signature
394+ let function_name = signature[ 0 ]
395+ . match_atom ( )
396+ . ok_or ( "Expected atom for function name" ) ?;
397+
366398 // Create the function definition node with zero cost (function definitions themselves don't have execution cost)
367- Ok ( CostAnalysisNode :: new (
368- CostExprNode :: UserFunction ( define_type. clone ( ) ) ,
369- StaticCost :: ZERO ,
370- children,
399+ Ok ( (
400+ function_name. clone ( ) . to_string ( ) ,
401+ CostAnalysisNode :: new (
402+ CostExprNode :: UserFunction ( define_type. clone ( ) ) ,
403+ StaticCost :: ZERO ,
404+ children,
405+ ) ,
371406 ) )
372407}
373408
@@ -389,12 +424,8 @@ fn build_listlike_cost_analysis_tree(
389424
390425 // Build children for all exprs
391426 for expr in exprs[ 1 ..] . iter ( ) {
392- children. push ( build_cost_analysis_tree (
393- expr,
394- user_args,
395- cost_map,
396- clarity_version,
397- ) ?) ;
427+ let ( _, child_tree) = build_cost_analysis_tree ( expr, user_args, cost_map, clarity_version) ?;
428+ children. push ( child_tree) ;
398429 }
399430
400431 let function_name = get_function_name ( & exprs[ 0 ] ) ?;
@@ -826,7 +857,7 @@ mod tests {
826857 let expr = & ast. expressions [ 0 ] ;
827858 let user_args = UserArgumentsContext :: new ( ) ;
828859 let cost_map = HashMap :: new ( ) ; // Empty cost map for tests
829- let cost_tree =
860+ let ( _ , cost_tree) =
830861 build_cost_analysis_tree ( expr, & user_args, & cost_map, & ClarityVersion :: Clarity3 )
831862 . unwrap ( ) ;
832863
@@ -873,7 +904,7 @@ mod tests {
873904 let expr = & ast. expressions [ 0 ] ;
874905 let user_args = UserArgumentsContext :: new ( ) ;
875906 let cost_map = HashMap :: new ( ) ; // Empty cost map for tests
876- let cost_tree =
907+ let ( _ , cost_tree) =
877908 build_cost_analysis_tree ( expr, & user_args, & cost_map, & ClarityVersion :: Clarity3 )
878909 . unwrap ( ) ;
879910
@@ -906,7 +937,7 @@ mod tests {
906937 let expr = & ast. expressions [ 0 ] ;
907938 let user_args = UserArgumentsContext :: new ( ) ;
908939 let cost_map = HashMap :: new ( ) ; // Empty cost map for tests
909- let cost_tree =
940+ let ( _ , cost_tree) =
910941 build_cost_analysis_tree ( expr, & user_args, & cost_map, & ClarityVersion :: Clarity3 )
911942 . unwrap ( ) ;
912943
@@ -929,7 +960,7 @@ mod tests {
929960 let expr = & ast. expressions [ 0 ] ;
930961 let user_args = UserArgumentsContext :: new ( ) ;
931962 let cost_map = HashMap :: new ( ) ; // Empty cost map for tests
932- let cost_tree =
963+ let ( _ , cost_tree) =
933964 build_cost_analysis_tree ( expr, & user_args, & cost_map, & ClarityVersion :: Clarity3 )
934965 . unwrap ( ) ;
935966
0 commit comments