1
- use std:: {
2
- collections:: { hash_map:: Entry , HashMap } ,
3
- fmt,
4
- } ;
1
+ use std:: { collections:: HashMap , fmt} ;
5
2
6
3
mod types;
7
4
pub use types:: { AddressMode , Modifier , Opcode , Value } ;
8
5
9
6
pub const DEFAULT_CORE_SIZE : usize = 8000 ;
10
7
11
- type InstructionSet = Box < [ Option < Instruction > ] > ;
8
+ type Instructions = Box < [ Option < Instruction > ] > ;
12
9
type LabelMap = HashMap < String , usize > ;
13
10
14
11
#[ derive( Clone , Debug , PartialEq ) ]
@@ -109,14 +106,15 @@ impl Instruction {
109
106
}
110
107
111
108
pub struct Core {
112
- instructions : InstructionSet ,
109
+ instructions : Instructions ,
110
+ resolved : Option < Instructions > ,
113
111
labels : LabelMap ,
114
112
}
115
113
116
114
impl PartialEq for Core {
117
- // TODO: should this impl resolve the instructions? Depends on the use case
118
115
fn eq ( & self , other : & Self ) -> bool {
119
- self . instructions == other. instructions
116
+ ( self . resolved . is_some ( ) && self . resolved == other. resolved )
117
+ || self . instructions == other. instructions
120
118
}
121
119
}
122
120
@@ -128,35 +126,35 @@ impl Default for Core {
128
126
129
127
impl fmt:: Debug for Core {
130
128
fn fmt ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
131
- write ! (
132
- formatter,
133
- "Labels: {:?}\n Core:\n {}" ,
134
- self . labels,
135
- self . dump( )
136
- )
129
+ if self . resolved . is_some ( ) {
130
+ write ! ( formatter, "{}" , self )
131
+ } else {
132
+ write ! ( formatter, "<unresolved core>" )
133
+ }
137
134
}
138
135
}
139
136
140
137
impl Core {
141
138
pub fn new ( core_size : usize ) -> Self {
142
139
Core {
143
140
instructions : vec ! [ None ; core_size] . into_boxed_slice ( ) ,
144
- labels : HashMap :: new ( ) ,
141
+ resolved : None ,
142
+ labels : LabelMap :: new ( ) ,
145
143
}
146
144
}
147
145
148
146
pub fn get ( & self , index : usize ) -> Option < Instruction > {
149
- self . instructions . get ( index) ?. clone ( )
150
- }
151
-
152
- pub fn get_resolved ( & self , index : usize ) -> Result < Instruction , String > {
153
- self . get ( index)
154
- . unwrap_or_default ( )
155
- . resolve ( index, & self . labels )
147
+ match & self . resolved {
148
+ Some ( instructions) => instructions,
149
+ None => & self . instructions ,
150
+ }
151
+ . get ( index) ?
152
+ . clone ( )
156
153
}
157
154
158
155
pub fn set ( & mut self , index : usize , value : Instruction ) {
159
156
self . instructions [ index] = Some ( value) ;
157
+ // TODO need to re-resolve here? Or make caller do it
160
158
}
161
159
162
160
pub fn add_label ( & mut self , index : usize , label : String ) -> Result < ( ) , String > {
@@ -168,21 +166,19 @@ impl Core {
168
166
) ) ;
169
167
}
170
168
171
- match self . labels . entry ( label) {
172
- Entry :: Occupied ( entry) => Err ( format ! ( "Label '{}' already exists" , entry. key( ) ) ) ,
173
- Entry :: Vacant ( entry) => {
174
- entry. insert ( index) ;
175
- Ok ( ( ) )
176
- }
169
+ if self . labels . insert ( label. clone ( ) , index) . is_some ( ) {
170
+ Err ( format ! ( "Label '{}' already exists" , label) )
171
+ } else {
172
+ Ok ( ( ) )
177
173
}
178
174
}
179
175
180
176
pub fn label_address ( & self , label : & str ) -> Option < usize > {
181
177
self . labels . get ( label) . copied ( )
182
178
}
183
179
184
- pub fn resolve ( & self ) -> Result < Self , String > {
185
- let instructions = self
180
+ pub fn resolve ( & mut self ) -> Result < & mut Self , String > {
181
+ let resolved = self
186
182
. instructions
187
183
. iter ( )
188
184
. enumerate ( )
@@ -192,29 +188,29 @@ impl Core {
192
188
. map ( |instruction| instruction. resolve ( i, & self . labels ) )
193
189
. transpose ( )
194
190
} )
195
- . collect :: < Result < InstructionSet , String > > ( ) ?;
191
+ . collect :: < Result < _ , String > > ( ) ?;
196
192
197
- Ok ( Self {
198
- instructions,
199
- ..Default :: default ( )
200
- } )
193
+ self . resolved = Some ( resolved) ;
194
+
195
+ Ok ( self )
201
196
}
197
+ }
202
198
203
- pub fn dump ( & self ) -> String {
204
- // TODO: convert to fmt::Display - this will require some upfront
205
- // validation that all labels are valid, etc
206
- // It may be desirable to have Debug be a dump() of the load file and
207
- // Display show the original parsed document (or something like that)
208
- match self . resolve ( ) {
209
- Err ( msg ) => msg ,
210
- Ok ( core ) => core
211
- . instructions
212
- . iter ( )
213
- . filter_map ( Option :: as_ref)
214
- . fold ( String :: new ( ) , |result, instruction| {
215
- result + & instruction. to_string ( ) + "\n "
216
- } ) ,
217
- }
199
+ impl fmt :: Display for Core {
200
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt :: Result {
201
+ write ! (
202
+ f ,
203
+ "{}" ,
204
+ match & self . resolved {
205
+ None => & self . instructions ,
206
+ Some ( instructions ) => instructions ,
207
+ }
208
+ . iter( )
209
+ . filter_map( Option :: as_ref)
210
+ . fold( String :: new( ) , |result, instruction| {
211
+ result + & instruction. to_string( ) + "\n "
212
+ } )
213
+ )
218
214
}
219
215
}
220
216
@@ -251,11 +247,13 @@ mod tests {
251
247
core. add_label ( 256 , "goblin" . into ( ) )
252
248
. expect_err ( "Should fail to add labels > 200" ) ;
253
249
core. add_label ( 5 , "baz" . into ( ) )
254
- . expect_err ( "Should fail to add duplicate label" ) ;
250
+ . expect_err ( "Should error duplicate label" ) ;
255
251
256
252
assert_eq ! ( core. label_address( "foo" ) . unwrap( ) , 0 ) ;
257
253
assert_eq ! ( core. label_address( "bar" ) . unwrap( ) , 0 ) ;
258
- assert_eq ! ( core. label_address( "baz" ) . unwrap( ) , 123 ) ;
254
+
255
+ // The _last_ version of a label will be the one we use
256
+ assert_eq ! ( core. label_address( "baz" ) . unwrap( ) , 5 ) ;
259
257
260
258
assert ! ( core. label_address( "goblin" ) . is_none( ) ) ;
261
259
assert ! ( core. label_address( "never_mentioned" ) . is_none( ) ) ;
@@ -303,12 +301,10 @@ mod tests {
303
301
} ,
304
302
) ;
305
303
306
- let resolved_core = core. resolve ( ) . expect ( "Should resolve all labels in core" ) ;
304
+ core. resolve ( ) . expect ( "Should resolve all labels in core" ) ;
307
305
308
306
assert_eq ! (
309
- resolved_core
310
- . get( 3 )
311
- . expect( "Should have instruction at pos 5" ) ,
307
+ core. get( 3 ) . expect( "Should have instruction at pos 5" ) ,
312
308
Instruction {
313
309
field_a: Field {
314
310
value: Value :: Literal ( 4 ) ,
0 commit comments