js2 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog +0 -0
- data/History.txt +4 -0
- data/LICENSE +0 -0
- data/Manifest.txt +43 -0
- data/PostInstall.txt +7 -0
- data/README +0 -0
- data/README.rdoc +48 -0
- data/Rakefile +42 -0
- data/bin/js2 +61 -0
- data/examples/js2.yml +8 -0
- data/examples/test.yml +5 -0
- data/lib/javascript/sel_marker.js2 +139 -0
- data/lib/javascript/test.js2 +73 -0
- data/lib/js2/ast/class_node.rb +105 -0
- data/lib/js2/ast/comment_node.rb +2 -0
- data/lib/js2/ast/haml_node.rb +22 -0
- data/lib/js2/ast/include_node.rb +11 -0
- data/lib/js2/ast/inherited_node.rb +7 -0
- data/lib/js2/ast/member_node.rb +18 -0
- data/lib/js2/ast/method_node.rb +29 -0
- data/lib/js2/ast/module_node.rb +6 -0
- data/lib/js2/ast/node.rb +14 -0
- data/lib/js2/ast/nodes.rb +123 -0
- data/lib/js2/ast/stuff_node.rb +6 -0
- data/lib/js2/config.rb +34 -0
- data/lib/js2/daemon.rb +35 -0
- data/lib/js2/decorator/app.rb +7 -0
- data/lib/js2/decorator/cleanser.rb +54 -0
- data/lib/js2/decorator/standard.rb +127 -0
- data/lib/js2/decorator/test.rb +148 -0
- data/lib/js2/parser/fast.rb +3959 -0
- data/lib/js2/parser/haml.rb +123 -0
- data/lib/js2/process/file_handler.rb +84 -0
- data/lib/js2/process/haml_engine.rb +19 -0
- data/lib/js2/process/universe.rb +57 -0
- data/lib/js2/processor.rb +150 -0
- data/lib/js2/test/selenium.rb +111 -0
- data/lib/js2/test/selenium_element.rb +220 -0
- data/lib/js2/test/selenium_helper.rb +27 -0
- data/lib/js2.rb +95 -0
- data/lib/tasks/js2.rake +9 -0
- data/meta/c_tokenizer.rl.erb +322 -0
- data/meta/replace.rb +126 -0
- metadata +110 -0
@@ -0,0 +1,220 @@
|
|
1
|
+
class JS2::Test::SeleniumElement
|
2
|
+
attr_accessor :options
|
3
|
+
QUICK_WAIT_FOR = 5
|
4
|
+
AJAX_TIME_OUT = 60
|
5
|
+
def initialize (sel, klass, key, selector = nil)
|
6
|
+
@sel = sel
|
7
|
+
@key = key
|
8
|
+
@klass = klass
|
9
|
+
@selector = selector
|
10
|
+
end
|
11
|
+
|
12
|
+
def log (str)
|
13
|
+
if JS2::Test::Selenium.logger
|
14
|
+
JS2::Test::Selenium.logger.info(str)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def raw
|
19
|
+
ret = self.class.new(@sel, @klass, @key, @selector)
|
20
|
+
ret.options[:raw] = true
|
21
|
+
return ret
|
22
|
+
end
|
23
|
+
|
24
|
+
def check
|
25
|
+
return execute('checked=true')
|
26
|
+
end
|
27
|
+
|
28
|
+
def uncheck
|
29
|
+
return execute('checked=false')
|
30
|
+
end
|
31
|
+
|
32
|
+
def checked?
|
33
|
+
return execute('checked')
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute (str)
|
37
|
+
wait_for_ajax
|
38
|
+
return @sel.execute(get_js_locator() + '.' + str)
|
39
|
+
end
|
40
|
+
|
41
|
+
def visible?(wait_for = nil)
|
42
|
+
return self.check_attribute(':visible', true, wait_for);
|
43
|
+
end
|
44
|
+
|
45
|
+
def sel_visible?()
|
46
|
+
return @sel.visible?(get_ele())
|
47
|
+
end
|
48
|
+
|
49
|
+
def hidden?(wait_for = nil)
|
50
|
+
return self.check_attribute(':visible', false, wait_for);
|
51
|
+
end
|
52
|
+
|
53
|
+
def find (str, idx = 0)
|
54
|
+
selector = "window.$(#{get_js_locator()}).find(#{str.to_json})[#{idx}]"
|
55
|
+
return self.class.new(@sel, @klass, @key, selector)
|
56
|
+
end
|
57
|
+
|
58
|
+
def filter (str, idx = 0)
|
59
|
+
selector = "window.$(#{get_js_locator()}).filter(#{str.to_json})[#{idx}]"
|
60
|
+
return self.class.new(@sel, @klass, @key, selector)
|
61
|
+
end
|
62
|
+
|
63
|
+
def get (idx)
|
64
|
+
# when jqObjects in //@+
|
65
|
+
selector = "#{get_js_locator()}[#{idx}][0]"
|
66
|
+
return self.class.new(@sel, @klass, @key, selector)
|
67
|
+
end
|
68
|
+
|
69
|
+
def [] (idx)
|
70
|
+
selector = "#{get_js_locator()}[#{idx}]"
|
71
|
+
return self.class.new(@sel, @klass, @key, selector)
|
72
|
+
end
|
73
|
+
|
74
|
+
def attr (attr)
|
75
|
+
get_ele()
|
76
|
+
js = %{return window.$(#{get_js_locator()}).attr(#{attr.to_json});}
|
77
|
+
return @sel.js_eval(js)
|
78
|
+
end
|
79
|
+
|
80
|
+
def check_attribute (attr, val, wait_for = nil)
|
81
|
+
wait_for ||= QUICK_WAIT_FOR
|
82
|
+
get_ele()
|
83
|
+
js = %{window.$(#{get_js_locator()}).is('#{attr}') == #{val.to_json};}
|
84
|
+
begin
|
85
|
+
log "Waiting for #{@key}.#{attr} to be #{val.to_json}... Waiting #{wait_for} secs."
|
86
|
+
@sel.wait_for_condition(js, wait_for)
|
87
|
+
rescue Selenium::CommandError
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
|
94
|
+
def containsp? (str)
|
95
|
+
wait_for_ajax
|
96
|
+
js = %{window.$(#{get_js_locator()}).html().toLowerCase().indexOf(#{str.to_json.downcase}) >= 0;}
|
97
|
+
begin
|
98
|
+
@sel.wait_for_condition(js, QUICK_WAIT_FOR)
|
99
|
+
return true
|
100
|
+
rescue Selenium::CommandError
|
101
|
+
return false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def contains? (str,timeout=QUICK_WAIT_FOR)
|
106
|
+
wait_for_ajax
|
107
|
+
js = %{window.$(#{get_js_locator()}).html().indexOf(#{str.to_json}) >= 0;}
|
108
|
+
begin
|
109
|
+
@sel.wait_for_condition(js, timeout)
|
110
|
+
return true
|
111
|
+
rescue Selenium::CommandError
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def click (options = {})
|
117
|
+
@sel.click(get_ele(), options)
|
118
|
+
end
|
119
|
+
|
120
|
+
def text
|
121
|
+
return @sel.text(get_ele())
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_value
|
125
|
+
return @sel.get_value(get_ele())
|
126
|
+
end
|
127
|
+
|
128
|
+
def click! (options = {})
|
129
|
+
@sel.click(get_ele(), options)
|
130
|
+
@sel.wait_for_page
|
131
|
+
end
|
132
|
+
|
133
|
+
def mouse_up ()
|
134
|
+
trigger("LEFT_MOUSE_UP")
|
135
|
+
end
|
136
|
+
|
137
|
+
def mouse_down ()
|
138
|
+
trigger("LEFT_MOUSE_DOWN")
|
139
|
+
end
|
140
|
+
|
141
|
+
def mouse_over (options = {})
|
142
|
+
@sel.mouse_over(get_ele(), options)
|
143
|
+
end
|
144
|
+
|
145
|
+
def mouse_out (options = {})
|
146
|
+
@sel.mouse_out(get_ele(), options)
|
147
|
+
end
|
148
|
+
|
149
|
+
def type (*params)
|
150
|
+
elem = get_ele()
|
151
|
+
@sel.type(elem, *params)
|
152
|
+
@sel.fire_event(elem, 'blur')
|
153
|
+
end
|
154
|
+
|
155
|
+
def html ()
|
156
|
+
wait_for_ajax
|
157
|
+
js = get_js_locator()
|
158
|
+
return @sel.js_eval("#{js}.innerHTML;")
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def get_locator
|
164
|
+
js = get_js_locator()
|
165
|
+
dom_locator = "dom=#{js};"
|
166
|
+
return dom_locator
|
167
|
+
end
|
168
|
+
|
169
|
+
def get_ele
|
170
|
+
real_locator = get_locator()
|
171
|
+
wait_for_ele()
|
172
|
+
|
173
|
+
return real_locator
|
174
|
+
end
|
175
|
+
|
176
|
+
def get_js_locator
|
177
|
+
if @selector
|
178
|
+
return @selector
|
179
|
+
end
|
180
|
+
|
181
|
+
filtered_locator = @key.to_s
|
182
|
+
int = ''
|
183
|
+
|
184
|
+
if m = filtered_locator.match(/([^\[\]]+)(\[([^\]]*)\])/)
|
185
|
+
log "filtered: #{filtered_locator} #{m.inspect}"
|
186
|
+
filtered_locator = m[1]
|
187
|
+
int = ', ' + m[3] if m[3]
|
188
|
+
end
|
189
|
+
|
190
|
+
funct = 'getVal'
|
191
|
+
get_val = "window.USE_SEL_MARKER.#{funct}('#{@klass}', '#{filtered_locator}'#{int})"
|
192
|
+
|
193
|
+
return get_val
|
194
|
+
end
|
195
|
+
|
196
|
+
def wait_for_ele ()
|
197
|
+
real_locator = get_locator
|
198
|
+
puts "waiting for #{real_locator}"
|
199
|
+
wait_for_ajax
|
200
|
+
@sel.wait_for_condition real_locator, QUICK_WAIT_FOR
|
201
|
+
puts "found #{real_locator}"
|
202
|
+
end
|
203
|
+
|
204
|
+
def wait_for_ajax
|
205
|
+
@sel.wait_for_condition('selenium.browserbot.getCurrentWindow().jQuery.active == 0', AJAX_TIME_OUT)
|
206
|
+
end
|
207
|
+
|
208
|
+
def trigger (event)
|
209
|
+
get_ele()
|
210
|
+
@sel.execute("window.$(#{get_js_locator}).trigger(JS2.SEL_EVENTS.#{event})")
|
211
|
+
end
|
212
|
+
|
213
|
+
def method_missing (method, *arg)
|
214
|
+
if @sel.respond_to?(method)
|
215
|
+
return @sel.send(method, get_js_locator, *arg)
|
216
|
+
else
|
217
|
+
raise "Method missing: #{method}"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class JS2::Test::SeleniumHelper
|
2
|
+
attr_accessor :klass, :lookup
|
3
|
+
|
4
|
+
def initialize (klass, lookup, sel)
|
5
|
+
@klass = klass
|
6
|
+
@lookup = lookup
|
7
|
+
@sel = sel
|
8
|
+
@all_eles = Hash.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def [] (key, tail = nil)
|
12
|
+
key = key.to_s
|
13
|
+
|
14
|
+
return @all_eles[key] if @all_eles[key]
|
15
|
+
|
16
|
+
# TODO: support inheritence
|
17
|
+
#raise "invalid key #{key}" unless @lookup[key]
|
18
|
+
|
19
|
+
return @all_eles[key] = JS2::Test::SeleniumElement.new(@sel, @klass, key, tail)
|
20
|
+
end
|
21
|
+
|
22
|
+
def type_form (params = {})
|
23
|
+
params.each_pair do |k,v|
|
24
|
+
self[k].type(v)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/js2.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module Js2
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
end
|
7
|
+
|
8
|
+
module JS2
|
9
|
+
module Parser
|
10
|
+
end
|
11
|
+
module AST
|
12
|
+
end
|
13
|
+
module Process
|
14
|
+
end
|
15
|
+
module Decorator
|
16
|
+
end
|
17
|
+
module Test
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
|
23
|
+
|
24
|
+
# for others
|
25
|
+
require 'js2/processor'
|
26
|
+
require 'js2/daemon'
|
27
|
+
require 'js2/config'
|
28
|
+
|
29
|
+
# parser
|
30
|
+
require 'js2/parser/fast'
|
31
|
+
require 'js2/parser/haml'
|
32
|
+
|
33
|
+
# process
|
34
|
+
require 'js2/process/haml_engine'
|
35
|
+
require 'js2/process/file_handler'
|
36
|
+
require 'js2/process/universe'
|
37
|
+
|
38
|
+
# ast
|
39
|
+
require 'js2/ast/node'
|
40
|
+
require 'js2/ast/class_node'
|
41
|
+
require 'js2/ast/comment_node'
|
42
|
+
require 'js2/ast/haml_node'
|
43
|
+
require 'js2/ast/inherited_node'
|
44
|
+
require 'js2/ast/stuff_node'
|
45
|
+
require 'js2/ast/member_node'
|
46
|
+
require 'js2/ast/method_node'
|
47
|
+
require 'js2/ast/module_node'
|
48
|
+
require 'js2/ast/include_node'
|
49
|
+
require 'js2/ast/nodes'
|
50
|
+
|
51
|
+
# decorator
|
52
|
+
require 'js2/decorator/standard'
|
53
|
+
require 'js2/decorator/test'
|
54
|
+
require 'js2/decorator/cleanser'
|
55
|
+
|
56
|
+
require 'yaml'
|
57
|
+
|
58
|
+
# test
|
59
|
+
require 'js2/test/selenium'
|
60
|
+
require 'js2/test/selenium_helper'
|
61
|
+
require 'js2/test/selenium_element'
|
62
|
+
|
63
|
+
module JS2
|
64
|
+
def self.config
|
65
|
+
return @@config
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.config_file= (config_file)
|
69
|
+
@@config = YAML.load_file(config_file)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.write_files(params)
|
73
|
+
return self.daemon.run(1)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.daemon (params)
|
77
|
+
return JS2::Process::Daemon.new(params)
|
78
|
+
end
|
79
|
+
|
80
|
+
begin
|
81
|
+
# for haml filter
|
82
|
+
module JS2
|
83
|
+
include Haml::Filters::Base
|
84
|
+
|
85
|
+
def render (text)
|
86
|
+
parser = ::JS2::Parser::Fast.new
|
87
|
+
nodes = parser.parse_string(text)
|
88
|
+
decorator = ::JS2::Decorator::Test.new
|
89
|
+
return "<script>" + decorator.draw_nodes(nodes) + "</script>"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
rescue Exception
|
93
|
+
puts "No haml filter support"
|
94
|
+
end
|
95
|
+
end
|
data/lib/tasks/js2.rake
ADDED
@@ -0,0 +1,322 @@
|
|
1
|
+
# Somewhat based on http://www.mozilla.org/js/language/js20-2000-07/formal/lexer-grammar.html
|
2
|
+
# Regular Expression Literals determined with these rules:
|
3
|
+
# http://www.mozilla.org/js/language/js20-1999-03-25/tokens.html
|
4
|
+
|
5
|
+
%%{
|
6
|
+
machine dude;
|
7
|
+
alphtype char;
|
8
|
+
|
9
|
+
action actionStringBegin {
|
10
|
+
}
|
11
|
+
|
12
|
+
action actionStringAcc {
|
13
|
+
}
|
14
|
+
|
15
|
+
action actionStringAccBsEscape {
|
16
|
+
}
|
17
|
+
|
18
|
+
action actionStringAccUtf16 {
|
19
|
+
}
|
20
|
+
|
21
|
+
unicodecharacter = any;
|
22
|
+
unicodeinitialalphabetic = alpha;
|
23
|
+
unicodealphanumeric = alnum;
|
24
|
+
whitespacecharacter = [\t\v\f ];
|
25
|
+
lineterminator = ('\r' | '\n');
|
26
|
+
asciidigit = digit;
|
27
|
+
|
28
|
+
literals = (
|
29
|
+
'==' | '!=' | '===' | '!==' | '<=' | '>=' | '||' | '&&' | '++' | '--' | '<<' | '<<=' | '>>' | '>>=' | '>>>' | '>>>='| '&=' | '%=' | '^=' | '|=' | '+=' | '-=' | '*=' | '/='
|
30
|
+
);
|
31
|
+
|
32
|
+
# put in class
|
33
|
+
# put in accessor
|
34
|
+
keywords = (
|
35
|
+
'break' | 'case' | 'catch' | 'continue' | 'default' | 'delete' | 'do' |
|
36
|
+
'else' | 'finally' | 'for' | 'function' | 'if' | 'in' | 'instanceof' |
|
37
|
+
'new' | 'return' | 'switch' | 'this' | 'throw' | 'try' | 'typeof' | 'var' | 'accessor' |
|
38
|
+
'void' | 'while' | 'with' | 'const' | 'true' | 'false' | 'null' | 'debugger' |
|
39
|
+
'class' | 'static' | 'foreach' | 'module' | 'include' | 'property'
|
40
|
+
);
|
41
|
+
|
42
|
+
# took out class
|
43
|
+
reserved = (
|
44
|
+
'abstract' | 'boolean' | 'byte' | 'char' | 'double' | 'enum' | 'export' |
|
45
|
+
'extends' | 'final' | 'float' | 'goto' | 'implements' | 'import' | 'int' | 'interface' |
|
46
|
+
'long' | 'native' | 'package' | 'private' | 'protected' | 'public' | 'short' |
|
47
|
+
'super' | 'synchronized' | 'throws' | 'transient' | 'volatile'
|
48
|
+
);
|
49
|
+
|
50
|
+
nonterminator = any - lineterminator;
|
51
|
+
linecommentcharacters = nonterminator*;
|
52
|
+
nonterminatororslash = nonterminator - '/';
|
53
|
+
nonterminatororastreisk = nonterminator - '*';
|
54
|
+
nonterminatororasteriskorslash = nonterminator - ('*' | '/');
|
55
|
+
blockcommentcharacters = (nonterminatororslash | (nonterminatororastreisk '/'))*;
|
56
|
+
multilineblockcommentcharacters = (blockcommentcharacters lineterminator)*;
|
57
|
+
|
58
|
+
linecomment = '//' linecommentcharacters;
|
59
|
+
singlelineblockcomment = '/*' blockcommentcharacters '*/';
|
60
|
+
multilineblockcomment = '/*' multilineblockcommentcharacters blockcommentcharacters '*/';
|
61
|
+
comment = linecomment | singlelineblockcomment | multilineblockcomment;
|
62
|
+
|
63
|
+
string_begin = '\'' @ actionStringBegin;
|
64
|
+
string_end = '\'';
|
65
|
+
stringchar_normal = ^(['\\] | 0..0x1f) @ actionStringAcc;
|
66
|
+
stringchar_bs_esc = '\\'['\\/bfnrt] @ actionStringAccBsEscape;
|
67
|
+
stringchar_utf16 = '\\u'[0-9a-fA-F]{4} @ actionStringAccUtf16;
|
68
|
+
stringchar_bs_other = '\\'^(['\\/bfnrtu]|0..0x1f) @ actionStringAccBsEscape;
|
69
|
+
stringchar = (stringchar_normal | stringchar_bs_esc | stringchar_utf16 | stringchar_bs_other);
|
70
|
+
string = string_begin . stringchar* . string_end;
|
71
|
+
|
72
|
+
ds_string_begin = '"' @ actionStringBegin;
|
73
|
+
ds_string_end = '"';
|
74
|
+
ds_stringchar_normal = ^(["\\] | 0..0x1f) @ actionStringAcc;
|
75
|
+
ds_stringchar_bs_esc = '\\'["\\/bfnrt] @ actionStringAccBsEscape;
|
76
|
+
ds_stringchar_utf16 = '\\u'[0-9a-fA-F]{4} @ actionStringAccUtf16;
|
77
|
+
ds_stringchar_bs_other = '\\'^(["\\/bfnrtu]|0..0x1f) @ actionStringAccBsEscape;
|
78
|
+
ds_stringchar = (ds_stringchar_normal | ds_stringchar_bs_esc | ds_stringchar_utf16 | ds_stringchar_bs_other);
|
79
|
+
ds_string = ds_string_begin . ds_stringchar* . ds_string_end;
|
80
|
+
|
81
|
+
all_string = string | ds_string;
|
82
|
+
|
83
|
+
integer = '-'? . digit+;
|
84
|
+
float = '-'? (
|
85
|
+
(('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
|
86
|
+
| (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
|
87
|
+
);
|
88
|
+
number = integer | float;
|
89
|
+
|
90
|
+
identifier_char = ([a-zA-Z0-9_]) | '$';
|
91
|
+
identifier = identifier_char+;
|
92
|
+
|
93
|
+
ordinaryregexpchar = nonterminator - ('/' | '\\');
|
94
|
+
regexpchars = (ordinaryregexpchar | '\\' nonterminator)+;
|
95
|
+
regexpbody = '/' @ {regexp_start = p;} regexpchars '/';
|
96
|
+
regexpflags = ('g' | 'i' | 'm')*;
|
97
|
+
regexpliteral = regexpbody regexpflags;
|
98
|
+
|
99
|
+
specialcasedivide = (
|
100
|
+
identifier '/'
|
101
|
+
);
|
102
|
+
single_char = any;
|
103
|
+
|
104
|
+
arg_list = '(' . whitespacecharacter* . (identifier . whitespacecharacter* . ',' . whitespacecharacter*)* . identifier? . whitespacecharacter* . ')';
|
105
|
+
curry_with = 'with' . whitespacecharacter* . arg_list;
|
106
|
+
curry = 'curry' . whitespacecharacter* . arg_list? . whitespacecharacter* . curry_with? . whitespacecharacter* . '{';
|
107
|
+
|
108
|
+
main := |*
|
109
|
+
|
110
|
+
lineterminator => {
|
111
|
+
line_number++;
|
112
|
+
};
|
113
|
+
|
114
|
+
curry => {
|
115
|
+
curr = ts-data;
|
116
|
+
<%= replacer.start :CURRY %>
|
117
|
+
cb_count++;
|
118
|
+
};
|
119
|
+
|
120
|
+
whitespacecharacter => {};
|
121
|
+
comment => {
|
122
|
+
if (<%= replacer.directly_in? :CLASS %>) {
|
123
|
+
<%= replacer.do_next(:COMMENT, 'ts-data', 'te-data-1') %>
|
124
|
+
}
|
125
|
+
};
|
126
|
+
|
127
|
+
all_string => {};
|
128
|
+
number => {};
|
129
|
+
keywords => {
|
130
|
+
curr = ts-data;
|
131
|
+
|
132
|
+
<%= replacer.set_keyword %>
|
133
|
+
|
134
|
+
if (<%= replacer.is? :CLASS %> || <%= replacer.is? :MODULE %>) {
|
135
|
+
if (<%= replacer.is? :CLASS %>) {
|
136
|
+
<%= replacer.start :CLASS %>
|
137
|
+
} else {
|
138
|
+
<%= replacer.start :MODULE %>
|
139
|
+
}
|
140
|
+
|
141
|
+
// if "class" wasn't the first thing in the file
|
142
|
+
// then submit the :STUFF
|
143
|
+
if (curr > 0) {
|
144
|
+
<%= replacer.stop :STUFF, 'curr-1' %>
|
145
|
+
}
|
146
|
+
|
147
|
+
} else if (<%= replacer.directly_in? :CLASS %> || <%= replacer.directly_in? :MODULE %>) {
|
148
|
+
if (<%= replacer.is? :STATIC %>) {
|
149
|
+
<%= replacer.set_static %>
|
150
|
+
}
|
151
|
+
|
152
|
+
if (<%= replacer.is? :FUNCTION %>) {
|
153
|
+
<%= replacer.start :METHOD %>
|
154
|
+
}
|
155
|
+
|
156
|
+
if (<%= replacer.is? :VAR %>) {
|
157
|
+
<%= replacer.start :MEMBER %>
|
158
|
+
}
|
159
|
+
|
160
|
+
|
161
|
+
if (<%= replacer.is? :ACCESSOR %>) {
|
162
|
+
<%= replacer.start :MEMBER %>
|
163
|
+
}
|
164
|
+
|
165
|
+
if (<%= replacer.is? :PROPERTY %>) {
|
166
|
+
<%= replacer.start :PROPERTY %>
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
if (<%= replacer.is? :INCLUDE %>) {
|
171
|
+
<%= replacer.start :INCLUDE %>
|
172
|
+
}
|
173
|
+
|
174
|
+
}
|
175
|
+
|
176
|
+
if (<%= replacer.is? :FOREACH %>) {
|
177
|
+
<%= replacer.start :FOREACH %>
|
178
|
+
}
|
179
|
+
|
180
|
+
};
|
181
|
+
|
182
|
+
literals => { };
|
183
|
+
reserved => { };
|
184
|
+
identifier => { };
|
185
|
+
|
186
|
+
<%= replacer.def_literals %>
|
187
|
+
|
188
|
+
single_char | (('(' | '{' | ';') whitespacecharacter* regexpliteral) => {
|
189
|
+
curr = ts-data;
|
190
|
+
single = data[ts-data];
|
191
|
+
|
192
|
+
if (single == '(') {
|
193
|
+
br_count++;
|
194
|
+
} else if (single == ')') {
|
195
|
+
br_count--;
|
196
|
+
|
197
|
+
if (in_FOREACH && br_count == br_lvl_FOREACH) {
|
198
|
+
<%= replacer.stop :FOREACH %>
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
if (single == '{') {
|
203
|
+
cb_count++;
|
204
|
+
} else if (single == '}') {
|
205
|
+
if (<%= replacer.directly_in? :CLASS %> || <%= replacer.directly_in? :MODULE %>) {
|
206
|
+
<%= replacer.start :STUFF, 'curr+1' %>
|
207
|
+
}
|
208
|
+
|
209
|
+
cb_count--;
|
210
|
+
|
211
|
+
// stuff that stops on }'s
|
212
|
+
<%= replacer.handle_stops [ :METHOD, :CLASS, :FOREACH, :MODULE, :CURRY ] %>
|
213
|
+
}
|
214
|
+
|
215
|
+
if (single == ';') {
|
216
|
+
<%= replacer.handle_semicolon_stops [ :MEMBER, :INCLUDE, :PROPERTY ] %>
|
217
|
+
}
|
218
|
+
|
219
|
+
};
|
220
|
+
|
221
|
+
*|;
|
222
|
+
}%%
|
223
|
+
|
224
|
+
require 'rubygems'
|
225
|
+
require 'inline'
|
226
|
+
|
227
|
+
class JS2::Parser::Fast
|
228
|
+
attr_accessor :data
|
229
|
+
|
230
|
+
inline do |builder|
|
231
|
+
builder.c_raw <<-END
|
232
|
+
|
233
|
+
int do_parse (int argc, VALUE *argv, VALUE self) {
|
234
|
+
// convert ruby string to char*
|
235
|
+
VALUE r_str = argv[0];
|
236
|
+
int data_length = RSTRING(r_str)->len;
|
237
|
+
char* data = STR2CSTR(r_str);
|
238
|
+
|
239
|
+
VALUE ln_argv[1];
|
240
|
+
int ln_argc = 1;
|
241
|
+
int line_number = 1;
|
242
|
+
ID ln_sym = rb_intern("set_line_number");
|
243
|
+
|
244
|
+
// do_next vars
|
245
|
+
VALUE do_next_argv[4];
|
246
|
+
int do_next_argc = 4;
|
247
|
+
ID do_next_sym = rb_intern("do_next");
|
248
|
+
|
249
|
+
VALUE set_static_argv[0];
|
250
|
+
int set_static_argc = 0;
|
251
|
+
ID set_static_sym = rb_intern("set_static");
|
252
|
+
|
253
|
+
// state vars
|
254
|
+
int i = 0; // iterator
|
255
|
+
int j = 0; // iterator
|
256
|
+
char word[100]; // keyword
|
257
|
+
char single;
|
258
|
+
|
259
|
+
int curr = 0;
|
260
|
+
int prev = -1;
|
261
|
+
int cb_count = 0;
|
262
|
+
int br_count = 0;
|
263
|
+
|
264
|
+
<%= replacer.declare_vars [ :CLASS, :METHOD, :MEMBER, :STUFF, :ACCESSOR, :COMMENT, :FOREACH, :MODULE, :INCLUDE, :CURRY, :PROPERTY ] %>
|
265
|
+
|
266
|
+
// ragel variables
|
267
|
+
int cs, act;
|
268
|
+
char *ts = NULL;
|
269
|
+
char *te = NULL;
|
270
|
+
char *p = data;
|
271
|
+
char *pe = p + data_length;
|
272
|
+
char *eof = pe;
|
273
|
+
char* regexp_start = NULL;
|
274
|
+
|
275
|
+
<%= replacer.start :STUFF %>
|
276
|
+
|
277
|
+
%% write data;
|
278
|
+
%% write init;
|
279
|
+
%% write exec;
|
280
|
+
|
281
|
+
if (in_STUFF == 1) {
|
282
|
+
<%= replacer.stop :STUFF %>
|
283
|
+
}
|
284
|
+
}
|
285
|
+
|
286
|
+
END
|
287
|
+
end
|
288
|
+
|
289
|
+
def set_line_number (l)
|
290
|
+
@line_number = l
|
291
|
+
end
|
292
|
+
|
293
|
+
def set_static ()
|
294
|
+
@nodes.set_static
|
295
|
+
end
|
296
|
+
|
297
|
+
def do_next (symbol, start_idx, end_idx, line)
|
298
|
+
if end_idx == -1 then end_idx = start_idx end
|
299
|
+
@nodes.do_next(symbol, start_idx, end_idx, line)
|
300
|
+
end
|
301
|
+
|
302
|
+
def parse_string (str)
|
303
|
+
self.data = str
|
304
|
+
@nodes = JS2::AST::Nodes.new("string", str)
|
305
|
+
self.do_parse(str)
|
306
|
+
return @nodes
|
307
|
+
end
|
308
|
+
|
309
|
+
def parse(filename)
|
310
|
+
self.data = File.read(filename)
|
311
|
+
@nodes = JS2::AST::Nodes.new(filename, data)
|
312
|
+
|
313
|
+
#@cleanser ||= JS2::DecoCleanser.new
|
314
|
+
#@cleanser.cleanse(data)
|
315
|
+
|
316
|
+
eof = data.size
|
317
|
+
self.do_parse(data)
|
318
|
+
|
319
|
+
return @nodes
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|