From f364a83db98e1acee24bee6b358b21d804add6ff Mon Sep 17 00:00:00 2001 From: Saf Date: Sun, 30 Aug 2020 13:57:46 -0700 Subject: [PATCH] Linted all the directive classes --- .rubocop.yml | 6 ++-- lib/n65/directives/ascii.rb | 24 +++---------- lib/n65/directives/bytes.rb | 50 ++++++++++----------------- lib/n65/directives/dw.rb | 56 ++++++++++++------------------- lib/n65/directives/enter_scope.rb | 44 ++++++++---------------- lib/n65/directives/exit_scope.rb | 24 ++++--------- lib/n65/directives/inc.rb | 44 ++++++++---------------- lib/n65/directives/incbin.rb | 30 ++++------------- lib/n65/directives/ines_header.rb | 45 +++++++++++-------------- lib/n65/directives/label.rb | 29 +++++----------- lib/n65/directives/org.rb | 28 +++++----------- lib/n65/directives/segment.rb | 22 +++--------- lib/n65/directives/space.rb | 24 ++++--------- 13 files changed, 135 insertions(+), 291 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 777e868..2dd57c6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,6 +10,9 @@ Style/FormatStringToken: Style/Documentation: Enabled: false +Lint/MissingSuper: + Enabled: false + Layout/EmptyLinesAroundAttributeAccessor: Enabled: true @@ -34,9 +37,6 @@ Lint/EmptyConditionalBody: Lint/FloatComparison: Enabled: true -Lint/MissingSuper: - Enabled: true - Lint/MixedRegexpCaptureTypes: Enabled: true diff --git a/lib/n65/directives/ascii.rb b/lib/n65/directives/ascii.rb index a4f1019..9a107da 100644 --- a/lib/n65/directives/ascii.rb +++ b/lib/n65/directives/ascii.rb @@ -1,42 +1,28 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive to include bytes + # This directive to include bytes class ASCII < InstructionBase - - - #### - ## Try to parse a .ascii directive def self.parse(line) match_data = line.match(/^\.ascii\s+"([^"]+)"$/) return nil if match_data.nil? + ASCII.new(match_data[1]) end - - #### - ## Initialize with a string def initialize(string) + super @string = string end - - #### - ## Execute on the assembler def exec(assembler) assembler.write_memory(@string.bytes) end - - #### - ## Display def to_s ".ascii \"#{@string}\"" end - end - end diff --git a/lib/n65/directives/bytes.rb b/lib/n65/directives/bytes.rb index 808c6aa..8a2c634 100644 --- a/lib/n65/directives/bytes.rb +++ b/lib/n65/directives/bytes.rb @@ -1,27 +1,21 @@ +# frozen_string_literal: true + require_relative '../instruction_base' -require_relative '../regexes.rb' +require_relative '../regexes' module N65 - - - #### - ## This directive to include bytes + # This directive to include bytes class Bytes < InstructionBase - - #### Custom Exceptions class InvalidByteValue < StandardError; end - - #### - ## Try to parse an incbin directive + # Try to parse an incbin directive def self.parse(line) match_data = line.match(/^\.bytes\s+(.+)$/) return nil if match_data.nil? bytes_array = match_data[1].split(',').map do |byte_string| - - ## Does byte_string represent a numeric literal, or is it a symbol? - ## In numeric captures $2 is always binary, $1 is always hex + # Does byte_string represent a numeric literal, or is it a symbol? + # In numeric captures $2 is always binary, $1 is always hex case byte_string.strip when Regexp.new("^#{Regexes::Num8}$") @@ -30,32 +24,28 @@ module N65 when Regexp.new("^#{Regexes::Num16}$") value = $2.nil? ? $1.to_i(16) : $2.to_i(2) - ## Break value up into two bytes + # Break value up into two bytes high = (0xff00 & value) >> 8 low = (0x00ff & value) [low, high] when Regexp.new("^#{Regexes::Sym}$") $1 else - fail(InvalidByteValue, byte_string) + raise(InvalidByteValue, byte_string) end end.flatten Bytes.new(bytes_array) end - - #### - ## Initialize with a byte array + # Initialize with a byte array def initialize(bytes_array) + super @bytes_array = bytes_array end - - #### - ## Execute on the assembler + # Execute on the assembler def exec(assembler) - promise = assembler.with_saved_state do |saved_assembler| @bytes_array.map! do |byte| case byte @@ -64,7 +54,7 @@ module N65 when String saved_assembler.symbol_table.resolve_symbol(byte) else - fail(InvalidByteValue, byte) + raise(InvalidByteValue, byte) end end saved_assembler.write_memory(@bytes_array) @@ -73,8 +63,8 @@ module N65 begin promise.call rescue SymbolTable::UndefinedSymbol - ## Write the bytes but assume a zero page address for all symbols - ## And just write 0xDE for a placeholder + # Write the bytes but assume a zero page address for all symbols + # And just write 0xDE for a placeholder placeholder_bytes = @bytes_array.map do |byte| case bytes when Integer @@ -82,21 +72,17 @@ module N65 when String 0xDE else - fail(InvalidByteValue, byte) + raise(InvalidByteValue, byte) end end assembler.write_memory(placeholder_bytes) - return promise + promise end end - - #### - ## Display, I don't want to write all these out + # Display, I don't want to write all these out def to_s ".bytes (#{@bytes_array.length})" end - end - end diff --git a/lib/n65/directives/dw.rb b/lib/n65/directives/dw.rb index f1fbe7f..0cfc536 100644 --- a/lib/n65/directives/dw.rb +++ b/lib/n65/directives/dw.rb @@ -1,25 +1,21 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive instruction can include a binary file + # This directive instruction can include a binary file class DW < InstructionBase - - #### - ## Try to parse a dw directive + # Try to parse a dw directive def self.parse(line) - - ## Maybe it is a straight up bit of hex + # Maybe it is a straight up bit of hex match_data = line.match(/^\.dw\s+\$([0-9A-F]{1,4})$/) unless match_data.nil? word = match_data[1].to_i(16) return DW.new(word) end - ## Or maybe it points to a symbol - match_data = line.match(/^\.dw\s+([A-Za-z_][A-Za-z0-9_\.]+)/) + # Or maybe it points to a symbol + match_data = line.match(/^\.dw\s+([A-Za-z_][A-Za-z0-9_.]+)/) unless match_data.nil? symbol = match_data[1] return DW.new(symbol) @@ -27,30 +23,24 @@ module N65 nil end - - #### - ## Initialize with filename + # Initialize with filename def initialize(value) @value = value end - - #### - ## Execute on the assembler, now in this case value may - ## be a symbol that needs to be resolved, if so we return - ## a lambda which can be executed later, with the promise - ## that that symbol will have then be defined - ## This is a little complicated, I admit. + # Execute on the assembler, now in this case value may + # be a symbol that needs to be resolved, if so we return + # a lambda which can be executed later, with the promise + # that that symbol will have then be defined + # This is a little complicated, I admit. def exec(assembler) - promise = assembler.with_saved_state do |saved_assembler| value = saved_assembler.symbol_table.resolve_symbol(@value) bytes = [value & 0xFFFF].pack('S').bytes saved_assembler.write_memory(bytes) end - - ## Try to execute it now, or setup the promise to return + # Try to execute it now, or setup the promise to return case @value when Integer bytes = [@value & 0xFFFF].pack('S').bytes @@ -59,28 +49,24 @@ module N65 begin promise.call rescue SymbolTable::UndefinedSymbol - ## Must still advance PC before returning promise, so we'll write - ## a place holder value of 0xDEAD + # Must still advance PC before returning promise, so we'll write + # a place holder value of 0xDEAD assembler.write_memory([0xDE, 0xAD]) - return promise + promise end else - fail("Uknown argument in .dw directive") + raise('Uknown argument in .dw directive') end end - - #### - ## Display + # Display def to_s case @value when String ".dw #{@value}" - when Fixnum - ".dw $%4.X" % @value + when Integer + '.dw $%4.X' % @value end end - end - end diff --git a/lib/n65/directives/enter_scope.rb b/lib/n65/directives/enter_scope.rb index 493c243..ea924a1 100644 --- a/lib/n65/directives/enter_scope.rb +++ b/lib/n65/directives/enter_scope.rb @@ -1,55 +1,39 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive to include bytes + # This directive to include bytes class EnterScope < InstructionBase - - #### - ## Try to parse an incbin directive def self.parse(line) - ## Anonymous scope + # Anonymous scope match_data = line.match(/^\.scope$/) - unless match_data.nil? - return EnterScope.new - end + return EnterScope.new unless match_data.nil? - ## Named scope + # Named scope match_data = line.match(/^\.scope\s+([a-zA-Z][a-zA-Z0-9_]+)$/) return nil if match_data.nil? + EnterScope.new(match_data[1]) end - - #### - ## Initialize with filename + # Initialize with filename def initialize(name = nil) @name = name end - - #### - ## Execute on the assembler, also create a symbol referring to - ## the current pc which contains a hyphen, and is impossible for - ## the user to create. This makes a scope simultaneously act as - ## a label to the current PC. If someone tries to use a scope - ## name as a label, it can return the address when the scope opened. + # Execute on the assembler, also create a symbol referring to + # the current pc which contains a hyphen, and is impossible for + # the user to create. This makes a scope simultaneously act as + # a label to the current PC. If someone tries to use a scope + # name as a label, it can return the address when the scope opened. def exec(assembler) assembler.symbol_table.enter_scope(@name) - unless @name.nil? - assembler.symbol_table.define_symbol("-#{@name}", assembler.program_counter) - end + assembler.symbol_table.define_symbol("-#{@name}", assembler.program_counter) unless @name.nil? end - - #### - ## Display def to_s ".scope #{@name}" end - end - end diff --git a/lib/n65/directives/exit_scope.rb b/lib/n65/directives/exit_scope.rb index 8e66f27..a45b294 100644 --- a/lib/n65/directives/exit_scope.rb +++ b/lib/n65/directives/exit_scope.rb @@ -1,35 +1,25 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive to include bytes + # This directive to include bytes class ExitScope < InstructionBase - - - #### - ## Try to parse an incbin directive def self.parse(line) match_data = line.match(/^\.$/) return nil if match_data.nil? + ExitScope.new end - - #### - ## Execute on the assembler + # Execute on the assembler def exec(assembler) assembler.symbol_table.exit_scope end - - #### - ## Display + # Display def to_s - "." + '.' end - end - end diff --git a/lib/n65/directives/inc.rb b/lib/n65/directives/inc.rb index f1c4d33..f53ea78 100644 --- a/lib/n65/directives/inc.rb +++ b/lib/n65/directives/inc.rb @@ -1,67 +1,51 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive instruction can include another asm file + # This directive instruction can include another asm file class Inc < InstructionBase + SYSTEM_INCLUDE = "#{File.dirname(__FILE__)}/../../../nes_lib" - #### System include directory - SystemInclude = File.dirname(__FILE__) + "/../../../nes_lib" - - #### Custom Exceptions class FileNotFound < StandardError; end - - #### - ## Try to parse an incbin directive + # Try to parse an incbin directive def self.parse(line) - ## Do We have a system directory include? + # Do We have a system directory include? match_data = line.match(/^\.inc <([^>]+)>$/) unless match_data.nil? - filename = File.join(SystemInclude, match_data[1]) + filename = File.join(SYSTEM_INCLUDE, match_data[1]) return Inc.new(filename) end - ## Do We have a project relative directory include? + # Do We have a project relative directory include? match_data = line.match(/^\.inc "([^"]+)"$/) unless match_data.nil? filename = File.join(Dir.pwd, match_data[1]) return Inc.new(filename) end - ## Nope, not an inc directive + # Nope, not an inc directive nil end - - #### - ## Initialize with filename + # Initialize with filename def initialize(filename) @filename = filename end - - #### - ## Execute on the assembler + # Execute on the assembler def exec(assembler) - unless File.exists?(@filename) - fail(FileNotFound, ".inc can't find #{@filename}") - end + raise(FileNotFound, ".inc can't find #{@filename}") unless File.exist?(@filename) + File.read(@filename).split(/\n/).each do |line| assembler.assemble_one_line(line) end end - - #### - ## Display + # Display def to_s ".inc \"#{@filename}\"" end - - end - end diff --git a/lib/n65/directives/incbin.rb b/lib/n65/directives/incbin.rb index 5f855ea..b41e1cb 100644 --- a/lib/n65/directives/incbin.rb +++ b/lib/n65/directives/incbin.rb @@ -1,51 +1,33 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive instruction can include a binary file + # This directive instruction can include a binary file class IncBin < InstructionBase - - #### Custom Exceptions class FileNotFound < StandardError; end - - #### - ## Try to parse an incbin directive def self.parse(line) match_data = line.match(/^\.incbin "([^"]+)"$/) return nil if match_data.nil? + filename = match_data[1] IncBin.new(filename) end - - #### - ## Initialize with filename def initialize(filename) @filename = filename end - - #### - ## Execute on the assembler def exec(assembler) - unless File.exists?(@filename) - fail(FileNotFound, ".incbin can't find #{@filename}") - end + raise(FileNotFound, ".incbin can't find #{@filename}") unless File.exist?(@filename) + data = File.read(@filename).unpack('C*') assembler.write_memory(data) end - - #### - ## Display def to_s ".incbin \"#{@filename}\"" end - - end - end diff --git a/lib/n65/directives/ines_header.rb b/lib/n65/directives/ines_header.rb index 5d7a990..bfc55d4 100644 --- a/lib/n65/directives/ines_header.rb +++ b/lib/n65/directives/ines_header.rb @@ -1,28 +1,33 @@ +# frozen_string_literal: true + require 'json' require_relative '../instruction_base' module N65 - - #### - ## This directive instruction can setup an iNES header class INESHeader < InstructionBase attr_reader :prog, :char, :mapper, :mirror, :battery_backed, :fourscreen_vram, :prog_ram, :tv - Defaults = {prog: 1, char: 0, mapper: 0, mirror: 0, battery_backed: 0, fourscreen_vram: 0, prog_ram: 0, tv: 0} + DEFAULTS = { + prog: 1, + char: 0, + mapper: 0, + mirror: 0, + battery_backed: 0, + fourscreen_vram: 0, + prog_ram: 0, + tv: 0 + }.freeze - #### - ## Implementation of the parser for this directive def self.parse(line) match_data = line.match(/^\.ines (.+)$/) return nil if match_data.nil? header = JSON.parse(match_data[1]) - header = header.inject({}) do |hash, (key, val)| + header = header.each_with_object({}) do |(key, val), hash| hash[key.to_sym] = val - hash end - header = Defaults.merge(header) + header = DEFAULTS.merge(header) INESHeader.new( header[:prog], @@ -32,12 +37,11 @@ module N65 header[:battery_backed], header[:fourscreen_vram], header[:prog_ram], - header[:tv]) + header[:tv] + ) end - - #### - ## Construct a header + # Construct a header def initialize(prog, char, mapper, mirror, battery_backed, fourscreen_vram, prog_ram, tv) @prog = prog @char = char @@ -49,18 +53,13 @@ module N65 @tv = tv end - - #### - ## Exec function the assembler will call + # Exec function the assembler will call def exec(assembler) assembler.set_ines_header(self) end - - #### - ## Emit the header bytes + # Emit the header bytes def emit_bytes - mapper_lo_nybble = (@mapper & 0x0f) mapper_hi_nybble = (@mapper & 0xf0) >> 4 @@ -82,16 +81,12 @@ module N65 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0] end - - #### - ## Display + # Display def to_s [".ines {\"prog\": #{@prog}, \"char\": #{@char}, \"mapper\": #{@mapper}, ", "\"mirror\": #{@mirror}}, \"battery_backed\": #{@battery_backed}, ", "\"fourscreen_vram\": #{@fourscreen_vram}, \"prog_ram\": #{@prog_ram}, ", "\"tv\": #{@tv}"].join end - end - end diff --git a/lib/n65/directives/label.rb b/lib/n65/directives/label.rb index 12d584f..6ff5753 100644 --- a/lib/n65/directives/label.rb +++ b/lib/n65/directives/label.rb @@ -1,46 +1,33 @@ +# frozen_string_literal: true module N65 - - #### - ## This class represents a label, and will create - ## an entry in the symbol table associated with - ## the address it appears at. + # This class represents a label, and will create + # an entry in the symbol table associated with + # the address it appears at. class Label - - #### - ## Try to parse as a label def self.parse(line) match_data = line.match(/^([a-zA-Z][a-zA-Z0-9_]+):$/) unless match_data.nil? label = match_data[1].to_sym - return self.new(label) + return new(label) end nil end - - #### - ## Create a new label object + # Create a new label object def initialize(symbol) @symbol = symbol end - - #### - ## Create an entry in the symbol table for this label + # Create an entry in the symbol table for this label def exec(assembler) program_counter = assembler.program_counter assembler.symbol_table.define_symbol(@symbol, program_counter) end - - #### - ## Display + # Display def to_s "#{@symbol}:" end - - end - end diff --git a/lib/n65/directives/org.rb b/lib/n65/directives/org.rb index 064cf4a..bad8c6c 100644 --- a/lib/n65/directives/org.rb +++ b/lib/n65/directives/org.rb @@ -1,47 +1,37 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - #### - ## This is an .org directive + # This is an .org directive class Org < InstructionBase attr_reader :address - #### - ## Try to parse an .org statement def self.parse(line) match_data = line.match(/^\.org\s+\$([0-9A-Fa-f]{4})$/) return nil if match_data.nil? + address = match_data[1].to_i(16) Org.new(address) end - - #### - ## Initialized with address to switch to + # Initialized with address to switch to def initialize(address) @address = address end - - #### - ## Exec this directive on the assembler + # Exec this directive on the assembler def exec(assembler) assembler.program_counter = address end - - #### - ## Display + # Display def to_s if @address <= 0xff - ".org $%2.X" % @address + '.org $%2.X' % @address else - ".org $%4.X" % @address + '.org $%4.X' % @address end end - end - end - diff --git a/lib/n65/directives/segment.rb b/lib/n65/directives/segment.rb index 4cf4d3d..cce79ee 100644 --- a/lib/n65/directives/segment.rb +++ b/lib/n65/directives/segment.rb @@ -1,13 +1,8 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### - ## This directive instruction can include a binary file class Segment < InstructionBase - - #### - ## Try to parse a dw directive def self.parse(line) match_data = line.match(/^.segment (prog|char) (\d+)$/i) unless match_data.nil? @@ -17,29 +12,20 @@ module N65 nil end - - #### - ## Initialize with filename + # Initialize with filename def initialize(segment, bank) @bank = bank @segment = segment end - - #### - ## Execute the segment and bank change on the assembler + # Execute the segment and bank change on the assembler def exec(assembler) assembler.current_segment = @segment assembler.current_bank = @bank end - - #### - ## Display def to_s ".segment #{@segment} #{@bank}" end - end - end diff --git a/lib/n65/directives/space.rb b/lib/n65/directives/space.rb index 94f1388..8fd88b9 100644 --- a/lib/n65/directives/space.rb +++ b/lib/n65/directives/space.rb @@ -1,46 +1,34 @@ +# frozen_string_literal: true + require_relative '../instruction_base' module N65 - - - #### ## This directive gives a symbolic name for memory and creates space for a variable in RAM class Space < InstructionBase - - #### - ## Try to parse a .space directive def self.parse(line) match_data = line.match(/^.space\s+([a-zA-Z]?[a-zA-Z0-9_]+?)\s+([0-9]+)$/) return nil if match_data.nil? - _, name, size = match_data.to_a + _, name, size = match_data.to_a Space.new(name, size.to_i) end - - #### - ## Initialize some memory space with a name + # Initialize some memory space with a name def initialize(name, size) @name = name @size = size end - - #### - ## .space creates a symbol at the current PC, and then advances PC by size + # .space creates a symbol at the current PC, and then advances PC by size def exec(assembler) program_counter = assembler.program_counter assembler.symbol_table.define_symbol(@name, program_counter) assembler.program_counter += @size end - - #### - ## Display + # Display def to_s ".space #{@name} #{@size}" end - end - end