Class: Iro::Ruby::Parser

Inherits:
Base
  • Object
show all
Defined in:
lib/iro/ruby/parser.rb

Constant Summary collapse

EVENT_NAME_TO_HIGHLIGT_NAME =
{
  tstring_content: 'String',
  CHAR: 'Character',
  int: 'Number',
  float: 'Float',
  
  comment: 'Comment',
  embdoc: 'Comment',
  embdoc_beg: 'Comment',
  embdoc_end: 'Comment',

  regexp_beg: 'Delimiter',
  regexp_end: 'Delimiter',
  heredoc_beg: 'Delimiter',
  heredoc_end: 'Delimiter',
  tstring_beg: 'Delimiter',
  tstring_end: 'Delimiter',
  qwords_beg: 'Delimiter', # For `**%w[**foo]`
  words_sep: 'Delimiter', # For `%w[foo**]**` in Ruby 2.4 or older
  embexpr_beg: 'Delimiter',
  embexpr_end: 'Delimiter',
  backtick: 'Delimiter',

  symbeg: 'rubySymbolDelimiter',

  ivar: 'rubyInstanceVariable',
  cvar: 'rubyClassVariable',
  gvar: 'rubyGlobalVariable',
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

Returns a new instance of Parser.



48
49
50
51
52
# File 'lib/iro/ruby/parser.rb', line 48

def initialize(*)
  super
  @tokens = {}
  @end_stack = []
end

Instance Attribute Details

#tokensObject (readonly)

Returns the value of attribute tokens.



46
47
48
# File 'lib/iro/ruby/parser.rb', line 46

def tokens
  @tokens
end

Class Method Details

.tokens(source) ⇒ Object



194
195
196
197
198
# File 'lib/iro/ruby/parser.rb', line 194

def self.tokens(source)
  parser = self.new(source)
  parser.parse
  parser.tokens
end

Instance Method Details

#highlight_end_as(group) ⇒ Object



72
73
74
# File 'lib/iro/ruby/parser.rb', line 72

def highlight_end_as(group)
  register_scanner_event group, @end_stack.pop
end

#highlight_keyword_like_method(ident) ⇒ Object



183
184
185
186
187
188
189
190
191
192
# File 'lib/iro/ruby/parser.rb', line 183

def highlight_keyword_like_method(ident)
  case ident.content
  when 'private', 'public', 'protected', 'private_class_method',
       'attr_reader', 'attr_writer', 'attr_accessor', 'attr',
       'include', 'extend', 'prepend', 'module_function', 'refine', 'using',
       'raise', 'fail', 'catch', 'throw',
       'require', 'require_relative'
    register_scanner_event 'Keyword', ident # TODO: Change highlight group
  end
end

#kw_group(str) ⇒ Object



121
122
123
124
125
126
# File 'lib/iro/ruby/parser.rb', line 121

def kw_group(str)
  {
    'def' => 'rubyDefine',
    'alias' => 'rubyDefine',
  }[str] || 'Keyword'
end

#on_command(ident, _) ⇒ Object



179
180
181
# File 'lib/iro/ruby/parser.rb', line 179

def on_command(ident, _)
  highlight_keyword_like_method(ident)
end

#on_def(name, params, body) ⇒ Object



128
129
130
131
132
133
# File 'lib/iro/ruby/parser.rb', line 128

def on_def(name, params, body)
  unhighlight! name if name.kw_type?
  register_scanner_event 'rubyFunction', name
  highlight_end_as 'rubyDefine'
  nil
end

#on_defs(recv, period, name, params, body) ⇒ Object



135
136
137
138
139
140
# File 'lib/iro/ruby/parser.rb', line 135

def on_defs(recv, period, name, params, body)
  unhighlight! name if name.kw_type?
  register_scanner_event 'rubyFunction', name
  highlight_end_as 'rubyDefine'
  nil
end

#on_fcall(ident) ⇒ Object



171
172
173
# File 'lib/iro/ruby/parser.rb', line 171

def on_fcall(ident)
  highlight_keyword_like_method(ident)
end

#on_kw(str) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/iro/ruby/parser.rb', line 102

def on_kw(str)
  super.tap do |result|
    if str == 'end'
      @end_stack << result
    else
      group = kw_group(str)
      register_token group, [lineno, column+1, str.bytesize]
    end
  end
end

#on_label(str) ⇒ Object

foo: bar ^^^ rubySymbol

^ no highlight


116
117
118
119
# File 'lib/iro/ruby/parser.rb', line 116

def on_label(str)
  register_token 'rubySymbol', [lineno, column+1, str.bytesize-1]
  super
end

#on_symbol(node) ⇒ Object



142
143
144
145
146
# File 'lib/iro/ruby/parser.rb', line 142

def on_symbol(node)
  unhighlight! node if node.gvar_type? || node.ivar_type? || node.cvar_type? || node.kw_type?
  register_scanner_event 'rubySymbol', node
  nil
end

#on_top_const_ref(name) ⇒ Object Also known as: on_const_ref, on_const_path_ref, on_const_path_field



163
164
165
166
# File 'lib/iro/ruby/parser.rb', line 163

def on_top_const_ref(*, name)
  register_scanner_event 'Type', name
  nil
end

#on_var_field(name) ⇒ Object



158
159
160
161
# File 'lib/iro/ruby/parser.rb', line 158

def on_var_field(name)
  register_scanner_event 'Type', name if name.const_type?
  nil
end

#on_var_ref(name) ⇒ Object



148
149
150
151
152
153
154
155
156
# File 'lib/iro/ruby/parser.rb', line 148

def on_var_ref(name)
  case name.type
  when :@ident
    register_scanner_event 'rubyLocalVariable', name
  when :@const
    register_scanner_event 'Type', name
  end
  nil
end

#on_vcall(ident) ⇒ Object



175
176
177
# File 'lib/iro/ruby/parser.rb', line 175

def on_vcall(ident)
  highlight_keyword_like_method(ident)
end

#parseObject



54
55
56
57
58
59
# File 'lib/iro/ruby/parser.rb', line 54

def parse
  super
  @end_stack.each do |end_kw|
    register_scanner_event 'Keyword', end_kw
  end
end

#register_scanner_event(group, event) ⇒ Object

TODO: Maybe multiline support is needed.



67
68
69
70
# File 'lib/iro/ruby/parser.rb', line 67

def register_scanner_event(group, event)
  pos = event.position
  register_token group, [pos[0], pos[1]+1, event.content.bytesize]
end

#register_token(group, token) ⇒ Object



61
62
63
64
# File 'lib/iro/ruby/parser.rb', line 61

def register_token(group, token)
  @tokens[group] ||= []
  @tokens[group] << token
end

#unhighlight!(scanner_event) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/iro/ruby/parser.rb', line 76

def unhighlight!(scanner_event)
  t = scanner_event.type[1..-1].to_sym
  group = EVENT_NAME_TO_HIGHLIGT_NAME[t] ||
    (scanner_event.kw_type? && kw_group(scanner_event.content))
  raise 'bug' unless group

  t = scanner_event.position + [scanner_event.content.bytesize]
  t[1] += 1
  @tokens[group].reject! { |ev| ev == t }
  @end_stack.reject!{|e| e == scanner_event} if scanner_event.kw_type? && scanner_event.content == 'end'
end