rkelly-remix 0.0.4 → 0.0.5
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.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +5 -0
- data/README.rdoc +106 -3
- data/lib/rkelly/constants.rb +1 -1
- data/lib/rkelly/generated_parser.rb +1 -1
- data/lib/rkelly/nodes/node.rb +20 -0
- data/lib/rkelly/tokenizer.rb +8 -4
- data/lib/rkelly/visitors/ecma_visitor.rb +10 -6
- data/test/expressions/test_11_4_6.rb +7 -1
- data/test/test_ecma_visitor.rb +3 -0
- metadata +17 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0735c3a4887540bf2decb0e3212c0402bb0e8a7e
|
4
|
+
data.tar.gz: d546a14e99056db30d3e3f66664f52efbbc733cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d2912446c29a7af0698985a20b87a245f9f310ece9fbde5df6db4e14479699faa7345e9c6f206fc0b46f757fc78b8cc08255001a72230a8be896828b29e46b7
|
7
|
+
data.tar.gz: 9a18576dfb4323215987fd68216c49dd9f32b206f6d52cc74d9bd93a090f0b803cf8646e5475b120df84ed386346283aeb5c01bf07b9dc2adf5126f78f836eee
|
data/CHANGELOG.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -1,11 +1,114 @@
|
|
1
1
|
= RKelly Remix
|
2
2
|
|
3
|
+
https://github.com/nene/rkelly-remix
|
4
|
+
|
3
5
|
== DESCRIPTION
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
+
RKelly Remix is a fork of the
|
8
|
+
RKelly[https://github.com/tenderlove/rkelly] JavaScript parser.
|
9
|
+
|
10
|
+
== Install
|
11
|
+
|
12
|
+
gem install rkelly-remix
|
13
|
+
|
14
|
+
Note that you can't have rkelly and rkelly-remix both installed at the
|
15
|
+
same time. That would cause a conflict since they're both included
|
16
|
+
with:
|
17
|
+
|
18
|
+
require 'rkelly'
|
19
|
+
|
20
|
+
== Example
|
21
|
+
|
22
|
+
# Iterate over and modify a JavaScript AST. Then print the modified
|
23
|
+
# AST as JavaScript.
|
24
|
+
require 'rkelly'
|
25
|
+
|
26
|
+
parser = RKelly::Parser.new
|
27
|
+
ast = parser.parse(
|
28
|
+
"for(var i = 0; i < 10; i++) { var x = 5 + 5; }"
|
29
|
+
)
|
30
|
+
|
31
|
+
ast.each do |node|
|
32
|
+
node.value = 'hello' if node.value == 'i'
|
33
|
+
node.name = 'hello' if node.respond_to?(:name) && node.name == 'i'
|
34
|
+
end
|
35
|
+
puts ast.to_ecma # => awesome javascript
|
36
|
+
|
37
|
+
== Why fork?
|
38
|
+
|
39
|
+
Currently the original RKelly project is unmaintained. The latest
|
40
|
+
release was in late 2012, and since then the author has not responded
|
41
|
+
to bug reports or pull requests.
|
42
|
+
|
43
|
+
I created this fork mainly to satisfy the needs of my
|
44
|
+
JSDuck[https://github.com/senchalabs/jsduck] project, but you too
|
45
|
+
should consider using it, as it fixes several problems in the original
|
46
|
+
RKelly:
|
47
|
+
|
48
|
+
=== Much improved speed
|
49
|
+
|
50
|
+
* 20 x faster in Ruby 1.8.
|
51
|
+
* 2 x faster in Ruby 1.9 and 2.0.
|
52
|
+
|
53
|
+
=== Correct start/end position data for all syntax nodes
|
54
|
+
|
55
|
+
Original RKelly only had a rudimentary support for getting the line
|
56
|
+
number of an AST node, and even that was often wrong.
|
57
|
+
|
58
|
+
In RKelly Remix each AST node has a range property, which contains
|
59
|
+
granular data about the exact location of the node in source code:
|
60
|
+
|
61
|
+
parser = RKelly::Parser.new
|
62
|
+
ast = parser.parse(<<-eojs)
|
63
|
+
function aaron() {
|
64
|
+
var x = 10;
|
65
|
+
return 1 + 1;
|
66
|
+
}
|
67
|
+
eojs
|
68
|
+
|
69
|
+
node = ast.pointcut(ReturnNode).matches.first
|
70
|
+
|
71
|
+
node.range.to_s # <{line:3 char:5 (41)}...{line:3 char:17 (53)}>
|
72
|
+
|
73
|
+
node.range.from.line # 3
|
74
|
+
node.range.from.char # 5
|
75
|
+
node.range.from.index # 41
|
76
|
+
|
77
|
+
node.range.to.line # 3
|
78
|
+
node.range.to.char # 17
|
79
|
+
node.range.to.index # 53
|
80
|
+
|
81
|
+
=== Sensible comments handling
|
82
|
+
|
83
|
+
Original RKelly attempted to associate each comment with a related AST
|
84
|
+
node, but failed to correctly do so, which is understandable, as there
|
85
|
+
is no standard way to do such a mapping. RKelly Remix abandons this
|
86
|
+
and just lists all commenst in the root node, leaving the user with
|
87
|
+
the task of associating them with AST nodes if he desires so (the same
|
88
|
+
approach is taken by another JS parser: Esprima[http://esprima.org] ).
|
89
|
+
|
90
|
+
parser = RKelly::Parser.new
|
91
|
+
ast = parser.parse(<<-eojs)
|
92
|
+
/**
|
93
|
+
* This is an awesome test comment.
|
94
|
+
*/
|
95
|
+
function aaron() { // This is a side comment
|
96
|
+
var x = 10;
|
97
|
+
return 1 + 1; // Equals two!
|
98
|
+
}
|
99
|
+
eojs
|
100
|
+
|
101
|
+
# print out all the comments
|
102
|
+
ast.comments.each do |c|
|
103
|
+
puts c.value
|
104
|
+
end
|
105
|
+
|
106
|
+
=== Improved parser
|
7
107
|
|
8
|
-
*
|
108
|
+
* List of reserved words matches with ECMAScript 5.1.
|
109
|
+
* Keywords are allowed in property names.
|
110
|
+
* Multibyte characters are supported in Ruby >= 1.9.
|
111
|
+
* Correct parsing of regexes like /[/]/
|
9
112
|
|
10
113
|
== License
|
11
114
|
|
data/lib/rkelly/constants.rb
CHANGED
data/lib/rkelly/nodes/node.rb
CHANGED
@@ -27,6 +27,13 @@ module RKelly
|
|
27
27
|
other.is_a?(self.class) && @value === other.value
|
28
28
|
end
|
29
29
|
|
30
|
+
# Matches nodes with the given pattern (usually a class name of
|
31
|
+
# the node) and returns an instance of PointcutVisitor on which
|
32
|
+
# #matches can be invoked to get the list of AST nodes that
|
33
|
+
# matched.
|
34
|
+
#
|
35
|
+
# ast.pointcut(RKelly::Nodes::IfNode).matches --> array of nodes
|
36
|
+
#
|
30
37
|
def pointcut(pattern)
|
31
38
|
case pattern
|
32
39
|
when String
|
@@ -44,14 +51,24 @@ module RKelly
|
|
44
51
|
end
|
45
52
|
alias :/ :pointcut
|
46
53
|
|
54
|
+
# Generates an s-expression data structure like so:
|
55
|
+
#
|
56
|
+
# "var x = 10;" --> [:var, [[:var_decl, :x, [:assign, [:lit, 10]]]]]]
|
57
|
+
#
|
47
58
|
def to_sexp
|
48
59
|
SexpVisitor.new.accept(self)
|
49
60
|
end
|
50
61
|
|
62
|
+
# Generates formatted and intented JavaScript source code.
|
51
63
|
def to_ecma
|
52
64
|
ECMAVisitor.new.accept(self)
|
53
65
|
end
|
54
66
|
|
67
|
+
# Generates a graph description in DOT language. This can be
|
68
|
+
# fed into the dot program to generate a graph of the AST:
|
69
|
+
#
|
70
|
+
# $ dot -Tpng generated-graph.dot -o graph.png
|
71
|
+
#
|
55
72
|
def to_dots
|
56
73
|
visitor = DotVisitor.new
|
57
74
|
visitor.accept(self)
|
@@ -74,10 +91,13 @@ edge [ ];
|
|
74
91
|
"#{header}\n#{nodes}\n#{arrows}\n}"
|
75
92
|
end
|
76
93
|
|
94
|
+
# Loops through all the syntax nodes.
|
77
95
|
def each(&block)
|
78
96
|
EnumerableVisitor.new(block).accept(self)
|
79
97
|
end
|
80
98
|
|
99
|
+
# This CRASHES!
|
100
|
+
# It calls method #s which is nowhere to be found.
|
81
101
|
def to_real_sexp
|
82
102
|
RealSexpVisitor.new.accept(self)
|
83
103
|
end
|
data/lib/rkelly/tokenizer.rb
CHANGED
@@ -12,11 +12,15 @@ module RKelly
|
|
12
12
|
const true false null debugger
|
13
13
|
}.map {|kw| [kw, kw.upcase.to_sym] }]
|
14
14
|
|
15
|
+
# First 6 are always reserved in ECMAScript 5.1
|
16
|
+
# Others are only reserved in strict mode.
|
17
|
+
# http://www.ecma-international.org/ecma-262/5.1/#sec-7.6.1.2
|
18
|
+
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
|
15
19
|
RESERVED = Hash[%w{
|
16
|
-
|
17
|
-
|
18
|
-
private protected public
|
19
|
-
|
20
|
+
class enum export extends import super
|
21
|
+
|
22
|
+
implements interface package private protected public static
|
23
|
+
let yield
|
20
24
|
}.map {|kw| [kw, true] }]
|
21
25
|
|
22
26
|
LITERALS = {
|
@@ -87,9 +87,7 @@ module RKelly
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def visit_FunctionDeclNode(o)
|
90
|
-
"#{indent}function #{o.value}
|
91
|
-
"#{o.arguments.map { |x| x.accept(self) }.join(', ')})" +
|
92
|
-
"#{o.function_body.accept(self)}"
|
90
|
+
"#{indent}function #{o.value}" + function_params_and_body(o)
|
93
91
|
end
|
94
92
|
|
95
93
|
def visit_ParameterNode(o)
|
@@ -269,15 +267,21 @@ module RKelly
|
|
269
267
|
end
|
270
268
|
|
271
269
|
def visit_GetterPropertyNode(o)
|
272
|
-
"get #{o.name}
|
270
|
+
"get #{o.name}" + function_params_and_body(o.value)
|
273
271
|
end
|
274
272
|
|
275
273
|
def visit_SetterPropertyNode(o)
|
276
|
-
"set #{o.name}
|
274
|
+
"set #{o.name}" + function_params_and_body(o.value)
|
277
275
|
end
|
278
276
|
|
279
277
|
def visit_FunctionExprNode(o)
|
280
|
-
|
278
|
+
name = (o.value == 'function') ? '' : ' '+o.value
|
279
|
+
"function" + name + function_params_and_body(o)
|
280
|
+
end
|
281
|
+
|
282
|
+
# Helper for all the various function nodes
|
283
|
+
def function_params_and_body(o)
|
284
|
+
"(#{o.arguments.map { |x| x.accept(self) }.join(', ')}) " +
|
281
285
|
"#{o.function_body.accept(self)}"
|
282
286
|
end
|
283
287
|
|
@@ -62,7 +62,12 @@ class Expressions_11_4_6_Test < ECMAScriptTestCase
|
|
62
62
|
['1234e-5', 0.01234],
|
63
63
|
]
|
64
64
|
0.upto(9) { |x| @@sign_tests << [x, x] }
|
65
|
-
|
65
|
+
|
66
|
+
# 0x0 needs special treatment as sprintf("%#x", 0) results in "0"
|
67
|
+
@@sign_tests << ["0x0", 0]
|
68
|
+
@@sign_tests << ["0X0", 0]
|
69
|
+
|
70
|
+
1.upto(15) { |x|
|
66
71
|
@@sign_tests << [sprintf("%#x", x), x]
|
67
72
|
@@sign_tests << [sprintf("%#x", x).gsub(/x/, 'X'), x]
|
68
73
|
if sprintf("%#x", x) =~ /[a-f]/
|
@@ -70,6 +75,7 @@ class Expressions_11_4_6_Test < ECMAScriptTestCase
|
|
70
75
|
@@sign_tests << [sprintf("%#x", x).upcase, x]
|
71
76
|
end
|
72
77
|
}
|
78
|
+
|
73
79
|
@@sign_tests.each { |actual, expected|
|
74
80
|
define_method(:"test_num_#{actual.to_s.gsub(/[\.+]/, '_')}") do
|
75
81
|
@runtime.execute("
|
data/test/test_ecma_visitor.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rkelly-remix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Aaron Patterson
|
@@ -10,12 +9,11 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-
|
12
|
+
date: 2013-10-22 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: rdoc
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
18
|
- - ~>
|
21
19
|
- !ruby/object:Gem::Version
|
@@ -23,7 +21,6 @@ dependencies:
|
|
23
21
|
type: :development
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
25
|
- - ~>
|
29
26
|
- !ruby/object:Gem::Version
|
@@ -31,25 +28,20 @@ dependencies:
|
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: hoe
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
32
|
- - ~>
|
37
33
|
- !ruby/object:Gem::Version
|
38
|
-
version: '3.
|
34
|
+
version: '3.7'
|
39
35
|
type: :development
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
39
|
- - ~>
|
45
40
|
- !ruby/object:Gem::Version
|
46
|
-
version: '3.
|
47
|
-
description:
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
* http://rkelly.rubyforge.org/'
|
41
|
+
version: '3.7'
|
42
|
+
description: |-
|
43
|
+
RKelly Remix is a fork of the
|
44
|
+
RKelly[https://github.com/tenderlove/rkelly] JavaScript parser.
|
53
45
|
email:
|
54
46
|
- aaron.patterson@gmail.com
|
55
47
|
- rene.saarsoo@sencha.com
|
@@ -264,8 +256,10 @@ files:
|
|
264
256
|
- test/test_while_node.rb
|
265
257
|
- test/test_with_node.rb
|
266
258
|
- .gemtest
|
267
|
-
homepage:
|
268
|
-
licenses:
|
259
|
+
homepage: https://github.com/nene/rkelly-remix
|
260
|
+
licenses:
|
261
|
+
- MIT
|
262
|
+
metadata: {}
|
269
263
|
post_install_message:
|
270
264
|
rdoc_options:
|
271
265
|
- --main
|
@@ -273,24 +267,22 @@ rdoc_options:
|
|
273
267
|
require_paths:
|
274
268
|
- lib
|
275
269
|
required_ruby_version: !ruby/object:Gem::Requirement
|
276
|
-
none: false
|
277
270
|
requirements:
|
278
|
-
- -
|
271
|
+
- - '>='
|
279
272
|
- !ruby/object:Gem::Version
|
280
273
|
version: '0'
|
281
274
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
282
|
-
none: false
|
283
275
|
requirements:
|
284
|
-
- -
|
276
|
+
- - '>='
|
285
277
|
- !ruby/object:Gem::Version
|
286
278
|
version: '0'
|
287
279
|
requirements: []
|
288
280
|
rubyforge_project: rkelly-remix
|
289
|
-
rubygems_version:
|
281
|
+
rubygems_version: 2.0.3
|
290
282
|
signing_key:
|
291
|
-
specification_version:
|
292
|
-
summary:
|
293
|
-
|
283
|
+
specification_version: 4
|
284
|
+
summary: RKelly Remix is a fork of the RKelly[https://github.com/tenderlove/rkelly]
|
285
|
+
JavaScript parser.
|
294
286
|
test_files:
|
295
287
|
- test/test_parser.rb
|
296
288
|
- test/test_ecma_visitor.rb
|