ruby2js 3.5.2 → 4.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -665
  3. data/lib/ruby2js.rb +47 -13
  4. data/lib/ruby2js/converter.rb +9 -3
  5. data/lib/ruby2js/converter/args.rb +6 -1
  6. data/lib/ruby2js/converter/assign.rb +159 -0
  7. data/lib/ruby2js/converter/begin.rb +7 -2
  8. data/lib/ruby2js/converter/case.rb +7 -2
  9. data/lib/ruby2js/converter/class.rb +80 -21
  10. data/lib/ruby2js/converter/class2.rb +107 -33
  11. data/lib/ruby2js/converter/def.rb +7 -3
  12. data/lib/ruby2js/converter/dstr.rb +8 -3
  13. data/lib/ruby2js/converter/hash.rb +28 -6
  14. data/lib/ruby2js/converter/hide.rb +13 -0
  15. data/lib/ruby2js/converter/if.rb +10 -2
  16. data/lib/ruby2js/converter/import.rb +19 -4
  17. data/lib/ruby2js/converter/kwbegin.rb +9 -2
  18. data/lib/ruby2js/converter/literal.rb +14 -2
  19. data/lib/ruby2js/converter/logical.rb +1 -1
  20. data/lib/ruby2js/converter/module.rb +41 -4
  21. data/lib/ruby2js/converter/opasgn.rb +8 -0
  22. data/lib/ruby2js/converter/return.rb +2 -1
  23. data/lib/ruby2js/converter/send.rb +73 -8
  24. data/lib/ruby2js/converter/vasgn.rb +5 -0
  25. data/lib/ruby2js/converter/xstr.rb +2 -3
  26. data/lib/ruby2js/demo.rb +53 -0
  27. data/lib/ruby2js/es2022.rb +5 -0
  28. data/lib/ruby2js/es2022/strict.rb +3 -0
  29. data/lib/ruby2js/filter.rb +9 -1
  30. data/lib/ruby2js/filter/active_functions.rb +44 -0
  31. data/lib/ruby2js/filter/camelCase.rb +6 -3
  32. data/lib/ruby2js/filter/cjs.rb +2 -0
  33. data/lib/ruby2js/filter/esm.rb +118 -26
  34. data/lib/ruby2js/filter/functions.rb +104 -106
  35. data/lib/ruby2js/filter/{wunderbar.rb → jsx.rb} +29 -7
  36. data/lib/ruby2js/filter/node.rb +58 -14
  37. data/lib/ruby2js/filter/nokogiri.rb +12 -12
  38. data/lib/ruby2js/filter/react.rb +192 -57
  39. data/lib/ruby2js/filter/require.rb +102 -11
  40. data/lib/ruby2js/filter/return.rb +13 -1
  41. data/lib/ruby2js/filter/stimulus.rb +185 -0
  42. data/lib/ruby2js/jsx.rb +309 -0
  43. data/lib/ruby2js/namespace.rb +75 -0
  44. data/lib/ruby2js/rails.rb +15 -9
  45. data/lib/ruby2js/serializer.rb +3 -1
  46. data/lib/ruby2js/version.rb +3 -3
  47. data/ruby2js.gemspec +2 -2
  48. metadata +17 -9
  49. data/lib/ruby2js/filter/esm_migration.rb +0 -72
  50. data/lib/ruby2js/filter/fast-deep-equal.rb +0 -23
@@ -6,7 +6,7 @@ module Ruby2JS
6
6
  # (arg :x)
7
7
  # (...)
8
8
 
9
- handle :def, :defm, :async do |name, args, body=nil|
9
+ handle :def, :defm, :async, :deff do |name, args, body=nil|
10
10
  body ||= s(:begin)
11
11
 
12
12
  add_implicit_block = false
@@ -106,7 +106,7 @@ module Ruby2JS
106
106
  # es2015 fat arrow support
107
107
  if \
108
108
  not name and es2015 and @state != :method and @ast.type != :defm and
109
- not @prop
109
+ @ast.type != :deff and not @prop
110
110
  then
111
111
  expr = body
112
112
  expr = expr.children.first while expr.type == :autoreturn
@@ -118,6 +118,10 @@ module Ruby2JS
118
118
  if EXPRESSIONS.include? expr.type
119
119
  if expr.type == :send and expr.children[0..1] == [nil, :raise]
