@@ -242,39 +242,33 @@ impl SymbolsTable {
242242 }
243243}
244244
245- /// Indicates the type of fixup required at the address.
246- enum FixupType {
247- Gosub ,
248- Goto ,
249- OnError ,
250- }
251-
252245/// Describes a location in the code needs fixing up after all addresses have been laid out.
253- struct Fixup {
254- target : String ,
255- target_pos : LineCol ,
256- ftype : FixupType ,
246+ #[ allow( clippy:: enum_variant_names) ]
247+ enum Fixup {
248+ CallAddr ( String , LineCol ) ,
249+ GotoAddr ( String , LineCol ) ,
250+ OnErrorGotoAddr ( String , LineCol ) ,
257251}
258252
259253impl Fixup {
260254 /// Constructs a `Fixup` for an `EXIT` instruction.
261255 fn from_exit ( target : String , span : ExitSpan ) -> Self {
262- Self { target, target_pos : span. pos , ftype : FixupType :: Goto }
256+ Self :: GotoAddr ( target, span. pos )
263257 }
264258
265259 /// Constructs a `Fixup` for a `GOSUB` instruction.
266260 fn from_gosub ( span : GotoSpan ) -> Self {
267- Self { target : span. target , target_pos : span. target_pos , ftype : FixupType :: Gosub }
261+ Self :: CallAddr ( span. target , span. target_pos )
268262 }
269263
270264 /// Constructs a `Fixup` for a `GOTO` instruction.
271265 fn from_goto ( span : GotoSpan ) -> Self {
272- Self { target : span. target , target_pos : span. target_pos , ftype : FixupType :: Goto }
266+ Self :: GotoAddr ( span. target , span. target_pos )
273267 }
274268
275269 /// Constructs a `Fixup` for a `ON ERROR GOTO` instruction.
276270 fn from_on_error ( span : GotoSpan ) -> Self {
277- Self { target : span. target , target_pos : span. target_pos , ftype : FixupType :: OnError }
271+ Self :: OnErrorGotoAddr ( span. target , span. target_pos )
278272 }
279273}
280274
@@ -1150,6 +1144,18 @@ impl Compiler {
11501144 Ok ( ( ) )
11511145 }
11521146
1147+ /// Gets the address of a label.
1148+ fn get_label_addr (
1149+ labels : & HashMap < String , Address > ,
1150+ label : String ,
1151+ pos : LineCol ,
1152+ ) -> Result < usize > {
1153+ match labels. get ( & label) {
1154+ Some ( addr) => Ok ( * addr) ,
1155+ None => Err ( Error :: UnknownLabel ( pos, label. to_owned ( ) ) ) ,
1156+ }
1157+ }
1158+
11531159 /// Finishes compilation and returns the image representing the compiled program.
11541160 #[ allow( clippy:: wrong_self_convention) ]
11551161 fn to_image ( mut self ) -> Result < ( Image , SymbolsTable ) > {
@@ -1158,20 +1164,28 @@ impl Compiler {
11581164 }
11591165
11601166 for ( pc, fixup) in self . fixups {
1161- let addr = match self . labels . get ( & fixup. target ) {
1162- Some ( addr ) => * addr ,
1163- None => {
1164- return Err ( Error :: UnknownLabel ( fixup . target_pos , fixup . target ) ) ;
1167+ let new_instr = match fixup {
1168+ Fixup :: CallAddr ( label , pos ) => {
1169+ let addr = Self :: get_label_addr ( & self . labels , label , pos ) ? ;
1170+ Instruction :: Call ( JumpISpan { addr } )
11651171 }
1166- } ;
11671172
1168- match fixup. ftype {
1169- FixupType :: Gosub => self . instrs [ pc] = Instruction :: Call ( JumpISpan { addr } ) ,
1170- FixupType :: Goto => self . instrs [ pc] = Instruction :: Jump ( JumpISpan { addr } ) ,
1171- FixupType :: OnError => {
1172- self . instrs [ pc] = Instruction :: SetErrorHandler ( ErrorHandlerISpan :: Jump ( addr) )
1173+ Fixup :: GotoAddr ( label, pos) => {
1174+ let addr = Self :: get_label_addr ( & self . labels , label, pos) ?;
1175+ Instruction :: Jump ( JumpISpan { addr } )
11731176 }
1174- }
1177+
1178+ Fixup :: OnErrorGotoAddr ( label, pos) => {
1179+ let addr = Self :: get_label_addr ( & self . labels , label, pos) ?;
1180+ Instruction :: SetErrorHandler ( ErrorHandlerISpan :: Jump ( addr) )
1181+ }
1182+ } ;
1183+ debug_assert_eq ! (
1184+ std:: mem:: discriminant( & Instruction :: Nop ) ,
1185+ std:: mem:: discriminant( & self . instrs[ pc] ) ,
1186+ "Fixup target address must contain a Nop instruction" ,
1187+ ) ;
1188+ self . instrs [ pc] = new_instr;
11751189 }
11761190 let image = Image { instrs : self . instrs , data : self . data } ;
11771191 Ok ( ( image, self . symtable ) )
0 commit comments