2
2
3
3
use super :: * ;
4
4
use crate :: reader:: Offset ;
5
- use crate :: value:: Parselet ;
5
+ use crate :: value:: ParseletRef ;
6
6
use crate :: vm:: Program ;
7
7
use crate :: Error ;
8
8
use crate :: { Object , RefValue } ;
9
- use indexmap:: { indexmap, IndexMap , IndexSet } ;
9
+ use indexmap:: { indexmap, indexset , IndexMap , IndexSet } ;
10
10
use log;
11
- use std:: collections:: { HashMap , HashSet } ;
11
+ use std:: cell:: RefCell ;
12
+ use std:: collections:: HashMap ;
12
13
13
14
#[ derive( Debug ) ]
14
15
pub ( in crate :: compiler) struct ImlProgram {
15
- main : ImlValue ,
16
- statics : IndexMap < ImlValue , Option < Parselet > > , // static values with optional final parselet replacement
17
- errors : Vec < Error > , // errors collected during compilation
16
+ errors : Vec < Error > , // errors collected during compilation
17
+ statics : IndexSet < Result < RefValue , usize > > ,
18
+ parselets : IndexMap < ImlRefParselet , usize > ,
18
19
}
19
20
20
21
impl ImlProgram {
21
- pub fn new ( main : ImlValue ) -> Self {
22
+ pub fn new ( main : ImlRefParselet ) -> Self {
22
23
ImlProgram {
23
- main : main. clone ( ) ,
24
- statics : indexmap ! ( main => None ) ,
25
24
errors : Vec :: new ( ) ,
25
+ statics : indexset ! [ Err ( 0 ) ] ,
26
+ parselets : indexmap ! [ main => 0 ] ,
26
27
}
27
28
}
28
29
@@ -37,25 +38,39 @@ impl ImlProgram {
37
38
38
39
In case *value* already exists inside of the current statics, the existing index will be returned,
39
40
otherwiese the value is cloned and put into the statics table. */
40
- pub fn register ( & mut self , value : & ImlValue ) -> usize {
41
+ pub fn register ( & mut self , value : & ImlValue ) -> Result < usize , ( ) > {
41
42
match value {
42
43
ImlValue :: Shared ( value) => return self . register ( & * value. borrow ( ) ) ,
43
- ImlValue :: Parselet ( _) | ImlValue :: Value ( _) => match self . statics . get_index_of ( value) {
44
- None => return self . statics . insert_full ( value. clone ( ) , None ) . 0 ,
45
- Some ( idx) => return idx,
44
+ ImlValue :: Parselet ( parselet) => match self . parselets . get ( parselet) {
45
+ Some ( idx) => Ok ( * idx) ,
46
+ None => {
47
+ let idx = self . statics . insert_full ( Err ( self . parselets . len ( ) + 1 ) ) . 0 ;
48
+ self . parselets . insert ( parselet. clone ( ) , idx) ;
49
+ Ok ( idx)
50
+ }
46
51
} ,
47
- ImlValue :: Variable { offset, name, .. } => self . errors . push ( Error :: new (
48
- offset. clone ( ) ,
49
- format ! ( "Variable '{}' used in static context" , name) ,
50
- ) ) ,
52
+ ImlValue :: Value ( value) => {
53
+ let value = Ok ( value. clone ( ) ) ;
54
+
55
+ match self . statics . get_index_of ( & value) {
56
+ Some ( idx) => Ok ( idx) ,
57
+ None => Ok ( self . statics . insert_full ( value) . 0 ) ,
58
+ }
59
+ }
60
+ ImlValue :: Variable { offset, name, .. } => {
61
+ self . errors . push ( Error :: new (
62
+ offset. clone ( ) ,
63
+ format ! ( "Variable '{}' used in static context" , name) ,
64
+ ) ) ;
65
+ Err ( ( ) )
66
+ }
51
67
ImlValue :: Generic { offset, .. } | ImlValue :: Instance ( ImlInstance { offset, .. } ) => {
52
68
self . errors
53
69
. push ( Error :: new ( offset. clone ( ) , format ! ( "Unresolved {}" , value) ) ) ;
70
+ Err ( ( ) )
54
71
}
55
72
_ => unreachable ! ( ) ,
56
73
}
57
-
58
- 0
59
74
}
60
75
61
76
/** Turns the ImlProgram and its intermediate values into a final VM program ready for execution.
@@ -65,44 +80,36 @@ impl ImlProgram {
65
80
and nullable parselet detection occurs.
66
81
*/
67
82
pub fn compile ( mut self ) -> Result < Program , Vec < Error > > {
68
- log:: info!( "compiling {}" , self . main) ;
69
-
70
- let mut finalize = HashSet :: new ( ) ; // list of consuming parselets required to be finalized
83
+ log:: info!( "compiling {}" , self . parselets[ 0 ] ) ;
71
84
72
- // Loop until end of statics is reached
73
- let mut idx = 0 ;
85
+ // Loop until end of parselets is reached
86
+ let mut count = 0 ;
74
87
75
- // self.statics grows inside of this while loop, therefore this condition.
76
- while idx < self . statics . len ( ) {
88
+ // self.parselets grows inside of this while loop, therefore this condition.
89
+ while count < self . parselets . len ( ) {
77
90
log:: trace!(
78
- "idx = {: >3}, statics .len() = {: >3}" ,
79
- idx ,
80
- self . statics . len( )
91
+ "count = {: >3}, parselets .len() = {: >3}" ,
92
+ count ,
93
+ self . parselets . len( )
81
94
) ;
82
95
83
- // Pick only intermediate parselets, other static values are directly moved
84
- let parselet = match self . statics . get_index_mut ( idx) . unwrap ( ) {
85
- ( _, Some ( _) ) => unreachable ! ( ) , // may not exist!
86
- ( ImlValue :: Parselet ( parselet) , None ) => parselet. clone ( ) ,
87
- _ => {
88
- idx += 1 ;
89
- continue ;
90
- }
91
- } ;
92
-
96
+ let ( parselet, idx) = self
97
+ . parselets
98
+ . get_index ( count)
99
+ . map ( |( p, idx) | ( p. clone ( ) , * idx) )
100
+ . unwrap ( ) ;
93
101
log:: trace!( "idx = {: >3}, parselet = {:?}" , idx, parselet. borrow( ) . name) ;
94
102
95
- // Memoize parselets required to be finalized (needs a general rework later...)
96
- if parselet. borrow ( ) . model . borrow ( ) . is_consuming {
97
- //fixme...
98
- finalize. insert ( parselet. clone ( ) ) ;
99
- }
103
+ // Compile static VM parselet from intermediate parselet
104
+ let compiled_parselet = parselet. compile ( & mut self , idx) ;
100
105
101
- // Compile VM parselet from intermediate parselet
102
- // println!("...compiling {} {:?}", idx, parselet.name);
103
- * self . statics . get_index_mut ( idx) . unwrap ( ) . 1 = Some ( parselet. compile ( & mut self , idx) ) ;
106
+ // Insert new parselet before placeholder...
107
+ self . statics
108
+ . insert_before ( idx, Ok ( RefValue :: from ( compiled_parselet) ) ) ;
109
+ // ...and remove the placeholder.
110
+ self . statics . shift_remove_index ( idx + 1 ) ;
104
111
105
- idx += 1 ;
112
+ count += 1 ;
106
113
}
107
114
108
115
// Stop on any raised error
@@ -111,36 +118,16 @@ impl ImlProgram {
111
118
}
112
119
113
120
// Finalize parselets
114
- log:: info!( "{} has {} parselets to finalize" , self . main, finalize. len( ) ) ;
115
-
116
- for ( i, parselet) in finalize. iter ( ) . enumerate ( ) {
117
- log:: trace!( " {: >3} => {:#?}" , i, parselet) ;
118
- }
119
-
120
- let leftrec = self . finalize ( finalize) ;
121
+ self . finalize ( ) ;
121
122
122
123
// Assemble all statics to be transferred into a Program
123
124
let statics: Vec < RefValue > = self
124
125
. statics
125
126
. into_iter ( )
126
- . map ( |( iml, parselet) | {
127
- if let Some ( mut parselet) = parselet {
128
- if let ImlValue :: Parselet ( imlparselet) = iml {
129
- parselet. consuming = leftrec
130
- . get ( & imlparselet)
131
- . map_or ( None , |leftrec| Some ( * leftrec) ) ;
132
-
133
- //println!("{:?} => {:?}", imlparselet.borrow().name, parselet.consuming);
134
- }
135
-
136
- RefValue :: from ( parselet)
137
- } else {
138
- iml. unwrap ( )
139
- }
140
- } )
127
+ . map ( |value| value. unwrap ( ) )
141
128
. collect ( ) ;
142
129
143
- log:: info!( "{} has {} statics compiled" , self . main , statics. len( ) ) ;
130
+ log:: info!( "{:? } has {} statics compiled" , statics [ 0 ] , statics. len( ) ) ;
144
131
145
132
for ( i, value) in statics. iter ( ) . enumerate ( ) {
146
133
log:: trace!( " {: >3} : {:#?}" , i, value) ;
@@ -156,11 +143,11 @@ impl ImlProgram {
156
143
- nullable parselets
157
144
- left-recursive parselets
158
145
159
- until no more changes occur.
146
+ until no more changes to these flag configurations occur.
160
147
161
148
It can only be run on a previously compiled program without any unresolved usages.
162
149
*/
163
- fn finalize ( & mut self , parselets : HashSet < ImlRefParselet > ) -> HashMap < ImlRefParselet , bool > {
150
+ fn finalize ( & mut self ) {
164
151
#[ derive( Debug , Clone , Copy , PartialEq , PartialOrd ) ]
165
152
struct Consumable {
166
153
leftrec : bool ,
@@ -172,18 +159,18 @@ impl ImlProgram {
172
159
value : & ImlValue ,
173
160
current : & ImlRefParselet ,
174
161
visited : & mut IndexSet < ImlRefParselet > ,
175
- configs : & mut HashMap < ImlRefParselet , Consumable > ,
162
+ configs : & HashMap < ImlRefParselet , RefCell < Consumable > > ,
176
163
) -> Option < Consumable > {
177
164
match value {
178
165
ImlValue :: Shared ( value) => {
179
166
finalize_value ( & * value. borrow ( ) , current, visited, configs)
180
167
}
181
168
ImlValue :: SelfToken => {
182
- configs. get_mut ( current) . unwrap ( ) . leftrec = true ;
169
+ configs[ current] . borrow_mut ( ) . leftrec = true ;
183
170
184
171
Some ( Consumable {
185
172
leftrec : true ,
186
- nullable : configs[ current] . nullable ,
173
+ nullable : configs[ current] . borrow ( ) . nullable ,
187
174
} )
188
175
}
189
176
ImlValue :: Parselet ( parselet) => {
@@ -221,7 +208,7 @@ impl ImlProgram {
221
208
op : & ImlOp ,
222
209
current : & ImlRefParselet ,
223
210
visited : & mut IndexSet < ImlRefParselet > ,
224
- configs : & mut HashMap < ImlRefParselet , Consumable > ,
211
+ configs : & HashMap < ImlRefParselet , RefCell < Consumable > > ,
225
212
) -> Option < Consumable > {
226
213
match op {
227
214
ImlOp :: Call { target, .. } => finalize_value ( target, current, visited, configs) ,
@@ -318,29 +305,25 @@ impl ImlProgram {
318
305
fn finalize_parselet (
319
306
current : & ImlRefParselet ,
320
307
visited : & mut IndexSet < ImlRefParselet > ,
321
- configs : & mut HashMap < ImlRefParselet , Consumable > ,
308
+ configs : & HashMap < ImlRefParselet , RefCell < Consumable > > ,
322
309
) -> Option < Consumable > {
323
310
// ... only if it's generally flagged to be consuming.
324
311
let parselet = current. borrow ( ) ;
325
312
let model = parselet. model . borrow ( ) ;
326
313
327
- if !model. is_consuming {
328
- return None ;
329
- }
330
-
331
314
//println!("- {}{}", ".".repeat(visited.len()), current);
332
315
333
316
if let Some ( idx) = visited. get_index_of ( current) {
334
317
// When in visited, this is a recursion
335
318
Some ( Consumable {
336
319
// If the idx is 0, current is the seeked parselet, so it is left-recursive
337
320
leftrec : if idx == 0 && !current. borrow ( ) . is_generated {
338
- configs. get_mut ( current) . unwrap ( ) . leftrec = true ;
321
+ configs[ current] . borrow_mut ( ) . leftrec = true ;
339
322
true
340
323
} else {
341
324
false
342
325
} ,
343
- nullable : configs[ current] . nullable ,
326
+ nullable : configs[ current] . borrow ( ) . nullable ,
344
327
} )
345
328
} else {
346
329
// If not already visited, add and recurse.
@@ -354,52 +337,65 @@ impl ImlProgram {
354
337
355
338
Some ( Consumable {
356
339
leftrec : false ,
357
- nullable : configs[ current] . nullable ,
340
+ nullable : configs[ current] . borrow ( ) . nullable ,
358
341
} )
359
342
}
360
343
}
361
344
362
- log:: trace!(
363
- "{} has {} parselets to finalize" ,
364
- self . statics. keys( ) [ 0 ] ,
365
- parselets. len( )
366
- ) ;
367
-
368
- // Now, start the closure algorithm with left-recursive and nullable configurations for all parselets
369
- // put into the finalize list.
345
+ // Now, start the closure algorithm with left-recursive and nullable configurations
346
+ // for all consumable parselets.
370
347
let mut changes = true ;
371
- let mut configs = parselets
372
- . iter ( )
348
+ let configs: HashMap < ImlRefParselet , RefCell < Consumable > > = self
349
+ . parselets
350
+ . keys ( )
351
+ . filter ( |k| k. borrow ( ) . model . borrow ( ) . is_consuming )
373
352
. map ( |k| {
374
353
(
375
354
k. clone ( ) ,
376
- Consumable {
355
+ RefCell :: new ( Consumable {
377
356
leftrec : false ,
378
357
nullable : false ,
379
- } ,
358
+ } ) ,
380
359
)
381
360
} )
382
361
. collect ( ) ;
383
362
363
+ log:: info!(
364
+ "{:?} has {} parselets to finalize" ,
365
+ self . statics[ 0 ] ,
366
+ configs. len( )
367
+ ) ;
368
+
369
+ for ( i, parselet) in configs. keys ( ) . enumerate ( ) {
370
+ log:: trace!( " {: >3} => {:#?}" , i, parselet) ;
371
+ }
372
+
384
373
while changes {
385
374
changes = false ;
386
375
387
- for parselet in & parselets {
388
- let result = finalize_parselet ( parselet, & mut IndexSet :: new ( ) , & mut configs) ;
389
- changes = result > configs. get ( parselet) . cloned ( ) ;
376
+ for parselet in configs. keys ( ) {
377
+ if let Some ( result) = finalize_parselet ( parselet, & mut IndexSet :: new ( ) , & configs) {
378
+ changes = result > * configs[ parselet] . borrow ( ) ;
379
+ }
390
380
}
391
381
}
392
382
393
- for parselet in & parselets {
394
- log:: trace!( " {:?} consuming={:?}" , parselet, configs[ & parselet] ) ;
383
+ // set left recursion flags
384
+ for ( parselet, config) in configs {
385
+ // get compiled parselet from statics
386
+ let parselet = self . statics [ self . parselets [ & parselet] ] . as_ref ( ) . unwrap ( ) ;
387
+
388
+ if let Some ( parselet) = parselet. borrow ( ) . object :: < ParseletRef > ( ) {
389
+ parselet. 0 . borrow_mut ( ) . consuming = Some ( config. borrow ( ) . leftrec ) ;
390
+ }
391
+
392
+ log:: trace!( " {:?} consuming={:?}" , parselet, config) ;
395
393
}
396
394
397
395
log:: debug!(
398
- "{} has {} parselets finalized" ,
399
- self . statics. keys ( ) [ 0 ] ,
400
- parselets. len( )
396
+ "{:? } has {} parselets finalized" ,
397
+ self . statics[ 0 ] ,
398
+ self . parselets. len( )
401
399
) ;
402
-
403
- configs. into_iter ( ) . map ( |( k, v) | ( k, v. leftrec ) ) . collect ( )
404
400
}
405
401
}
0 commit comments