120
120
  style = :statement
121
+ elsif expr.type == :send and expr.children.length == 2 and
122
+ expr.children.first == nil and @rbstack.last and
123
+ @rbstack.last[expr.children[1]]&.type == :autobind
124
+ style = :statement
121
125
  else
122
126
  style = :expression
123
127
  end
@@ -131,7 +135,7 @@ module Ruby2JS
131
135
  style = :statement
132
136
  end
133
137
 
134
- if args.children.length == 1 and style == :expression
138
+ if args.children.length == 1 and args.children.first.type == :arg and style == :expression
135
139
  parse args; put ' => '
136
140
  else
137
141
  put '('; parse args; put ') => '
@@ -10,6 +10,11 @@ module Ruby2JS
10
10
  # (...))
11
11
 
12
12
  handle :dstr, :dsym do |*children|
13
+ if @state == :expression and children.empty?
14
+ puts '""'
15
+ return
16
+ end
17
+
13
18
  if es2015
14
19
  # gather length of string parts; if long enough, newlines will
15
20
  # not be escaped (poor man's HEREDOC)
@@ -26,7 +31,7 @@ module Ruby2JS
26
31
  else
27
32
  put str
28
33
  end
29
- else
34
+ elsif child != s(:begin)
30
35
  put '${'
31
36
  parse child
32
37
  put '}'
@@ -40,8 +45,8 @@ module Ruby2JS
40
45
  children.each_with_index do |child, index|
41
46
  put ' + ' unless index == 0
42
47
 
43
- if child.type == :begin and child.children.length == 1
44
- child = child.children.first
48
+ if child.type == :begin and child.children.length <= 1
49
+ child = child.children.first || s(:str, '')
45
50
  end
46
51
 
47
52
  if child.type == :send
@@ -7,6 +7,24 @@ module Ruby2JS
7
7
  # (str "value")))
8
8
 
9
9
  handle :hash do |*pairs|
10
+ if not es2018 and pairs.any? {|pair| pair.type == :kwsplat}
11
+ groups = []
12
+ pending = []
13
+ while not pairs.empty?
14
+ pair = pairs.shift
15
+ if pair.type != :kwsplat
16
+ pending << pair
17
+ else
18
+ groups << s(:hash, *pending) unless pending.empty?
19
+ groups << pair.children.first
20
+ pending = []
21
+ end
22
+ end
23
+ groups << s(:hash, *pending) unless pending.empty?
24
+ parse s(:assign, s(:hash), *groups)
25
+ return
26
+ end
27
+
10
28
  compact do
11
29
  singleton = pairs.length <= 1
12
30
 
@@ -24,7 +42,7 @@ module Ruby2JS
24
42
  pairs.unshift(*node.children.first.children)
25
43
  index = 0
26
44
  else
27
- puts '...'; parse node.children.first
45
+ put '...'; parse node.children.first
28
46
  end
29
47
 
30
48
  next
@@ -73,7 +91,7 @@ module Ruby2JS
73
91
  if right.type == :hash
74
92
  right.children.each do |pair|
75
93
  next unless Parser::AST::Node === pair.children.last
76
- if [:block, :def, :async].include? pair.children.last.type
94
+ if %i[block def defm async].include? pair.children.last.type
77
95
  if @comments[pair.children.last]
78
96
  (puts ''; singleton = false) if singleton
79
97
  comments(pair.children.last).each do |comment|
@@ -120,22 +138,26 @@ module Ruby2JS
120
138
 
121
139
  if \
122
140
  anonfn and
123
- left.children.first.to_s =~ /\A[a-zA-Z_$][a-zA-Z_$0-9]*\Z/
141
+ left.children.first.to_s =~ /\A[a-zA-Z_$][a-zA-Z_$0-9]*\z/
124
142
  then
125
143
  @prop = left.children.first
126
144
  parse right, :method
127
145
  elsif \
128
- es2015 and left.type == :sym and right.type == :lvar and
129
- left.children == right.children
146
+ es2015 and left.type == :sym and (right.type == :lvar or
147
+ (right.type == :send and right.children.first == nil)) and
148
+ left.children.last == right.children.last
130
149
  then
131
150
  parse right
151
+ elsif right.type == :defm and %i[sym str].include? left.type and es2015
152
+ @prop = left.children.first.to_s
153
+ parse right
132
154
  else
