fdlint 0.1.3 → 0.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -9
  3. data/Gemfile.lock +14 -4
  4. data/Rakefile +9 -85
  5. data/bin/fdlint +71 -8
  6. data/lib/fdlint/cli.rb +102 -0
  7. data/lib/{file_validator.rb → fdlint/file_validator.rb} +0 -0
  8. data/lib/fdlint/helper/code_type.rb +55 -0
  9. data/lib/fdlint/helper/file_reader.rb +19 -0
  10. data/lib/fdlint/helper/logger.rb +35 -0
  11. data/lib/fdlint/log_entry.rb +51 -0
  12. data/lib/fdlint/parser/base_parser.rb +151 -0
  13. data/lib/{css/parser.rb → fdlint/parser/css/css_parser.rb} +31 -28
  14. data/lib/{css → fdlint/parser/css}/struct.rb +5 -5
  15. data/lib/{encoding_error.rb → fdlint/parser/encoding_error.rb} +2 -2
  16. data/lib/{html/parser.rb → fdlint/parser/html/html_parser.rb} +26 -20
  17. data/lib/{html → fdlint/parser/html}/query.rb +0 -0
  18. data/lib/{html → fdlint/parser/html}/rule/check_tag_rule.rb +0 -0
  19. data/lib/{html → fdlint/parser/html}/struct.rb +82 -38
  20. data/lib/fdlint/parser/js/expr/expr.rb +71 -0
  21. data/lib/fdlint/parser/js/expr/left_hand.rb +65 -0
  22. data/lib/fdlint/parser/js/expr/operate.rb +94 -0
  23. data/lib/fdlint/parser/js/expr/primary.rb +168 -0
  24. data/lib/{js/parser.rb → fdlint/parser/js/js_parser.rb} +11 -9
  25. data/lib/fdlint/parser/js/stat/if.rb +27 -0
  26. data/lib/fdlint/parser/js/stat/iter.rb +88 -0
  27. data/lib/fdlint/parser/js/stat/stat.rb +120 -0
  28. data/lib/fdlint/parser/js/stat/switch.rb +67 -0
  29. data/lib/fdlint/parser/js/stat/try.rb +30 -0
  30. data/lib/fdlint/parser/js/stat/var.rb +42 -0
  31. data/lib/fdlint/parser/js/struct.rb +257 -0
  32. data/lib/fdlint/parser/node.rb +27 -0
  33. data/lib/fdlint/parser/parse_error.rb +10 -0
  34. data/lib/fdlint/parser/parser_visitable.rb +134 -0
  35. data/lib/{position_info.rb → fdlint/parser/position_info.rb} +12 -1
  36. data/lib/fdlint/parser.rb +3 -0
  37. data/lib/fdlint/printer/base_printer.rb +20 -0
  38. data/lib/fdlint/printer/console_printer.rb +80 -0
  39. data/lib/fdlint/printer/nocolor_printer.rb +29 -0
  40. data/lib/fdlint/printer/vim_printer.rb +21 -0
  41. data/lib/fdlint/printer.rb +1 -0
  42. data/lib/fdlint/rule/dsl.rb +83 -0
  43. data/lib/fdlint/rule/validation.rb +79 -0
  44. data/lib/fdlint/rule.rb +81 -0
  45. data/lib/fdlint/support/core/array.rb +5 -0
  46. data/lib/fdlint/support/core/file.rb +8 -0
  47. data/lib/fdlint/support/core/hash.rb +5 -0
  48. data/lib/fdlint/support/core/nil.rb +7 -0
  49. data/lib/fdlint/support/core/string.rb +7 -0
  50. data/lib/fdlint/support/core_ext.rb +5 -0
  51. data/lib/fdlint/validator.rb +102 -0
  52. data/lib/fdlint/version.rb +3 -0
  53. data/lib/fdlint.rb +5 -0
  54. data/rules.d/css.rule.rb +100 -0
  55. data/rules.d/filename.rule.rb +49 -0
  56. data/rules.d/html.rule.rb +169 -0
  57. data/rules.d/js.jquery.rule.rb +49 -0
  58. data/rules.d/js.rule.rb +205 -0
  59. data/test/default_test.rb +14 -0
  60. data/test/fixtures/js/scope-test.js +15 -2
  61. data/test/test_helper.rb +9 -0
  62. metadata +269 -221
  63. data/lib/base_parser.rb +0 -143
  64. data/lib/cmd_runner.rb +0 -145
  65. data/lib/context.rb +0 -31
  66. data/lib/css/reader.rb +0 -30
  67. data/lib/css/rule/check_compression_rule.rb +0 -48
  68. data/lib/css/rule/checklist.rb +0 -45
  69. data/lib/helper/code_type.rb +0 -50
  70. data/lib/helper/color_string.rb +0 -44
  71. data/lib/helper/file_reader.rb +0 -22
  72. data/lib/helper/strenc.rb +0 -65
  73. data/lib/js/expr/expr.rb +0 -66
  74. data/lib/js/expr/left_hand.rb +0 -63
  75. data/lib/js/expr/operate.rb +0 -92
  76. data/lib/js/expr/primary.rb +0 -166
  77. data/lib/js/rule/all.rb +0 -35
  78. data/lib/js/rule/checklist.rb +0 -41
  79. data/lib/js/rule/file_checker.rb +0 -42
  80. data/lib/js/rule/helper.rb +0 -96
  81. data/lib/js/rule/no_global.rb +0 -87
  82. data/lib/js/stat/if.rb +0 -25
  83. data/lib/js/stat/iter.rb +0 -85
  84. data/lib/js/stat/stat.rb +0 -117
  85. data/lib/js/stat/switch.rb +0 -65
  86. data/lib/js/stat/try.rb +0 -28
  87. data/lib/js/stat/var.rb +0 -40
  88. data/lib/js/struct.rb +0 -248
  89. data/lib/log_entry.rb +0 -49
  90. data/lib/node.rb +0 -28
  91. data/lib/parse_error.rb +0 -13
  92. data/lib/parser_visitable.rb +0 -138
  93. data/lib/printer/base_printer.rb +0 -24
  94. data/lib/printer/console_printer.rb +0 -66
  95. data/lib/printer/nocolor_printer.rb +0 -27
  96. data/lib/printer/vim_printer.rb +0 -19
  97. data/lib/rule.rb +0 -241
  98. data/lib/rule_helper.rb +0 -14
  99. data/lib/runner.rb +0 -225
  100. data/rules.d/css.rule +0 -127
  101. data/rules.d/html.dtd.rule +0 -22
  102. data/rules.d/html.prop.rule +0 -51
  103. data/rules.d/html.tag.rule +0 -136
  104. data/rules.d/js.file.rule +0 -13
  105. data/rules.d/js.jquery.rule +0 -56
  106. data/rules.d/js.mergefile.rule +0 -71
  107. data/rules.d/js.rule +0 -84
