Class: Kapusta::LSP::ScopeWalker

Inherits:
Object
  • Object
show all
Defined in:
lib/kapusta/lsp/scope_walker.rb

Defined Under Namespace

Classes: Binding, EndMarker, Reference, Scope

Constant Summary collapse

SKIPPED_HEADS =
%w[macros quasi-sym quasi-list
quasi-list-tail quasi-vec quasi-vec-tail quasi-hash quasi-gensym].freeze
DISPATCHERS =
{
  'let' => :walk_let,
  'local' => :walk_local_var,
  'var' => :walk_local_var,
  'global' => :walk_global,
  'set' => :walk_set,
  'fn' => :walk_fn,
  'defn' => :walk_fn,
  'lambda' => :walk_fn,
  'λ' => :walk_fn,
  'for' => :walk_for,
  'each' => :walk_each_like,
  'collect' => :walk_each_like,
  'icollect' => :walk_each_like,
  'fcollect' => :walk_for_like,
  'accumulate' => :walk_accumulate,
  'faccumulate' => :walk_faccumulate,
  'case' => :walk_case_match,
  'match' => :walk_case_match,
  'try' => :walk_try,
  'module' => :walk_module_class,
  'class' => :walk_module_class,
  'hashfn' => :walk_hashfn,
  'macro' => :walk_macro_def,
  'import-macros' => :walk_import_macros,
  'ivar' => :walk_sigil_form,
  'cvar' => :walk_sigil_form,
  'gvar' => :walk_sigil_form
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeScopeWalker

Returns a new instance of ScopeWalker.



61
62
63
64
65
66
67
68
69
70
# File 'lib/kapusta/lsp/scope_walker.rb', line 61

def initialize
  @bindings = []
  @references = []
  @end_markers = []
  @scope_seq = 0
  @root_scope = make_scope(nil, :file)
  @gvar_scope = make_scope(nil, :gvars)
  @in_module_or_class = 0
  @sigil_scope_stack = [make_sigil_scopes]
end

Instance Attribute Details

#bindingsObject (readonly)

Returns the value of attribute bindings.



53
54
55
# File 'lib/kapusta/lsp/scope_walker.rb', line 53

def bindings
  @bindings
end

#end_markersObject (readonly)

Returns the value of attribute end_markers.



53
54
55
# File 'lib/kapusta/lsp/scope_walker.rb', line 53

def end_markers
  @end_markers
end

#referencesObject (readonly)

Returns the value of attribute references.



53
54
55
# File 'lib/kapusta/lsp/scope_walker.rb', line 53

def references
  @references
end

#root_scopeObject (readonly)

Returns the value of attribute root_scope.



53
54
55
# File 'lib/kapusta/lsp/scope_walker.rb', line 53

def root_scope
  @root_scope
end

Class Method Details

.analyze(forms) ⇒ Object



55
56
57
58
59
# File 'lib/kapusta/lsp/scope_walker.rb', line 55

def self.analyze(forms)
  walker = new
  walker.walk_top(forms)
  walker
end

Instance Method Details

#binding_at(line, column) ⇒ Object



112
113
114
115
116
117
# File 'lib/kapusta/lsp/scope_walker.rb', line 112

def binding_at(line, column)
  @bindings.each do |b|
    return b if b.line == line && column >= b.column && column <= b.end_column
  end
  nil
end

#end_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/kapusta/lsp/scope_walker.rb', line 108

def end_form?(form)
  form.is_a?(List) && !form.empty? && form.head.is_a?(Sym) && form.head.name == 'end'
end

#record_end_marker(form, target) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/kapusta/lsp/scope_walker.rb', line 96

def record_end_marker(form, target)
  head = form.head
  return unless head.is_a?(Sym) && head.respond_to?(:line) && head.line

  @end_markers << EndMarker.new(
    line: head.line,
    column: head.column,
    end_column: head.column + head.name.length,
    target:
  )
end

#reference_at(line, column) ⇒ Object



119
120
121
122
123
124
# File 'lib/kapusta/lsp/scope_walker.rb', line 119

def reference_at(line, column)
  @references.each do |r|
    return r if r.line == line && column >= r.column && column <= r.end_column
  end
  nil
end

#sym_at(line, column) ⇒ Object



126
127
128
# File 'lib/kapusta/lsp/scope_walker.rb', line 126

def sym_at(line, column)
  binding_at(line, column) || reference_at(line, column)
end

#walk_form_run(forms, start, scope, header_target: nil) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/kapusta/lsp/scope_walker.rb', line 76

def walk_form_run(forms, start, scope, header_target: nil)
  i = start
  while i < forms.length
    form = forms[i]
    if end_form?(form)
      record_end_marker(form, header_target) if header_target
      return i + 1
    end

    if bodyless_header?(form)
      i = walk_bodyless_header(form, forms, i + 1, scope)
      next
    end

    walk_form(form, scope)
    i += 1
  end
  i
end

#walk_top(forms) ⇒ Object



72
73
74
# File 'lib/kapusta/lsp/scope_walker.rb', line 72

def walk_top(forms)
  walk_form_run(forms, 0, @root_scope)
end