133
155
  if not [:str, :sym].include? left.type and es2015
134
156
  put '['
135
157
  parse left
136
158
  put ']'
137
159
  elsif \
138
- left.children.first.to_s =~ /\A[a-zA-Z_$][a-zA-Z_$0-9]*\Z/
160
+ left.children.first.to_s =~ /\A[a-zA-Z_$][a-zA-Z_$0-9]*\z/
139
161
  then
140
162
  put left.children.first
141
163
  else
@@ -0,0 +1,13 @@
1
+ module Ruby2JS
2
+ class Converter
3
+
4
+ # (hide, ...)
5
+
6
+ handle :hide do |*nodes|
7
+ capture {parse_all(*nodes)}
8
+
9
+ @lines.pop if @state == :statement and @lines.last == []
10
+ @lines.last.pop if @lines.last.last == @sep
11
+ end
12
+ end
13
+ end
@@ -64,10 +64,18 @@ module Ruby2JS
64
64
  if else_block.type == :begin
65
65
  else_block = s(:xnode, '', *else_block.children)
66
66
  end
67
+ else
68
+ if then_block.type == :begin
69
+ then_block = s(:kwbegin, then_block)
70
+ end
71
+
72
+ if else_block.type == :begin
73
+ else_block = s(:kwbegin, else_block)
74
+ end
67
75
  end
68
76
 
69
- parse condition; put ' ? '; parse then_block
70
- put ' : '; parse else_block
77
+ parse condition; put ' ? '; parse then_block, @state
78
+ put ' : '; parse else_block, @state
71
79
  end
72
80
  end
73
81
  end
@@ -28,14 +28,29 @@ module Ruby2JS
28
28
  put path.inspect
29
29
  else
30
30
  # import (x) from "file.js"
31
- default_import = !args.first.is_a?(Array) && [:const, :send, :attr].include?(args.first.type)
31
+ default_import = !args.first.is_a?(Array) && %i[const send attr str].include?(args.first.type)
32
+
33
+ if default_import and args.length > 1
34
+ parse args.shift
35
+ put ', '
36
+ default_import = false
37
+ end
38
+
32
39
  args = args.first if args.first.is_a?(Array)
33
40
 
41
+ if args.first.type == :array
42
+ args = args.first.children
43
+ end
44
+
34
45
  # handle the default name or { ConstA, Const B } portion
35
46
  put "{ " unless default_import
36
47
  args.each_with_index do |arg, index|
37
48
  put ', ' unless index == 0
38
- parse arg
49
+ if arg.type == :str
50
+ put arg.children.first # useful for '*'
51
+ else
52
+ parse arg
53
+ end
39
54
  end
40
55
  put " }" unless default_import
41
56
 
@@ -43,7 +58,7 @@ module Ruby2JS
43
58
 
44
59
  # should there be an as clause? e.g., import React as *
45
60
  if path.is_a?(Array) && !path[0].is_a?(String) && path[0].type == :pair && path[0].children[0].children[0] == :as
46
- put " as #{path[0].children[1].children[0]}"
61
+ put " as #{path[0].children[1].children.last}"
47
62
 
48
63
  # advance to the next kwarg, aka from
49
64
  from_kwarg_position = 1
@@ -82,7 +97,7 @@ module Ruby2JS
82
97
  elsif node.respond_to?(:type) && node.children[1] == :default
83
98
  put 'default '
84
99
  args[0] = node.children[2]
85
- elsif node.respond_to?(:type) && node.type == :lvasgn
100
+ elsif node.respond_to?(:type) && [:lvasgn, :casgn].include?(node.type)
86
101
  if node.children[0] == :default
87
102
  put 'default '
88
103
  args[0] = node.children[1]
@@ -6,7 +6,7 @@ module Ruby2JS
6
6
  # (resbody nil nil
7
7
  # (send nil :b)) nil)
8
8
  handle :rescue do |*statements|
9
- parse_all s(:kwbegin, s(:rescue, *statements))
9
+ parse s(:kwbegin, s(:rescue, *statements)), @state
10
10
  end
11
11
 
12
12
  # (kwbegin
@@ -19,7 +19,14 @@ module Ruby2JS
19
19
 
20
20
  handle :kwbegin do |*children|
21
21
  block = children.first
