@@ -15,12 +15,15 @@ use foundry_compilers::{
1515} ;
1616use foundry_config:: Config ;
1717use itertools:: Itertools ;
18- use rayon:: prelude:: * ;
19- use solang_parser:: pt as solang_ast;
18+ use solar_ast:: {
19+ ast:: { self , Arena , FunctionKind , Span , VarMut } ,
20+ interface:: source_map:: FileName ,
21+ visit:: Visit ,
22+ } ;
23+ use solar_parse:: { interface:: Session , Parser as SolarParser } ;
2024use std:: {
2125 collections:: { BTreeMap , BTreeSet } ,
22- fmt,
23- fmt:: Write ,
26+ fmt:: { self , Write } ,
2427 path:: PathBuf ,
2528 sync:: Arc ,
2629} ;
@@ -85,85 +88,94 @@ impl BindJsonArgs {
8588 . unwrap ( )
8689 . 1 ;
8790
88- // Insert empty bindings file
91+ let sess = Session :: builder ( ) . with_stderr_emitter ( ) . build ( ) ;
92+ let result = sess. enter ( || -> solar_parse:: interface:: Result < ( ) > {
93+ // TODO: Switch back to par_iter_mut and `enter_parallel` after solar update.
94+ sources. 0 . iter_mut ( ) . try_for_each ( |( path, source) | {
95+ let mut content = Arc :: try_unwrap ( std:: mem:: take ( & mut source. content ) ) . unwrap ( ) ;
96+
97+ let arena = Arena :: new ( ) ;
98+ let mut parser = SolarParser :: from_source_code (
99+ & sess,
100+ & arena,
101+ FileName :: Real ( path. clone ( ) ) ,
102+ content. to_string ( ) ,
103+ ) ?;
104+ let ast = parser. parse_file ( ) . map_err ( |e| e. emit ( ) ) ?;
105+
106+ let mut visitor = PreprocessorVisitor :: new ( ) ;
107+ visitor. visit_source_unit ( & ast) ;
108+ visitor. update ( & sess, & mut content) ;
109+
110+ source. content = Arc :: new ( content) ;
111+ Ok ( ( ) )
112+ } )
113+ } ) ;
114+ eyre:: ensure!( result. is_ok( ) , "failed parsing" ) ;
115+
116+ // Insert empty bindings file.
89117 sources. insert ( target_path. clone ( ) , Source :: new ( "library JsonBindings {}" ) ) ;
90118
91- let sources = Sources (
92- sources
93- . 0
94- . into_par_iter ( )
95- . map ( |( path, source) | {
96- let mut locs_to_update = Vec :: new ( ) ;
97- let mut content = Arc :: unwrap_or_clone ( source. content ) ;
98- let ( parsed, _) = solang_parser:: parse ( & content, 0 )
99- . map_err ( |errors| eyre:: eyre!( "Parser failed: {errors:?}" ) ) ?;
100-
101- // All function definitions in the file
102- let mut functions = Vec :: new ( ) ;
103-
104- for part in & parsed. 0 {
105- if let solang_ast:: SourceUnitPart :: FunctionDefinition ( def) = part {
106- functions. push ( def) ;
107- }
108- if let solang_ast:: SourceUnitPart :: ContractDefinition ( contract) = part {
109- for part in & contract. parts {
110- match part {
111- solang_ast:: ContractPart :: FunctionDefinition ( def) => {
112- functions. push ( def) ;
113- }
114- // Remove `immutable` attributes
115- solang_ast:: ContractPart :: VariableDefinition ( def) => {
116- for attr in & def. attrs {
117- if let solang_ast:: VariableAttribute :: Immutable ( loc) =
118- attr
119- {
120- locs_to_update. push ( (
121- loc. start ( ) ,
122- loc. end ( ) ,
123- String :: new ( ) ,
124- ) ) ;
125- }
126- }
127- }
128- _ => { }
129- }
130- }
131- } ;
132- }
119+ Ok ( PreprocessedState { sources, target_path, project, config } )
120+ }
121+ }
133122
134- for def in functions {
135- // If there's no body block, keep the function as is
136- let Some ( solang_ast:: Statement :: Block { loc, .. } ) = def. body else {
137- continue ;
138- } ;
139- let new_body = match def. ty {
140- solang_ast:: FunctionTy :: Modifier => "{ _; }" ,
141- _ => "{ revert(); }" ,
142- } ;
143- let start = loc. start ( ) ;
144- let end = loc. end ( ) ;
145- locs_to_update. push ( ( start, end + 1 , new_body. to_string ( ) ) ) ;
146- }
123+ struct PreprocessorVisitor {
124+ updates : Vec < ( Span , & ' static str ) > ,
125+ }
126+
127+ impl PreprocessorVisitor {
128+ fn new ( ) -> Self {
129+ Self { updates : Vec :: new ( ) }
130+ }
147131
148- locs_to_update. sort_by_key ( |( start, _, _) | * start) ;
132+ fn update ( mut self , sess : & Session , content : & mut String ) {
133+ if self . updates . is_empty ( ) {
134+ return ;
135+ }
149136
150- let mut shift = 0_i64 ;
137+ let sf = sess. source_map ( ) . lookup_source_file ( self . updates [ 0 ] . 0 . lo ( ) ) ;
138+ let base = sf. start_pos . 0 ;
151139
152- for ( start, end, new) in locs_to_update {
153- let start = ( ( start as i64 ) - shift) as usize ;
154- let end = ( ( end as i64 ) - shift) as usize ;
140+ self . updates . sort_by_key ( |( span, _) | span. lo ( ) ) ;
141+ let mut shift = 0_i64 ;
142+ for ( span, new) in self . updates {
143+ let lo = span. lo ( ) - base;
144+ let hi = span. hi ( ) - base;
145+ let start = ( ( lo. 0 as i64 ) - shift) as usize ;
146+ let end = ( ( hi. 0 as i64 ) - shift) as usize ;
155147
156- content. replace_range ( start..end, new. as_str ( ) ) ;
157- shift += ( end - start) as i64 ;
158- shift -= new. len ( ) as i64 ;
159- }
148+ content. replace_range ( start..end, new) ;
149+ shift += ( end - start) as i64 ;
150+ shift -= new. len ( ) as i64 ;
151+ }
152+ }
153+ }
160154
161- Ok ( ( path, Source :: new ( content) ) )
162- } )
163- . collect :: < Result < BTreeMap < _ , _ > > > ( ) ?,
164- ) ;
155+ impl < ' ast > Visit < ' ast > for PreprocessorVisitor {
156+ fn visit_item_function ( & mut self , func : & ' ast ast:: ItemFunction < ' ast > ) {
157+ // Replace function bodies with a noop statement.
158+ if let Some ( block) = & func. body {
159+ if !block. is_empty ( ) {
160+ let span = block. first ( ) . unwrap ( ) . span . to ( block. last ( ) . unwrap ( ) . span ) ;
161+ let new_body = match func. kind {
162+ FunctionKind :: Modifier => "_;" ,
163+ _ => "revert();" ,
164+ } ;
165+ self . updates . push ( ( span, new_body) ) ;
166+ }
167+ }
165168
166- Ok ( PreprocessedState { sources, target_path, project, config } )
169+ self . walk_item_function ( func)
170+ }
171+
172+ fn visit_variable_definition ( & mut self , var : & ' ast ast:: VariableDefinition < ' ast > ) {
173+ // Remove `immutable` attributes.
174+ if let Some ( VarMut :: Immutable ) = var. mutability {
175+ self . updates . push ( ( var. span , "" ) ) ;
176+ }
177+
178+ self . walk_variable_definition ( var)
167179 }
168180}
169181
0 commit comments