Class: Coffeetags::Parser
Instance Attribute Summary (collapse)
-
- (Object) tree
readonly
Returns the value of attribute tree.
Instance Method Summary (collapse)
-
- (Object) execute!
Parse the @source and create a tags tree Coffeetags::Parser instance returns self, so it can be chained.
-
- (Coffeetags::Parser) initialize(source, include_vars = false)
constructor
Creates a new parser.
-
- (Object) item_for_regex(line, regex, level, additional_fields = {})
Helper function for generating parse tree elements for given line and regular expression.
-
- (Integer) line_level(line)
Detect current line level based on indentation very useful in parsing, since CoffeeScript's syntax depends on whitespace.
-
- (Object) mark_commented_lines
Mark line numbers as commented out either by single line comment (#) or block comments (###~###).
-
- (Object) scope_path(_el = nil, _tree = nil)
Generate current scope path, for example: e ->.
Constructor Details
- (Coffeetags::Parser) initialize(source, include_vars = false)
Creates a new parser
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/CoffeeTags/parser.rb', line 9 def initialize source, include_vars = false @include_vars = include_vars @source = source @fake_parent = 'window' # tree maps the ... tree :-) @tree = [] # regexes @block = /^\s*(if|unless|switch|loop|do)/ @class_regex = /^\s*class\s*([\w\.]*)/ @proto_meths = /^\s*([A-Za-z]*)::([@a-zA-Z0-9_]*)/ @var_regex = /([@a-zA-Z0-9_]*)\s*[=:]{1}\s*$/ @token_regex = /([@a-zA-Z0-9_]*)\s*[:=]{1}/ @iterator_regex = /^\s*for\s*([a-zA-Z0-9_]*)\s*/ @comment_regex = /^\s*#/ @block_comment_regex = /^\s*###/ @comment_lines = mark_commented_lines end |
Instance Attribute Details
- (Object) tree (readonly)
Returns the value of attribute tree
3 4 5 |
# File 'lib/CoffeeTags/parser.rb', line 3 def tree @tree end |
Instance Method Details
- (Object) execute!
this method mutates @tree instance variable of
Parse the @source and create a tags tree Coffeetags::Parser instance returns self, so it can be chained
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/CoffeeTags/parser.rb', line 106 def execute! line_n = 0 level = 0 @source.each_line do |line| line_n += 1 # indentify scopes level = line_level line # ignore comments! next if @comment_lines.include? line_n # extract elements for given line [ @class_regex, @proto_meths, @var_regex ].each do |regex| mt = item_for_regex line, regex, level @tree << mt unless mt.nil? end # does this line contain a block? mt = item_for_regex line, @block, level, :kind => 'b' @tree << mt unless mt.nil? # instance variable or iterator (for/in)? token = line.match(@token_regex ) token ||= line.match(@iterator_regex) # we have found something! if not token.nil? o = { :name => token[1], :level => level, :parent => '', :source => line.chomp, :line => line_n } # remove edge cases for now # - if a line containes a line like: element.getElement('type=[checkbox]').lol() is_in_string = line =~ /.*['"].*#{token[1]}.*=.*["'].*/ # - scope access and comparison in if x == 'lol' is_in_comparison = line =~ /::|==/ # - objects with blank parent (parser bug?) has_blank_parent = o[:parent] =~ /\.$/ # - multiple consecutive assignments is_previous_not_the_same = !(@tree.last and @tree.last[:name] == o[:name] and @tree.last[:level] == o[:level]) if is_in_string.nil? and is_in_comparison.nil? and has_blank_parent.nil? and is_previous_not_the_same o[:kind] = line =~ /[:=]{1}.*[-=]\>/ ? 'f' : 'o' o[:parent] = scope_path o o[:parent] = @fake_parent if o[:parent].empty? @tree << o if o[:kind] == 'f' @tree << o if o[:kind] == 'o' and @include_vars end end # get rid of duplicate entries @tree.uniq! self # chain! end end |
- (Object) item_for_regex(line, regex, level, additional_fields = {})
Helper function for generating parse tree elements for given line and regular expression
92 93 94 95 96 97 98 99 100 |
# File 'lib/CoffeeTags/parser.rb', line 92 def item_for_regex line, regex, level, additional_fields={} if item = line.match(regex) entry_for_item = { :name => item[1], :level => level } entry_for_item.merge(additional_fields) end end |
- (Integer) line_level(line)
Detect current line level based on indentation very useful in parsing, since CoffeeScript's syntax depends on whitespace
52 53 54 |
# File 'lib/CoffeeTags/parser.rb', line 52 def line_level line line.match(/^[ \t]*/)[0].gsub("\t", " ").split('').length end |
- (Object) mark_commented_lines
Mark line numbers as commented out either by single line comment (#) or block comments (###~###)
34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/CoffeeTags/parser.rb', line 34 def mark_commented_lines [].tap do |reg| in_block_comment = false @source.each_with_index do |line, index| line_no = index+1 in_block_comment = !(in_block_comment) if line =~ @block_comment_regex reg << line_no if in_block_comment reg << line_no if line =~ @comment_regex and not in_block_comment end end end |
- (Object) scope_path(_el = nil, _tree = nil)
Generate current scope path, for example: e ->
f ->
z ->
Scope path for function z would be: window.e.f
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/CoffeeTags/parser.rb', line 65 def scope_path _el = nil, _tree = nil bf = [] tree = (_tree || @tree) element = (_el || tree.last) idx = tree.index(element) || -1 current_level = element[:level] tree[0..idx].reverse.each_with_index do |item, index| # uhmmmmmm if item[:level] != current_level and item[:level] < current_level and item[:line] !~ @block bf << item[:name] unless item[:kind] == 'b' current_level = item[:level] end end bf.uniq.reverse.join('.') end |