22
- if block.type == :ensure
22
+
23
+ if @state == :expression
24
+ parse s(:send, s(:block, s(:send, nil, :proc), s(:args),
25
+ s(:begin, s(:autoreturn, *children))), :[])
26
+ return
27
+ end
28
+
29
+ if block&.type == :ensure
23
30
  block, finally = block.children
24
31
  else
25
32
  finally = nil
@@ -5,12 +5,24 @@ module Ruby2JS
5
5
  # (float 1.1)
6
6
  # (str "1"))
7
7
 
8
- handle :int, :float, :str do |value|
8
+ handle :str do |value|
9
9
  put value.inspect
10
10
  end
11
11
 
12
+ handle :int, :float do |value|
13
+ put number_format(value)
14
+ end
15
+
12
16
  handle :octal do |value|
13
- put '0' + value.to_s(8)
17
+ put '0' + number_format(value.to_s(8))
18
+ end
19
+
20
+ def number_format(number)
21
+ return number.to_s unless es2021
22
+ parts = number.to_s.split('.')
23
+ parts[0] = parts[0].gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1_")
24
+ parts[1] = parts[1].gsub(/(\d\d\d)(?=\d)/, "\\1_") if parts[1]
25
+ parts.join('.')
14
26
  end
15
27
  end
16
28
  end
@@ -57,7 +57,7 @@ module Ruby2JS
57
57
  else
58
58
  group = LOGICAL.include?( expr.type ) &&
59
59
  operator_index( :not ) < operator_index( expr.type )
60
- group = true if expr and expr.type == :begin
60
+ group = true if expr and %i[begin in?].include? expr.type
61
61
 
62
62
  put '!'; put '(' if group; parse expr; put ')' if group
63
63
  end
@@ -4,14 +4,43 @@ module Ruby2JS
4
4
  # (module
5
5
  # (const nil :A)
6
6
  # (...)
7
+ #
8
+ # Note: modules_hash is an anonymous modules as a value in a hash; the
9
+ # name has already been output so should be ignored other than
10
+ # in determining the namespace.
11
+
12
+ handle :module, :module_hash do |name, *body|
13
+ extend = @namespace.enter(name)
14
+
15
+ if body == [nil]
16
+ if @ast.type == :module and not extend
17
+ parse @ast.updated(:casgn, [*name.children, s(:hash)])
18
+ else
19
+ parse @ast.updated(:hash, [])
20
+ end
21
+
22
+ @namespace.leave
23
+ return
24
+ end
7
25
 
8
- handle :module do |name, *body|
9
26
  while body.length == 1 and body.first.type == :begin
10
27
  body = body.first.children
11
28
  end
12
29
 
13
- if body.length > 0 and body.all? {|child| child.type == :def}
14
- parse @ast.updated(:class_module, [name, nil, *body])
30
+ if body.length > 0 and body.all? {|child|
31
+ %i[def module].include? child.type or
32
+ (es2015 and child.type == :class and child.children[1] == nil)}
33
+
34
+ if extend
35
+ parse s(:assign, name, @ast.updated(:class_module,
36
+ [nil, nil, *body])), :statement
37
+ elsif @ast.type == :module_hash
38
+ parse @ast.updated(:class_module, [nil, nil, *body])
39
+ else
40
+ parse @ast.updated(:class_module, [name, nil, *body])
41
+ end
42
+
43
+ @namespace.leave
15
44
  return
16
45
  end
17
46
 
@@ -42,6 +71,8 @@ module Ruby2JS
42
71
  symbols << node.children.first
43
72
  elsif node.type == :class and node.children.first.children.first == nil
44
73
  symbols << node.children.first.children.last
74
+ elsif node.type == :module
75
+ symbols << node.children.first.children.last
45
76
  end
46
77
  end
47
78
 
@@ -50,11 +81,17 @@ module Ruby2JS
50
81
 
51
82
  body = s(:send, s(:block, s(:send, nil, :proc), s(:args),
52
83
  s(:begin, *body)), :[])
53
- if name.children.first == nil
84
+ if not name
85
+ parse body
86
+ elsif extend
87
+ parse s(:assign, name, body)
88
+ elsif name.children.first == nil
54
89
  parse s(:lvasgn, name.children.last, body)
55
90
  else