@@ -1,29 +1,31 @@
1
- require_relative '../base_parser'
2
1
  require_relative 'struct'
3
2
 
4
- module XRay
3
+ module Fdlint; module Parser
4
+
5
5
  module CSS
6
6
 
7
- class Parser < XRay::BaseParser
8
- TERM = %q([^;{}'"])
9
- TERM2 = %q([^;{}'",])
10
- QUOT_EXPR = "'[^']*'"
11
- DQUOT_EXPR = '"[^"]*"'
7
+ class CssParser < ::Fdlint::Parser::BaseParser
8
+
9
+ include ::Fdlint::Parser::ParserVisitable
12
10
 
13
- R_IDENT = /-?[_a-z][_a-z0-9-]*/
14
- R_ANY = %r"((?:#{TERM})|(?:#{QUOT_EXPR})|(?:#{DQUOT_EXPR}))+"
11
+ TERM = %q([^;{}'"])
12
+ TERM2 = %q([^;{}'",])
13
+ QUOT_EXPR = "'[^']*'"
14
+ DQUOT_EXPR = '"[^"]*"'
15
+ R_IDENT = /-?[_a-z][_a-z0-9-]*/
16
+ R_ANY = %r"((?:#{TERM})|(?:#{QUOT_EXPR})|(?:#{DQUOT_EXPR}))+"
15
17
  R_SELECTOR = %r"((?:#{TERM2})|(?:#{QUOT_EXPR})|(?:#{DQUOT_EXPR}))+"
16
18
  R_PROPERTY = /[*_+\\]?-?[_a-z\\][\\_a-z0-9-]*/
17
19
 
18
20
  attr_reader :comments
19
21
 
20
- def initialize(css, logger)
22
+ def initialize(css)
21
23
  super
22
24
  @comments = []
23
25
  end
24
26
 
25
27
  def parse_stylesheet(inner = false)
26
- log 'parse stylesheet'
28
+ debug { 'parse stylesheet' }
27
29
 
28
30
  do_parse_comment
29
31
 
@@ -39,7 +41,7 @@ module XRay
39
41
 
40
42
  # ruleset or directive
41
43
  def parse_statement
42
- log 'parse statement'
44
+ debug { 'parse statement' }
43
45
 
44
46
  if check /@/
45
47
  parse_directive
@@ -49,7 +51,7 @@ module XRay
49
51
  end
50
52
 
51
53
  def parse_directive
52
- log 'parse directive'
54
+ debug { 'parse directive' }
53
55
 
54
56
  skip /@/
55
57
  keyword = scan R_IDENT
@@ -69,14 +71,14 @@ module XRay
69
71
  skip /;/
70
72
  end
71
73
 
72
- log " keyword: #{keyword} #{keyword.position}"
73
- log(" expression: #{expr} #{expr.position}") if expr
74
- log(" block:\n#{block}\n#{block.position}") if block
74
+ debug { " keyword: #{keyword} #{keyword.position}" }
75
+ debug { " expression: #{expr} #{expr.position}" } if expr
76
+ debug { " block:\n#{block}\n#{block.position}" } if block
75
77
  Directive.new keyword, expr, block
76
78
  end
77
79
 
78
80
  def parse_ruleset
79
- log 'parse ruleset'
81
+ debug { 'parse ruleset' }
80
82
 
81
83
  selector = check(/\{/) ? nil : parse_selector
82
84
  skip /\{/
@@ -87,15 +89,15 @@ module XRay
87
89
  end
88
90
 
89
91
  def parse_selector
90
- log ' parse selector'
92
+ debug { ' parse selector' }
91
93
  simple_selectors = batch(:parse_simple_selector, /\{/, /,/)
92
94
  Selector.new simple_selectors
93
95
  end
94
96
 
95
97
  def parse_simple_selector
96
- log ' parse simple selector'
97
98
  selector = scan R_SELECTOR
98
- log " #{selector} #{selector.position}"
99
+ debug { ' parse simple selector' }
100
+ debug { " #{selector} #{selector.position}" }
99
101
  selector
100
102
  end
101
103
 
@@ -113,7 +115,7 @@ module XRay
113
115
  end
114
116
 
115
117
  def parse_declaration
116
- log ' parse declaration'
118
+ debug { ' parse declaration' }
117
119
 
118
120
  property = parse_property
119
121
  skip /:/
@@ -123,24 +125,24 @@ module XRay
123
125
  end
124
126
 
125
127
  def parse_property
126
- log ' parse property'
128
+ debug { ' parse property' }
127
129
  property = scan R_PROPERTY
128
- log " #{property} #{property.position}"
130
+ debug { " #{property} #{property.position}" }
129
131
  property
130
132
  end
131
133
 
132
134
  def parse_value
133
- log ' parse value'
135
+ debug { ' parse value' }
134
136
 
135
137
  value = scan R_ANY
136
- log " #{value} #{value.position}"
138
+ debug { " #{value} #{value.position}" }
137
139
  value
138
140
  end
139
141
 
140
142
  def parse_comment
141
- log 'pare comment'
143
+ debug { 'pare comment' }
142
144
  comment = raw_scan /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//
143
- log " #{comment}"
145
+ debug { " #{comment}" }
144
146
  comment
145
147
  end
146
148
 
@@ -183,4 +185,5 @@ module XRay
183
185
  end
184
186
 
185
187
  end
186
- end
188
+
189
+ end; end
@@ -1,8 +1,7 @@
1
- require_relative '../node'
2
-
3
- module XRay
1
+ module Fdlint; module Parser
4
2
  module CSS
5
- Node = XRay::Node
3
+
4
+ Node = ::Fdlint::Parser::Node
6
5
 
7
6
  class StyleSheet < Node
8
7
  attr_reader :statements
@@ -108,4 +107,5 @@ module XRay
108
107
  end
109
108
 
110
109
  end
111
- end
110
+
111
+ end; end
@@ -1,6 +1,6 @@
1
- module XRay
1
+ module Fdlint; module Parser
2
2
 
3
3
  class EncodingError < RuntimeError
4
4
  end
5
5
 
6
- end
6
+ end; end
@@ -1,11 +1,13 @@
1
- require_relative '../base_parser'
2
- require_relative '../css/parser'
3
- require_relative '../js/parser'
4
- require_relative 'struct'
1
+ require 'fdlint/parser/base_parser'
2
+ require 'fdlint/parser/css/css_parser'
3
+ require 'fdlint/parser/js/js_parser'
4
+ require 'fdlint/parser/html/struct'
5
5
 
6
- module XRay; module HTML
6
+ module Fdlint; module Parser; module HTML
7
7
 
8
- class Parser < BaseParser
8
+ class HtmlParser < ::Fdlint::Parser::BaseParser
9
+
10
+ include ::Fdlint::Parser::ParserVisitable
9
11
 
10
12
  def self.parse(src, &block)
11
13
  parser = self.new(src)
@@ -36,12 +38,13 @@ module XRay; module HTML
36
38
  when 0 then nil
37
39
  when 1 then nodes[0]
38
40
  else
39
- ::XRay::HTML::Document.new( nodes )
41
+ ::Fdlint::Parser::HTML::Document.new( nodes )
40
42
  end
41
43
  end
42
44
 
43
45
  def parse_element
44
46
  if @scanner.check(DTD) and !@dtd_checked
47
+ # only one DTD for one document
45
48
  @dtd_checked = true
46
49
  parse_dtd
47
50
  elsif @scanner.check(COMMENT)
@@ -49,7 +52,7 @@ module XRay; module HTML
49
52
  elsif @scanner.check(TAG_START)
50
53
  parse_tag
51
54
  elsif !text_end?
52
- parse_text
55
+ parse_text_tag
53
56
  else
54
57
  parse_error('Invalid HTML struct')
55
58
  end
@@ -65,8 +68,9 @@ module XRay; module HTML
65
68
  CommentElement.new(@scanner[1])
66
69
  end
67
70
 
68
- def parse_text
71
+ def parse_text_tag
69
72
  text = ''
73
+ pos = scanner_pos
70
74
  until text_end? do
71
75
  text << '<' if @scanner.skip(/</)
72
76
  text << "#{@scanner.scan(TEXT)}"
@@ -74,7 +78,9 @@ module XRay; module HTML
74
78
  # TODO: make this detection a rule
75
79
  parse_warn "'#{$~}' not escaped" if text =~ /<|>/
76
80
  end
77
- TextElement.new text
81
+ TextElement.new( text ).tap do |text|
82
+ text.position = pos
83
+ end
78
84
  end
79
85
 
80
86
  def parse_tag
@@ -137,7 +143,7 @@ module XRay; module HTML
137
143
  begin
138
144
  end_tag = %r(<#{tag.text.sub(/^(?!=\/)/, '\/')}>)i
139
145
  rescue
140
- raise ::XRay::ParseError.new("invalid tag name: #{tag.text}", scanner_pos)
146
+ raise ::Fdlint::Parser::ParseError.new("invalid tag name: #{tag.text}", scanner_pos)
141
147
  end
142
148
 
143
149
  if auto_close?(tag.text) and !@scanner.check(end_tag)
@@ -159,7 +165,7 @@ module XRay; module HTML
159
165
 
160
166
  scopes.pop
161
167
 
162
- el = Element.new(tag, prop, children, close_type, ending)
168
+ el = Tag.new(tag, prop, children, close_type, ending)
163
169
  el.scopes = scopes.dup
164
170
  el
165
171
  end
@@ -183,7 +189,7 @@ module XRay; module HTML
183
189
  end
184
190
 
185
191
  def auto_close?(tag)
186
- XRay::HTML::AUTO_CLOSE_TAGS.include?(tag.to_s.downcase)
192
+ Fdlint::Parser::HTML::AUTO_CLOSE_TAGS.include?(tag.to_s.downcase)
187
193
  end
188
194
 
189
195
  def text_end?
@@ -200,13 +206,13 @@ module XRay; module HTML
200
206
  end
201
207
 
202
208
 
203
- end; end
209
+ end; end; end
204
210
 
205
211
  if __FILE__ == $0
206
- XRay::HTML::Parser.parse(%q(<div class="info" checked>information</div>)) { |e| puts e.outer_html }
207
- XRay::HTML::Parser.parse(%q(<img width="100" height='150' id=img > <center>text</center>)) { |e| puts e.first.outer_html }
208
- XRay::HTML::Parser.parse(%q(<center><div><div><center>text</center></div></div></center>)) { |e| puts e.outer_html }
209
- XRay::HTML::Parser.parse(%q(<center ns:name="value"><div><div><center>text</center></div></div></center>)) { |e| puts e.outer_html }
210
- begin; XRay::HTML::Parser.parse(%q(<center><div></center></div>)) { |e| puts e.outer_html }; rescue; end
211
- XRay::HTML::Parser.parse('<br/>') { |e| puts e.outer_html }
212
+ Fdlint::Parser::HTML::HtmlParser.parse(%q(<div class="info" checked>information</div>)) { |e| puts e.outer_html }
213
+ Fdlint::Parser::HTML::HtmlParser.parse(%q(<img width="100" height='150' id=img > <center>text</center>)) { |e| puts e.first.outer_html }
214
+ Fdlint::Parser::HTML::HtmlParser.parse(%q(<center><div><div><center>text</center></div></div></center>)) { |e| puts e.outer_html }
215
+ Fdlint::Parser::HTML::HtmlParser.parse(%q(<center ns:name="value"><div><div><center>text</center></div></div></center>)) { |e| puts e.outer_html }
216
+ begin; Fdlint::Parser::HTML::HtmlParser.parse(%q(<center><div></center></div>)) { |e| puts e.outer_html }; rescue; end
217
+ Fdlint::Parser::HTML::HtmlParser.parse('<br/>') { |e| puts e.outer_html }
212
218
  end
File without changes
@@ -1,9 +1,8 @@
1
- require_relative '../node'
2
-
3
- module XRay
1
+ module Fdlint; module Parser
4
2
  module HTML
5
3
 
6
- Node = XRay::Node
4
+ Node = ::Fdlint::Parser::Node
5
+
7
6
  AUTO_CLOSE_TAGS = %w(area base basefont br col frame hr img input link meta param)
8
7
  INLINE_ELEMENTS = %w(a br label abbr legend address link
9
8
  area mark audio meter bm nav cite optgroup
@@ -11,21 +10,53 @@ module XRay
11
10
  command source datalist span em strong
12
11
  font sub i summary iframe sup img tbody
13
12
  input td ins time kbd var)
13
+ module Matchable
14
+ def =~ patten
15
+ if name
16
+ case patten
17
+ when String
18
+ name =~ Regexp.new("^#{patten}$", Regexp::IGNORECASE)
19
+ when Regexp
20
+ name =~ patten
21
+ end
22
+ end
23
+ end
24
+
25
+ alias_method :name_equal?, :=~
26
+
27
+ end
28
+
14
29
 
15
30
  class Element < Node
16
31
 
32
+ include Matchable
33
+
17
34
  attr_reader :tag, :props, :children
18
- attr_accessor :parent, :close_type, :ending, :scopes
35
+ attr_accessor :position, :parent, :close_type, :ending, :scopes
19
36
 
20
37
  def initialize(tag, props=[], children=[], close_type=:after, ending=nil)
21
- @tag, @props, @children, @close_type, @ending = tag, to_props(props), Array.[](children).flatten || [], close_type, ending
22
- @position = @tag.position.dup if tag.is_a?(Node) and tag.position
23
- @children.each { |el| el.parent = self }
38
+
39
+ @tag, @close_type, @ending = tag, close_type, ending
40
+ @props = to_props( props )
24
41
  @scopes = []
42
+
43
+ if tag.respond_to?( :position ) and tag.position
44
+ @position = @tag.position.dup
45
+ end
46
+
47
+ @children = (Array.[](children).flatten || []).tap do |children|
48
+ children.each do |child|
49
+ child.parent = self
50
+ end
51
+ end
25
52
  end
26
53
 
27
54
  def has_scope?
28
- !(parent.nil? and @scopes.empty?)
55
+ !top_level?
56
+ end
57
+
58
+ def top_level?
59
+ parent.nil? and @scopes.empty?
29
60
  end
30
61
 
31
62
  def in_scope?(scp)
@@ -37,19 +68,13 @@ module XRay
37
68
  end
38
69
 
39
70
  def text
40
- children.inject("") do |s,child|
41
- s + child.text
42
- end
71
+ children.inject("") { |s,child| s + child.text }
43
72
  end
44
73
 
45
74
  def tag_name
46
75
  @tag.is_a?(Node) ? @tag.text : @tag.to_s
47
76
  end
48
77
 
49
- def tag_name_equal?(name)
50
- tag_name.downcase == name.downcase
51
- end
52
-
53
78
  def inner_html
54
79
  @children.inject('') { |s,c| s + c.outer_html }
55
80
  end
@@ -98,6 +123,10 @@ module XRay
98
123
  end
99
124
  end
100
125
 
126
+ def [] name
127
+ prop_value(name)
128
+ end
129
+
101
130
  def to_s
102
131
  "[HTML: #{outer_html}]"
103
132
  end
@@ -111,7 +140,7 @@ module XRay
111
140
  end
112
141
 
113
142
  def closed?
114
- @close_type != :none
143
+ auto_close? && !self_closed? || @close_type != :none
115
144
  end
116
145
 
117
146
  def self_closed?
@@ -126,30 +155,41 @@ module XRay
126
155
  false
127
156
  end
128
157
 
129
- protected
130
- def parse(text)
131
- @outer_html = text
158
+ def stylesheet_link?
159
+ self =~ 'link' && self['rel'] =~ /stylesheet/i
132
160
  end
133
161
 
162
+ protected
163
+
164
+ def parse(text)
165
+ @outer_html = text
166
+ end
167
+
134
168
  private
135
169
 
136
- def to_props(src)
137
- case src
138
- when Array
139
- src
140
- when Hash
141
- src.map do |n, v|
142
- Property.new(n, v)
170
+ def to_props(src)
171
+ case src
172
+ when Array
173
+ src
174
+ when Hash
175
+ src.map do |n, v|
176
+ Property.new(n, v)
177
+ end
178
+ else
179
+ []
143
180
  end
144
- else
145
- []
146
- end
147
- end
181
+ end
148
182
 
149
183
  end
150
184
 
185
+ class Tag < Element
186
+ include Matchable
187
+
188
+ alias_method :name, :tag_name
189
+ end
190
+
191
+ class Document < Tag
151
192
 
152
- class Document < Element
153
193
  def initialize( children=[] )
154
194
  super(nil, {}, children || [])
155
195
  @position = Position.new(0,0,0)
@@ -169,9 +209,15 @@ module XRay
169
209
  children.empty?
170
210
  end
171
211
 
212
+ def has_dtd?
213
+ !empty? && children.first.is_a?( DTDElement )
214
+ end
215
+
216
+ alias_method :have_dtd?, :has_dtd?
217
+
172
218
  end
173
219
 
174
- class TextElement < Element
220
+ class TextElement < Tag
175
221
 
176
222
  def initialize(text="")
177
223
  super(nil)
@@ -263,6 +309,8 @@ module XRay
263
309
 
264
310
  class Property < Node
265
311
 
312
+ include Matchable
313
+
266
314
  attr_reader :name, :sep
267
315
  attr_accessor :value
268
316
 
@@ -272,10 +320,6 @@ module XRay
272
320
 
273
321
  def position; name.position; end
274
322
 
275
- def name_equal?(text)
276
- @name.to_s.downcase == text.to_s.downcase
277
- end
278
-
279
323
  def to_s
280
324
  if value.nil?
281
325
  name.to_s
@@ -288,4 +332,4 @@ module XRay
288
332
 
289
333
 
290
334
  end
291
- end
335
+ end; end
@@ -0,0 +1,71 @@
1
+ require 'fdlint/parser/js/expr/primary'
2
+ require 'fdlint/parser/js/expr/left_hand'
3
+ require 'fdlint/parser/js/expr/operate'
4
+
5
+
6
+ module Fdlint
7
+ module Parser
8
+ module JS
9
+ module Expr
10
+
11
+ module Expr
12
+
13
+ include ::Fdlint::Parser::JS::Expr::Primary
14
+ include ::Fdlint::Parser::JS::Expr::LeftHand
15
+ include ::Fdlint::Parser::JS::Expr::Operate
16
+
17
+ def parse_expression
18
+ log 'parse expression'
19
+ parse_expr_with_operate :parse_expr_assignment, /,/
20
+ end
21
+
22
+ def parse_expr_assignment
23
+ log 'parse expr assignment'
24
+
25
+ expr = parse_expr_condition
26
+
27
+ r = /=|\*=|\/=|%=|\+=|-=|<<=|>>=|>>>=|&=|\^=|\|=/
28
+ if expr.left_hand? && check(r)
29
+ op = scan r
30
+ expr = create_element Expression, op.text, expr, parse_expr_assignment
31
+ end
32
+ expr
33
+ end
34
+
35
+ def parse_expr_condition
36
+ log 'parse expr condition'
37
+ expr = parse_expr_logical_or
38
+ if check /\?/
39
+ skip /\?/
40
+ left = parse_expr_assignment
41
+ skip /:/
42
+ right = parse_expr_assignment
43
+
44
+ expr = create_element ConditionExpression, expr, left, right
45
+ end
46
+ expr
47
+ end
48
+
49
+ def parse_expr_with_operate(left, pattern = nil, &block)
50
+ block = block || lambda {
51
+ if check pattern
52
+ skip_empty
53
+ before_pos = scanner_pos
54
+ op = scan pattern
55
+ [op.text, self.send(left), before_pos]
56
+ end
57
+ }
58
+
59
+ expr = self.send left
60
+ while (ret = block.call)
61
+ expr = create_element Expression, ret[0], expr, ret[1], ret[2]
62
+ end
63
+ expr
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,65 @@
1
+ module Fdlint
2
+ module Parser
3
+ module JS
4
+ module Expr
5
+
6
+ module LeftHand
7
+
8
+ def parse_expr_lefthand
9
+ log 'parse expr lefthand'
10
+ expr = check(/new\b/) ? parse_expr_new : parse_expr_member
11
+ expr.left_hand = true
12
+ expr
13
+ end
14
+
15
+ def parse_expr_new
16
+ log 'parse expr new'
17
+
18
+ pos = skip /new/
19
+ expr = check(/new\b/) ? parse_expr_new : parse_expr_member
20
+ args = check(/\(/) ? parse_arguments_list : nil
21
+
22
+ create_element Expression, 'new', expr, args, pos
23
+ end
24
+
25
+ def parse_expr_member
26
+ log 'parse expr member'
27
+ parse_expr_with_operate(:parse_expr_member_left) do
28
+ if check /[.]/
29
+ skip /[.]/
30
+ ['.', parse_expr_identifier]
31
+ elsif check /[\[]/
32
+ skip /\[/
33
+ expr = parse_expression
34
+ skip /\]/
35
+ ['[', expr]
36
+ elsif check /\(/
37
+ ['(', parse_arguments_list]
38
+ end
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ def parse_expr_member_left
45
+ if check /function\b/
46
+ create_element FunctionExpression, parse_function_declaration(true)
47
+ else
48
+ parse_expr_primary
49
+ end
50
+ end
51
+
52
+
53
+ def parse_arguments_list
54
+ log 'parse arguments list'
55
+ skip /\(/
56
+ params = batch :parse_expr_assignment, /\)/, /,/
57
+ skip /\)/
58
+ Elements.new params
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end