Class: SpitewasteCLI
- Inherits:
-
Thor
- Object
- Thor
- SpitewasteCLI
- Defined in:
- lib/spitewaste/cli.rb,
lib/spitewaste/cli/asm.rb,
lib/spitewaste/cli/docs.rb,
lib/spitewaste/cli/exec.rb,
lib/spitewaste/cli/image.rb,
lib/spitewaste/cli/compile.rb,
lib/spitewaste/cli/convert.rb,
lib/spitewaste/cli/version.rb
Constant Summary collapse
- VALID_FORMATS =
%i[spw spitewaste ws whitespace wsa wsassembly asm assembly]
- CACHE_DIR =
File. '~/.cache/spitewaste'
Class Method Summary collapse
- .exit_on_failure? ⇒ Boolean
-
.handle_no_command_error(*args) ⇒ Object
TODO: Figure out how to invoke a command from this class method.
- .make_cache_path(name) ⇒ Object
- .shared_options ⇒ Object
- .validate_format(options) ⇒ Object
Instance Method Summary collapse
- #asm(input, output = '/dev/stdout') ⇒ Object
- #compile(file = nil) ⇒ Object
- #convert(input = '/dev/stdin', output = '/dev/stdout') ⇒ Object
- #docs(*terms) ⇒ Object
- #exec(input = '/dev/stdin') ⇒ Object
- #image(input, output = nil) ⇒ Object
- #version ⇒ Object
Class Method Details
.exit_on_failure? ⇒ Boolean
10 11 12 |
# File 'lib/spitewaste/cli.rb', line 10 def self.exit_on_failure? exit 1 end |
.handle_no_command_error(*args) ⇒ Object
TODO: Figure out how to invoke a command from this class method.
36 37 38 |
# File 'lib/spitewaste/cli.rb', line 36 def self.handle_no_command_error *args exec $0, 'exec', *args end |
.make_cache_path(name) ⇒ Object
48 49 50 51 52 |
# File 'lib/spitewaste/cli.rb', line 48 def self.make_cache_path name FileUtils.mkpath CACHE_DIR base = File.basename File.(name).tr(?/, ?-), '.*' File.join(CACHE_DIR, base[1..]) + '.json' end |
.shared_options ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/spitewaste/cli.rb', line 14 def self. option :format, desc: 'input format (in case auto-detection misguesses)', aliases: '-f' option :aliases, desc: 'augment or override one or more of the default instruction mnemonics [WIP]', banner: 'pop:drop...', type: :array, aliases: '-a' option :coexist, desc: <<DESC, allow multiple mnemonics to refer to the same instruction where possible [WIP] \e[1mNOTE: \e[0mIf --no-coexist (the default), aliases take precedence and render the original mnemonics invalid. DESC type: :boolean, aliases: '-x' end |
.validate_format(options) ⇒ Object
40 41 42 43 44 45 46 |
# File 'lib/spitewaste/cli.rb', line 40 def self.validate_format if fmt = [:format]&.to_sym and !VALID_FORMATS.include?(fmt) raise ArgumentError, "invalid format '#{fmt}'", [] end Hash[*VALID_FORMATS][fmt] || fmt # expand short names end |
Instance Method Details
#asm(input, output = '/dev/stdout') ⇒ Object
8 9 10 11 |
# File 'lib/spitewaste/cli/asm.rb', line 8 def asm input, output = '/dev/stdout' as = Spitewaste::Assembler.new File.read input File.open(output, ?w) { |of| as.assemble! format: :assembly, io: of } end |
#compile(file = nil) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/spitewaste/cli/compile.rb', line 44 def compile file = nil fmt = SpitewasteCLI.validate_format out = [:output] out ||= file ? File.basename(file, '.*') : 'a.out' file ||= '/dev/stdin' as = Spitewaste::Assembler.new File.read(file), format: fmt as.assemble! format: :codegen, io: cpp = StringIO.new cmd = "#{[:compiler]} -x c++ -o #{out} #{[:argv]} -" Open3.capture2 cmd, stdin_data: cpp.string if [:run] print `./#{out}` File.delete out unless [:keep] end end |
#convert(input = '/dev/stdin', output = '/dev/stdout') ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/spitewaste/cli/convert.rb', line 26 def convert input = '/dev/stdin', output = '/dev/stdout' ext = File.extname output Kernel.exec 'spw', 'image', input, output if ext == '.png' fmt = SpitewasteCLI.validate_format valid_outputs = %i[ws whitespace wsa wsassembly asm assembly cpp codegen] if out_fmt = [:output_format]&.to_sym and !valid_outputs.include?(out_fmt) raise ArgumentError, "invalid output format '#{out_fmt}'", [] end ext_map = { '.ws' => :whitespace, '.wsa' => :wsassembly, '.asm' => :assembly, '.cpp' => :codegen} out_fmt = Hash[*valid_outputs][out_fmt] || ext_map[ext] raise ArgumentError, "can't determine output format", [] unless out_fmt opts = .dup # options is frozen if opts[:symbol_file] == '%' opts[:symbol_file] = SpitewasteCLI.make_cache_path input end as = Spitewaste::Assembler.new File.read(input), format: fmt, **opts File.open(output, ?w) { |of| as.assemble! format: out_fmt, io: of } end |
#docs(*terms) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/spitewaste/cli/docs.rb', line 23 def docs *terms abort "need at least one search term" if terms.empty? docs = JSON.load File.read DOCS found = [] min = [:match_all] ? terms.size : 1 docs.each do |lib, fns| fns.each do |fn, data| full = "#{lib}/#{bold under fn} #{data['full']}" ms = terms.count { |t| full[/#{t}/i] } found << [lib, fn, full, ms] if ms >= min end end abort "no matches for terms: #{terms}" if found.empty? found.sort_by! { |v| -v[-1] } IO.popen('less -R', 'w') do |io| found.each do |lib, fn, full| full.gsub! /#{terms * ?|}/i, &method(:hi) desc, specs = full.split "\n\n" io.puts "#{?- * 10}\n#{desc}\n\n" io.puts specs if [:show_specs] end end end |
#exec(input = '/dev/stdin') ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/spitewaste/cli/exec.rb', line 21 def exec input = '/dev/stdin' fmt = SpitewasteCLI.validate_format raise LoadError, "No such file '#{input}'", [] unless File.exists? input opts = .dup # options is frozen if opts[:symbol_file] == '%' opts[:symbol_file] = SpitewasteCLI.make_cache_path input end if File.extname(input) != '.ws' io = Tempfile.new as = Spitewaste::Assembler.new File.read(input), format: fmt, **opts as.assemble! format: :whitespace, io: io input = io.tap(&:close).path end cmd = [:interpreter].split cmd.map! { |c| c == '%' ? input : c } Kernel.exec *cmd end |
#image(input, output = nil) ⇒ Object
46 47 48 49 50 51 52 53 54 |
# File 'lib/spitewaste/cli/image.rb', line 46 def image input, output = nil fmt = SpitewasteCLI.validate_format output ||= Pathname.new(input).sub_ext '.png' as = Spitewaste::Assembler.new File.read(input), format: fmt File.open(output, ?w) { |of| as.assemble! format: :image, io: of, **.transform_keys(&:to_sym) } end |
#version ⇒ Object
6 7 8 |
# File 'lib/spitewaste/cli/version.rb', line 6 def version puts "spw version #{Spitewaste::VERSION}" end |