56
91
  parse s(:send, name.children.first, "#{name.children.last}=", body)
57
92
  end
93
+
94
+ @namespace.leave
58
95
  end
59
96
  end
60
97
  end
@@ -12,6 +12,14 @@ module Ruby2JS
12
12
  var = s(:lvar, var.children.first) if var.type == :lvasgn
13
13
  var = s(:cvar, var.children.first) if var.type == :cvasgn
14
14
 
15
+ if var.type == :lvar
16
+ name = var.children.first
17
+ receiver = @rbstack.map {|rb| rb[name]}.compact.last
18
+ if receiver
19
+ var = s(:attr, nil, name)
20
+ end
21
+ end
22
+
15
23
  if \
16
24
  [:+, :-].include?(op) and value.type==:int and
17
25
  (value.children==[1] or value.children==[-1])
@@ -14,7 +14,8 @@ module Ruby2JS
14
14
 
15
15
  EXPRESSIONS = [ :array, :float, :hash, :int, :lvar, :nil, :send, :attr,
16
16
  :str, :sym, :dstr, :dsym, :cvar, :ivar, :zsuper, :super, :or, :and,
17
- :block, :const, :true, :false, :xnode, :taglit, :self ]
17
+ :block, :const, :true, :false, :xnode, :taglit, :self,
18
+ :op_asgn, :and_asgn, :or_asgn ]
18
19
 
19
20
  handle :autoreturn do |*statements|
20
21
  return if statements == [nil]
@@ -9,11 +9,12 @@ module Ruby2JS
9
9
  # (sendw nil :puts
10
10
  # (int 1))
11
11
 
12
- # Note: attr, sendw, and await are only generated by filters. Attr forces
12
+ # Note: attr, sendw, send!, and await are only generated by filters. Attr forces
13
13
  # interpretation as an attribute vs a function call with zero parameters.
14
+ # send! forces interpretation as a method call even with zero parameters.
14
15
  # Sendw forces parameters to be placed on separate lines.
15
16
 
16
- handle :send, :sendw, :await, :attr, :call do |receiver, method, *args|
17
+ handle :send, :sendw, :send!, :await, :attr, :call do |receiver, method, *args|
17
18
  ast = @ast
18
19
 
19
20
  if \
@@ -40,12 +41,26 @@ module Ruby2JS
40
41
  # strip '!' and '?' decorations
41
42
  method = method.to_s[0..-2] if method =~ /\w[!?]$/
42
43
 
44
+ # anonymous class
45
+ if method == :new and receiver and receiver.children == [nil, :Class] and
46
+ args.last.type == :def and args.last.children.first == nil
47
+
48
+ parent = (args.length > 1) ? args.first : nil
49
+
50
+ if es2015
51
+ return parse s(:class2, nil, parent, *args.last.children[2..-1])
52
+ else
53
+ return parse s(:kwbegin, s(:class, s(:const, nil, :$$), parent,
54
+ *args.last.children[2..-1]), s(:const, nil, :$$))
55
+ end
56
+ end
57
+
43
58
  # three ways to define anonymous functions
44
59
  if method == :new and receiver and receiver.children == [nil, :Proc]
45
60
  return parse args.first, @state
46
61
 
47
62
  elsif not receiver and [:lambda, :proc].include? method
48
- if method == :lambda
63
+ if method == :lambda and @state != :statement
49
64
  return parse s(args.first.type, *args.first.children[0..-2],
50
65
  s(:autoreturn, args.first.children[-1])), @state
51
66
  else
@@ -60,10 +75,17 @@ module Ruby2JS
60
75
  (es2015 || @state == :statement ? group(receiver) : parse(receiver))
61
76
  put '('; parse_all(*args, join: ', '); put ')'
62
77
  return
78
+ elsif not t2 and m2 == :async and args2.length == 0
79
+ put '('; parse receiver; put ')()'
80
+ return
63
81
  end
64
82
  end
65
83
 
66
84
  # async/await support
85
+ # map "await x do...end" to "await x {...}" due to precedence rules
86
+ if method == :await and es2017 and receiver == nil and args.length == 2 and args[1].type == :def
87
+ args = [s(:block, args.first, *args.last.children[1..-1])]
88
+ end
67
89
  if es2017 and receiver == nil and args.length == 1
68
90
  if method == :async
69
91
  if args.first.type == :def
