@@ -4,6 +4,8 @@ use std::{
4
4
string:: ToString ,
5
5
} ;
6
6
7
+ type LabelMap = HashMap < String , usize > ;
8
+
7
9
pub const DEFAULT_CORE_SIZE : usize = 8000 ;
8
10
9
11
enum_string ! ( pub Opcode {
@@ -148,6 +150,24 @@ impl Field {
148
150
value : Value :: Literal ( value) ,
149
151
}
150
152
}
153
+
154
+ pub fn resolve ( & self , from : usize , labels : & LabelMap ) -> Result < Self , String > {
155
+ match & self . value {
156
+ Value :: Literal ( _) => Ok ( self . clone ( ) ) ,
157
+ Value :: Label ( label) => {
158
+ let label_value = labels
159
+ . get ( label)
160
+ . ok_or_else ( || format ! ( "Label '{}' not found" , & label) ) ?;
161
+
162
+ let value = Value :: Literal ( ( * label_value as i32 ) - ( from as i32 ) ) ;
163
+
164
+ Ok ( Self {
165
+ address_mode : self . address_mode ,
166
+ value,
167
+ } )
168
+ }
169
+ }
170
+ }
151
171
}
152
172
153
173
impl ToString for Field {
@@ -180,6 +200,17 @@ impl Instruction {
180
200
field_b,
181
201
}
182
202
}
203
+
204
+ pub fn resolve ( & self , from : usize , labels : & LabelMap ) -> Result < Self , String > {
205
+ let field_a = self . field_a . resolve ( from, labels) ?;
206
+ let field_b = self . field_b . resolve ( from, labels) ?;
207
+ Ok ( Self {
208
+ opcode : self . opcode ,
209
+ modifier : self . modifier ,
210
+ field_a,
211
+ field_b,
212
+ } )
213
+ }
183
214
}
184
215
185
216
impl ToString for Instruction {
@@ -196,24 +227,30 @@ impl ToString for Instruction {
196
227
197
228
#[ derive( PartialEq ) ]
198
229
pub struct Core {
199
- instructions : Vec < Instruction > ,
200
- labels : HashMap < String , usize > ,
230
+ instructions : Box < [ Option < Instruction > ] > ,
231
+ labels : LabelMap ,
201
232
}
202
233
203
234
impl Core {
204
235
pub fn new ( core_size : usize ) -> Self {
205
236
Core {
206
- instructions : vec ! [ Instruction :: default ( ) ; core_size] ,
237
+ instructions : vec ! [ None ; core_size] . into_boxed_slice ( ) ,
207
238
labels : HashMap :: new ( ) ,
208
239
}
209
240
}
210
241
211
- pub fn get ( & self , index : usize ) -> Option < & Instruction > {
212
- self . instructions . get ( index)
242
+ pub fn get ( & self , index : usize ) -> Option < Instruction > {
243
+ self . instructions . get ( index) ?. clone ( )
244
+ }
245
+
246
+ pub fn get_resolved ( & self , index : usize ) -> Result < Instruction , String > {
247
+ self . get ( index)
248
+ . unwrap_or_default ( )
249
+ . resolve ( index, & self . labels )
213
250
}
214
251
215
252
pub fn set ( & mut self , index : usize , value : Instruction ) {
216
- self . instructions [ index] = value;
253
+ self . instructions [ index] = Some ( value) ;
217
254
}
218
255
219
256
pub fn add_label ( & mut self , index : usize , label : String ) -> Result < ( ) , String > {
@@ -238,21 +275,22 @@ impl Core {
238
275
self . labels . get ( label) . copied ( )
239
276
}
240
277
241
- pub fn dump_all ( & self ) -> String {
242
- self . instructions
243
- . iter ( )
244
- . fold ( String :: new ( ) , |result, instruction| {
245
- result + & instruction. to_string ( ) + "\n "
246
- } )
247
- }
248
-
249
278
pub fn dump ( & self ) -> String {
250
- self . instructions
279
+ let resolve_result: Result < Vec < _ > , String > = self
280
+ . instructions
251
281
. iter ( )
252
- . filter ( |& instruction| * instruction != Instruction :: default ( ) )
253
- . fold ( String :: new ( ) , |result, instruction| {
282
+ . filter ( |& maybe_instruction| maybe_instruction. is_some ( ) )
283
+ . map ( |instruction| instruction. as_ref ( ) . unwrap ( ) )
284
+ . enumerate ( )
285
+ . map ( |( i, instruction) | instruction. resolve ( i, & self . labels ) )
286
+ . collect ( ) ;
287
+
288
+ match resolve_result {
289
+ Err ( msg) => msg,
290
+ Ok ( resolved) => resolved. iter ( ) . fold ( String :: new ( ) , |result, instruction| {
254
291
result + & instruction. to_string ( ) + "\n "
255
- } )
292
+ } ) ,
293
+ }
256
294
}
257
295
}
258
296
@@ -435,4 +473,44 @@ mod tests {
435
473
assert ! ( core. label_address( "goblin" ) . is_none( ) ) ;
436
474
assert ! ( core. label_address( "never_mentioned" ) . is_none( ) ) ;
437
475
}
476
+
477
+ // TODO: add test for unresolvable label
478
+ #[ test]
479
+ fn resolve_labels ( ) {
480
+ let mut core = Core :: new ( 200 ) ;
481
+
482
+ core. add_label ( 123 , "baz" . into ( ) ) . expect ( "Should add baz" ) ;
483
+ core. add_label ( 0 , "foo" . into ( ) ) . expect ( "Should add foo" ) ;
484
+
485
+ core. set (
486
+ 5 ,
487
+ Instruction {
488
+ field_a : Field {
489
+ value : Value :: Label ( "baz" . into ( ) ) ,
490
+ ..Default :: default ( )
491
+ } ,
492
+ field_b : Field {
493
+ value : Value :: Label ( "foo" . into ( ) ) ,
494
+ ..Default :: default ( )
495
+ } ,
496
+ ..Default :: default ( )
497
+ } ,
498
+ ) ;
499
+
500
+ let resolved = core. get_resolved ( 5 ) . expect ( "Should resolve instruction" ) ;
501
+ assert_eq ! (
502
+ resolved,
503
+ Instruction {
504
+ field_a: Field {
505
+ value: Value :: Literal ( 118 ) ,
506
+ ..Default :: default ( )
507
+ } ,
508
+ field_b: Field {
509
+ value: Value :: Literal ( -5 ) ,
510
+ ..Default :: default ( )
511
+ } ,
512
+ ..Default :: default ( )
513
+ }
514
+ )
515
+ }
438
516
}
0 commit comments