# Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net> # A CodeRay Scanner for YARV # FIXME: add unit test. require 'rubygems' require 'coderay' module CodeRay module Scanners class YARV < Scanner register_for :yarv file_extension 'yarv' def string_parse(tokens) if match = scan(/^"[^"]*"/) string = match.dup while "\\" == match[-2..-2] match = scan(/^.*"/) break unless match string << match end tokens << [string, :string] true else false end end def space_parse(tokens) if match = scan(/^[ \t]*/) tokens << [match, :space] if match end end def scan_tokens(tokens, options) state = :initial number_expected = true until eos? kind = nil match = nil case state when :initial if match = scan(/^\s*/) tokens << [match, :space] unless match.empty? end state = if match = scan(/^$/) :initial else :expect_label end when :expect_label state = if match = scan(/\d+/x) tokens << [match, :label] :expect_opcode else match = scan(/^.*$/) tokens << [match, :error] :initial end when :expect_opcode state = if match = scan(/(\s+)(\S+)/) match =~ /(\s+)(\S+)/ tokens << [$1, :space] opcode = $2 tokens << [opcode, :reserved] :expect_operand else match = scan(/^(.*)$/) tokens << [match, :error] :initial end when :expect_literal space_parse(tokens) if match = scan(/^#<.+>/) tokens << [match, :content] elsif match = scan(/^(\d+)/) tokens << [match, :integer] elsif match = scan(/^([:][^: ,\n]+)/) tokens << [match, :symbol] elsif string_parse(tokens) # elsif match = scan(/nil|true|false/) tokens << [match, :pre_constant] elsif match = scan(/\/.*\//) tokens << [match, :entity] else match = scan(/^.*$/) tokens << [match, :error] unless match.empty? end state = :expect_opt_lineno when :expect_operand space_parse(tokens) state = :expect_another_operand if match = scan(/^(\d+)/) tokens << [match, :integer] if match = scan(/^[.]{2}\d+/) tokens << ['..', :operator] tokens << [match[2..-1], :integer] end elsif match = scan(/\/.*\//) # Really a regular expression tokens << [match, :entity] elsif match = scan(/^([:][^: ,\n]+)/) tokens << [match, :symbol] elsif match = scan(/^([$][^ ,\n]+)/) tokens << [match, :global_variable] elsif match = scan(/nil|true|false/) tokens << [match, :pre_constant] elsif match = scan(/nil|true|false/) tokens << [match, :pre_constant] elsif match = scan(/block in (?:<.+>|[^,]+)/) tokens << ["block in ", :variable] tokens << [match['block in '.size..-1], :content] elsif match = scan(/[A-Za-z_][_A-Za-z0-9?!]*/) tokens << [match, :variable] elsif match = scan(/^#[^, \n]*/) tokens << [match, :content] elsif match = scan(/^<.+>/) tokens << [match, :content] elsif string_parse(tokens) else state = :expect_opt_lineno end when :expect_another_operand state = if match = scan(/^,/) tokens << [match, :operator] :expect_operand else :expect_opt_lineno end when :expect_opt_lineno space_parse(tokens) if match = scan(/^\(\s+\d+\)$/) tokens << [match, :comment] else match = scan(/^.*$/) tokens << [match, :error] unless match.empty? end state = :initial end end tokens end end end end if __FILE__ == $0 require 'term/ansicolor' ruby_scanner = CodeRay.scanner :yarv string=' 0000 trace 1 ( 9) 0002 putnil 0003 putstring "irb" 0005 send :require, 1, nil, 8, <ic:0> 0011 pop 0012 trace 1 ( 11) 0014 putstring "/usr/local/bin/irb" 0016 getglobal $0 0018 opt_eq <ic:8> 0020 branchunless 41 0022 trace 1 ( 12) 0024 getinlinecache 31, <ic:2> 0027 getconstant :IRB 0029 setinlinecache <ic:2> 0031 putstring "/usr/local/bin/irb" 0033 send :start, 1, nil, 0, <ic:3> 0026 putobject 0..1 0030 send :map, 0, block in <top gcd.rb>, 0, <ic:3> 0177 send :catch, 1, block in start, 8, <ic:23> 0045 opt_regexpmatch1 /^-e$/ ' yarv_scanner = CodeRay.scanner :yarv tokens = yarv_scanner.tokenize(string) p tokens yarv_highlighter = CodeRay::Duo[:yarv, :term] puts yarv_highlighter.encode(string) end