@@ -74,6 +96,15 @@ module Ruby2JS
74
96
  # async def o.m(x) {...}
75
97
  return parse args.first.updated :asyncs
76
98
 
99
+ elsif args.first.type == :send and
100
+ args.first.children.first.type == :block and
101
+ args.first.children.last == :[]
102
+
103
+ put '(async '
104
+ parse args.first.children.first, :statement
105
+ put ')()'
106
+ return
107
+
77
108
  elsif args.first.type == :block
78
109
  block = args.first
79
110
 
@@ -117,8 +148,13 @@ module Ruby2JS
117
148
 
118
149
  # resolve anonymous receivers against rbstack
119
150
  receiver ||= @rbstack.map {|rb| rb[method]}.compact.last
151
+ autobind = nil
120
152
 
121
153
  if receiver
154
+ if receiver.type == :autobind
155
+ autobind = receiver = receiver.children.first
156
+ end
157
+
122
158
  group_receiver = receiver.type == :send &&
123
159
  op_index < operator_index( receiver.children[1] ) if receiver
124
160
  group_receiver ||= GROUP_OPERATORS.include? receiver.type
@@ -137,6 +173,8 @@ module Ruby2JS
137
173
  group_target ||= GROUP_OPERATORS.include? target.type
138
174
  end
139
175
 
176
+ put 'await ' if @ast.type == :await
177
+
140
178
  if method == :!
141
179
  parse s(:not, receiver)
142
180
 
@@ -152,7 +190,7 @@ module Ruby2JS
152
190
  end
153
191
 
154
192
  elsif method == :[]=
155
- parse receiver
193
+ (group_receiver ? group(receiver) : parse(receiver))
156
194
  if \
157
195
  args.length == 2 and [:str, :sym].include? args.first.type and
158
196
  args.first.children.first.to_s =~ /^[a-zA-Z]\w*$/
@@ -175,9 +213,15 @@ module Ruby2JS
175
213
  receiver.type == :send and
176
214
  receiver.children[1] == :+@ and
177
215
  Parser::AST::Node === receiver.children[0] and
178
- receiver.children[0].type == :class
216
+ %i(class module).include? receiver.children[0].type
179
217
  then
180
- parse receiver.children[0].updated(:class_extend)
218
+ if receiver.children[0].type == :class
219
+ parse receiver.children[0].updated(:class_extend)
220
+ else
221
+ mod = receiver.children[0]
222
+ parse s(:assign, mod.children[0],
223
+ mod.updated(nil, [nil, *mod.children[1..-1]]))
224
+ end
181
225
  else
182
226
  put method.to_s[0]; parse receiver
183
227
  end
@@ -277,10 +321,23 @@ module Ruby2JS
277
321
  elsif method == :typeof and receiver == nil
278
322
  put 'typeof '; parse args.first
279
323
 
324
+ elsif ast.children[1] == :is_a? and receiver and args.length == 1
325
+ parse receiver; put ' instanceof '; parse args.first
326
+
327
+ elsif ast.children[1] == :kind_of? and receiver and args.length == 1
328
+ parse receiver; put ' instanceof '; parse args.first
329
+
330
+ elsif ast.children[1] == :instance_of? and receiver and args.length == 1
331
+ parse s(:send, s(:attr, receiver, :constructor), :==, args.first)
332
+
280
333
  else
281
- put 'await ' if @ast.type == :await
334
+ if method == :bind and receiver&.type == :send
335
+ if receiver.children.length == 2 and receiver.children.first == nil
336
+ receiver = receiver.updated(:attr) # prevent autobind
337
+ end
338
+ end
282
339
 
283
- if not ast.is_method?
340
+ if not ast.is_method? and ast.type != :send!
284
341
  if receiver
285
342
  (group_receiver ? group(receiver) : parse(receiver))
286
343
  put ".#{ method }"
@@ -302,6 +359,14 @@ module Ruby2JS
302
359
  compact { puts "("; parse_all(*args, join: ",#@ws"); sput ')' }
303
360
  end
304
361
  end
362
+
363
+ if autobind and not ast.is_method? and ast.type != :attr
364
+ if @state == :statement
365
+ put '()'
366
+ else
367
+ put '.bind('; parse(autobind); put ')'
368
+ end
369
+ end
305
370
  end
306
371
  end
307
372