red 3.5.0 → 4.0.0

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.
@@ -0,0 +1,126 @@
1
+ module Red
2
+ class ControlNode < String # :nodoc:
3
+ class Begin < ControlNode # :nodoc:
4
+ # [:begin, {expression | :block}]
5
+ def initialize(body_sexp, options)
6
+ body = body_sexp.red!(:force_return => options[:as_assignment] || options[:as_receiver] || options[:as_argument] || options[:force_return])
7
+ self << "%s" % [body]
8
+ end
9
+ end
10
+
11
+ class Ensure < ControlNode # :nodoc:
12
+ # [:ensure, {expression | :block}, {expression | :block}]
13
+ def initialize(attempted_sexp, ensure_body_sexp, options)
14
+ #string = (options[:as_argument] || options[:force_return] ? "function(){%s;}()" : "%s") % [string]
15
+
16
+ attempted = (attempted_sexp.is_sexp?(:block, :rescue) ? attempted_sexp : [:block, attempted_sexp]).red!(:force_return => options[:force_return])
17
+ ensure_body = (ensure_body_sexp.is_sexp?(:block) ? ensure_body_sexp : [:block, ensure_body_sexp]).red!(:force_return => options[:force_return])
18
+ string = attempted_sexp.is_sexp?(:rescue) ? "%sfinally{%s;}" : "try{%s;}finally{%s;}"
19
+
20
+ self << string % [attempted, ensure_body]
21
+ end
22
+ end
23
+
24
+ class Rescue < ControlNode # :nodoc:
25
+ # [:rescue, (expression | :block), {:resbody}]
26
+ def initialize(attempted_sexp, rescue_body_sexp, options = {})
27
+ (options = rescue_body_sexp) && (rescue_body_sexp = attempted_sexp) && (attempted_sexp = [:nil]) if rescue_body_sexp.is_a?(Hash)
28
+
29
+ string = "try{%s;}catch(_e){_eRescued=false;%s;if(!_eRescued){throw(_e);};}"
30
+ if options[:as_argument] || options[:as_assignment]
31
+ string = "function(){%s;}.m$(this)()" % string
32
+ options[:force_return] = true
33
+ end
34
+ attempted = (attempted_sexp.is_sexp?(:block) ? attempted_sexp : [:block, attempted_sexp]).red!(:force_return => options[:force_return])
35
+ rescue_body = rescue_body_sexp.red!(:force_return => options[:force_return])
36
+
37
+ self << "try{%s;}catch(_e){_eRescued=false;%s;if(!_eRescued){throw(_e);};}" % [attempted, rescue_body]
38
+ end
39
+ end
40
+
41
+ class RescueBody < ControlNode # :nodoc:
42
+ # [:resbody, {nil | [:array, {expression}, {expression}, ...]}, (expression | :block), (:resbody)]
43
+ def initialize(exception_types_array_sexp, block_sexp, rescue_body_sexp = nil, options = {})
44
+ (options = block_sexp) && (block_sexp = nil) if block_sexp.is_a?(Hash)
45
+ (options = rescue_body_sexp) && (block_sexp.first==:resbody ? (rescue_body_sexp = block_sexp && block_sexp = nil) : (rescue_body_sexp = nil)) if rescue_body_sexp.is_a?(Hash)
46
+
47
+ if block_sexp.is_sexp?(:block) && block_sexp[1].is_sexp?(:lasgn) && block_sexp[1].last == [:gvar, %s($!)]
48
+ exception_variable = "var %s=_e;" % block_sexp.delete(block_sexp.assoc(:lasgn))[1].red!
49
+ elsif block_sexp.is_sexp?(:lasgn) && block_sexp.last == [:gvar, %s($!)]
50
+ exception_variable = "var %s=_e;" % block_sexp[1].red!
51
+ block_sexp = [:nil]
52
+ end
53
+
54
+ exception_types_array = (exception_types_array_sexp || [:array, [:const, :Exception]]).red!
55
+ block = (block_sexp.is_sexp?(:block) ? block_sexp : [:block, block_sexp]).red!(:force_return => options[:force_return])
56
+ rescue_body = "else{%s;}" % rescue_body_sexp.red!(:force_return => options[:force_return]) if rescue_body_sexp
57
+
58
+ self << "%sif($eType(_e,%s)){_eRescued=true;%s;}%s" % [exception_variable, exception_types_array, block, rescue_body]
59
+ end
60
+ end
61
+
62
+ class For < ControlNode # :nodoc:
63
+ # [:for, {expression}, {expression}, {expression | :block}]
64
+ def initialize(source_sexp, iterator_assignment_sexp, body_sexp, options)
65
+ body = body_sexp.red!
66
+ unless source_sexp.is_sexp?(:xstr, :dxstr)
67
+ source = source_sexp.red!(:as_argument => true)
68
+ iterator = iterator_assignment_sexp.last.red!
69
+ self << "for(var %s in %s){%s;}" % [iterator, source, body]
70
+ else
71
+ loop_statement = source_sexp.red!
72
+ self << "for(%s){%s;}" % [loop_statement, body]
73
+ end
74
+ end
75
+ end
76
+
77
+ class Keyword < ControlNode # :nodoc:
78
+ # [:break, (expression)]
79
+ # [:next, (expression)]
80
+ def initialize(*arguments_array_sexp)
81
+ options = arguments_array_sexp.pop
82
+ arguments = arguments_array_sexp.map {|arg| arg.red!(:as_argument => true) }.join(",")
83
+ keyword = self.class.to_s.split('::').last.downcase
84
+ self << "$%s(%s)" % [keyword, arguments]
85
+ end
86
+
87
+ class Break < Keyword # :nodoc:
88
+ end
89
+
90
+ class Next < Keyword # :nodoc:
91
+ end
92
+
93
+ class Redo < Keyword # :nodoc:
94
+ end
95
+ end
96
+
97
+ class Loop < ControlNode # :nodoc:
98
+ # [:until, {expression}, {expression | :block}, true | false]
99
+ # [:while, {expression}, {expression | :block}, true | false]
100
+ def initialize(condition_sexp, body_sexp, run_only_if_condition_met, options)
101
+ condition = (self.is_a?(Until) ? "!$T(%s)" : "$T(%s)") % [condition_sexp.red!(:as_argument => true)]
102
+ body = body_sexp.red!
103
+ if run_only_if_condition_met
104
+ self << "while(%s){%s;}" % [condition, body]
105
+ else
106
+ self << "do{%s;}while(%s)" % [body, condition]
107
+ end
108
+ end
109
+
110
+ class Until < Loop # :nodoc:
111
+ end
112
+
113
+ class While < Loop # :nodoc:
114
+ end
115
+ end
116
+
117
+ class Return < ControlNode # :nodoc:
118
+ # [:return, (expression)]
119
+ def initialize(expression_sexp = nil, options = {})
120
+ (options = expression_sexp) && (expression_sexp = [:nil]) if expression_sexp.is_a?(Hash)
121
+ expression = expression_sexp.red!(:as_argument => true)
122
+ self << "return(%s)" % [expression]
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,75 @@
1
+ module Red
2
+ class DataNode < String # :nodoc:
3
+ class Error < DataNode # :nodoc:
4
+ end
5
+
6
+ class Nil < DataNode # :nodoc:
7
+ # nil
8
+ def initialize(value_data, options)
9
+ self << ""
10
+ end
11
+ end
12
+
13
+ class Numeric < DataNode # :nodoc:
14
+ # 1
15
+ def initialize(value_data, options)
16
+ value = value_data.inspect
17
+ string = options[:as_receiver] ? "(%s)" : "%s"
18
+ self << string % [value]
19
+ end
20
+ end
21
+
22
+ class Range < DataNode # :nodoc:
23
+ # 1..2
24
+ def initialize(value_data, options)
25
+ start = value_data.begin
26
+ finish = value_data.end
27
+ exclusive = value_data.exclude_end?.inspect
28
+ self << "c$Range.m$new(%s,%s,%s)" % [start, finish, exclusive]
29
+ end
30
+ end
31
+
32
+ class Regexp < DataNode # :nodoc:
33
+ # /foo/mi
34
+ def initialize(value_data, options)
35
+ source = value_data.source
36
+ options = 0
37
+ options += 1 if value_data.to_s.match(/\(\?[^-]*i.*-*/)
38
+ options += 2 if value_data.to_s.match(/\(\?[^-]*x.*-*/)
39
+ options += 4 if value_data.to_s.match(/\(\?[^-]*m.*-*/)
40
+ self << "'%s',%s" % [source.gsub('\\','\\\\\\\\'),options]
41
+ end
42
+ end
43
+
44
+ class String < DataNode # :nodoc:
45
+ # 'foo'
46
+ def initialize(value_data, options)
47
+ value = options[:no_escape] ? value_data : value_data.gsub(/'/, "\\\\'")
48
+ string = options[:unquoted] ? "%s" % [value] : "%s" % [value.inspect]
49
+ self << string
50
+ end
51
+ end
52
+
53
+ class Symbol < DataNode # :nodoc:
54
+ # :foo
55
+ def initialize(value_data, options)
56
+ value = self.camelize(value_data.to_s, options[:not_camelized])
57
+ string = options[:as_receiver] ? "$q('%s')" : options[:as_argument] ? "'%s'" : "%s"
58
+ self << string % [value]
59
+ end
60
+
61
+ def camelize(string, disabled = false)
62
+ return string unless self.camelize?(string) && !disabled
63
+ words = string.gsub(/@/,'').gsub('?','_bool').gsub('!','_bang').gsub('=','_eql').split(/_/)
64
+ underscore = words.shift if words.first.empty?
65
+ return (underscore ? '_' : '') + words[0] + words[1..-1].map {|word| word == word.upcase ? word : word.capitalize }.join
66
+ end
67
+
68
+ def camelize?(string)
69
+ is_not_a_constant_name = string != string.upcase || string =~ (/@|\$/)
70
+ is_not_a_js_special_attribute = string[0..1] != '__'
71
+ return is_not_a_constant_name && is_not_a_js_special_attribute
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,191 @@
1
+ module Red
2
+ class DefinitionNode < String # :nodoc:
3
+ class Alias < DefinitionNode # :nodoc:
4
+ def initialize(new_method_name_sexp, old_method_name_sexp, options)
5
+ new_method_name = new_method_name_sexp.last.red!
6
+ old_method_name = old_method_name_sexp.last.red!
7
+ self << "_.m$%s=_.m$%s" % [new_method_name, old_method_name]
8
+ @@red_methods |= [old_method_name_sexp.last] unless @@red_import
9
+ end
10
+ end
11
+
12
+ class Class < DefinitionNode # :nodoc:
13
+ # [:class, :Foo, (expression), [:scope, (expression | :block)]] => superclass doesn't show up sometimes when namespaced a certain way; I forgot what the pattern is though
14
+ def initialize(class_name_sexp, superclass_sexp, scope_sexp, options = {})
15
+ (options = scope_sexp) && (scope_sexp = superclass_sexp) && (superclass_sexp = nil) if scope_sexp.is_a?(Hash)
16
+ superclass = (superclass_sexp || [:const, :Object]).red!
17
+ class_name = "%s" % class_name_sexp.red!
18
+
19
+ if class_name_sexp.is_sexp?(:colon3)
20
+ old_namespace_stack = @@namespace_stack
21
+ namespaced_class = class_name
22
+ @@namespace_stack = [namespaced_class]
23
+ elsif class_name_sexp.is_sexp?(:colon2)
24
+ @@namespace_stack.push(class_name)
25
+ namespaced_class = class_name
26
+ class_name = class_name_sexp.last.red!
27
+ else
28
+ class_name = "c$%s" % class_name_sexp.red!
29
+ @@namespace_stack.push(class_name)
30
+ namespaced_class = @@namespace_stack.join(".")
31
+ end
32
+ @@red_constants |= [namespaced_class]
33
+
34
+ scope = scope_sexp.red!(:as_class_eval => true)
35
+
36
+ self << "\n\n$class('%s',%s,function(){ var _=%s.prototype;\n %s;\n})" % [namespaced_class.gsub("c$",""), superclass, namespaced_class, scope]
37
+
38
+ old_namespace_stack.nil? ? @@namespace_stack.pop : @@namespace_stack = old_namespace_stack
39
+ end
40
+ end
41
+
42
+ class Module < DefinitionNode # :nodoc:
43
+ # [:module, :Foo, [:scope, (expression | :block)]]
44
+ def initialize(module_name_sexp, scope_sexp, options)
45
+ module_name = "%s" % module_name_sexp.red!
46
+
47
+ if module_name_sexp.is_sexp?(:colon3)
48
+ old_namespace_stack = @@namespace_stack
49
+ namespaced_module = module_name
50
+ @@namespace_stack = [namespaced_module]
51
+ elsif module_name_sexp.is_sexp?(:colon2)
52
+ namespaced_module = module_name
53
+ module_name = module_name_sexp.last.red!
54
+ @@namespace_stack.push(module_name)
55
+ else
56
+ module_name = "c$%s" % module_name_sexp.red!
57
+ @@namespace_stack.push(module_name)
58
+ namespaced_module = @@namespace_stack.join(".")
59
+ end
60
+ @@red_constants |= [namespaced_module]
61
+
62
+ scope = scope_sexp.red!(:as_class_eval => true)
63
+
64
+ self << "\n\n$module('%s',function(){ var _=%s.prototype;\n %s;\n})" % [namespaced_module.gsub("c$",""), namespaced_module, scope]
65
+
66
+ @@namespace_stack.pop
67
+ end
68
+ end
69
+
70
+ class Method < DefinitionNode # :nodoc:
71
+ # def args_and_contents_from(scope, function)
72
+ # block = scope.assoc(:block) || scope
73
+ # block_arg = block.delete(block.assoc(:block_arg)) || ([:block_arg, :block] if block.flatten.include?(:yield))
74
+ # arguments = block.assoc(:args) ? block.assoc(:args)[1..-1] || [] : []
75
+ # defaults = arguments.delete(arguments.assoc(:block))
76
+ # splat_arg = arguments.pop.to_s[1..-1] if arguments.last && arguments.last.to_s.include?('*')
77
+ # arguments = (block_arg ? arguments << block_arg.last : arguments).map {|arg| arg.red!}
78
+ # block_given = "var blockGivenBool=(typeof(arguments[arguments.length-1])=='function')" if block_arg
79
+ # args_array = "var blockGivenBool;var l=(blockGivenBool?arguments.length-1:arguments.length);#{splat_arg}=[];for(var i=#{block_arg ? arguments.size - 1 : arguments.size};i<l;++i){#{splat_arg}.push(arguments[i]);};var block=(blockGivenBool?arguments[arguments.length-1]:nil)" if splat_arg
80
+ # contents = [block_given, args_array, defaults.red!(:as_argument_default => true), scope.red!(:force_return => function != 'initialize')].compact.reject {|x| x.empty? }
81
+ # return [arguments, contents]
82
+ # end
83
+
84
+ class Instance < Method # :nodoc:
85
+ # [:defn, :foo, [:scope, [:block, [:args, (:my_arg1, :my_arg2, ..., :'*my_args', (:block))], (:block_arg, :my_block), {expression}, {expression}, ...]]
86
+ def initialize(function_name_sexp, scope_sexp, options)
87
+ return if @@red_import && !@@red_methods.include?(function_name_sexp)
88
+ function = (METHOD_ESCAPE[function_name_sexp] || function_name_sexp).red!
89
+ @@red_function = function
90
+ block_sexp = scope_sexp.assoc(:block)
91
+ block_arg_sexp = block_sexp.delete(block_sexp.assoc(:block_arg)) || ([:block_arg, :_block] if block_sexp.flatten.include?(:yield))
92
+ @@red_block_arg = block_arg_sexp.last if block_arg_sexp
93
+ argument_sexps = block_sexp.assoc(:args)[1..-1] || []
94
+ defaults_sexp = argument_sexps.delete(argument_sexps.assoc(:block))
95
+ splat_arg = argument_sexps.pop.to_s[1..-1] if argument_sexps.last && argument_sexps.last.to_s.include?('*')
96
+ argument_sexps += [block_arg_sexp.last] if block_arg_sexp
97
+ args_array = argument_sexps.map {|argument| argument.red! }
98
+ splatten_args = "for(var bg=m$blockGivenBool(arguments[arguments.length-1]),l=bg?arguments.length-1:arguments.length,i=#{block_arg_sexp ? argument_sexps.size - 1 : argument_sexps.size},#{splat_arg}=[];i<l;++i){#{splat_arg}.push(arguments[i]);};var #{block_arg_sexp.last rescue :_block}=(bg?c$Proc.m$new(arguments[arguments.length-1]):nil)" if splat_arg
99
+ block_arg = "var #{block_arg_sexp.last rescue :_block}=(m$blockGivenBool(arguments[arguments.length-1])?c$Proc.m$new(arguments[arguments.length-1]):nil)" if block_arg_sexp && !splat_arg
100
+ defaults = defaults_sexp.red!(:as_argument_default => true) if defaults_sexp
101
+ arguments = args_array.join(",")
102
+ scope = scope_sexp.red!(:force_return => function != 'initialize')
103
+ contents = [splatten_args, block_arg, defaults, scope].compact.join(";")
104
+ if options[:as_class_eval]
105
+ string = "_.m$%s=function(%s){%s;}"
106
+ else
107
+ string = "m$%s=function(%s){%s;}"
108
+ end
109
+ self << string % [function, arguments, contents]
110
+ @@red_block_arg = nil
111
+ @@red_function = nil
112
+ end
113
+ end
114
+
115
+ class Singleton < Method # :nodoc:
116
+ # [:defs, {expression}, :foo, [:scope, (:block, [:args, (:my_arg1, :my_arg2, ..., :'*my_args', (:block))], (:block_arg, :my_block), {expression}, {expression}, ...)]
117
+ def initialize(object_sexp, function_name_sexp, scope_sexp, options)
118
+ return if @@red_import && !@@red_methods.include?(function_name_sexp)
119
+ function = (METHOD_ESCAPE[function_name_sexp] || function_name_sexp).red!
120
+ @@red_function = function
121
+ object = object_sexp.is_sexp?(:self) ? @@namespace_stack.join(".") : object_sexp.red!
122
+ singleton = "%s.m$%s" % [object, function]
123
+ block_sexp = scope_sexp.assoc(:args) ? (scope_sexp << [:block, scope_sexp.delete(scope_sexp.assoc(:args)), [:nil]]).assoc(:block) : scope_sexp.assoc(:block)
124
+ block_arg_sexp = block_sexp.delete(block_sexp.assoc(:block_arg)) || ([:block_arg, :_block] if block_sexp.flatten.include?(:yield))
125
+ @@red_block_arg = block_arg_sexp.last if block_arg_sexp
126
+ block_sexp = [[:nil]] if block_sexp.empty?
127
+ argument_sexps = block_sexp.assoc(:args)[1..-1] || []
128
+ defaults_sexp = argument_sexps.delete(argument_sexps.assoc(:block))
129
+ splat_arg = argument_sexps.pop.to_s[1..-1] if argument_sexps.last && argument_sexps.last.to_s.include?('*')
130
+ argument_sexps += [block_arg_sexp.last] if block_arg_sexp
131
+ args_array = argument_sexps.map {|argument| argument.red! }
132
+ splatten_args = "for(var bg=m$blockGivenBool(arguments[arguments.length-1]),l=bg?arguments.length-1:arguments.length,i=#{block_arg_sexp ? argument_sexps.size - 1 : argument_sexps.size},#{splat_arg}=[];i<l;++i){#{splat_arg}.push(arguments[i]);};var #{block_arg_sexp.last rescue :_block}=(bg?c$Proc.m$new(arguments[arguments.length-1]):nil)" if splat_arg
133
+ block_arg = "var #{block_arg_sexp.last rescue :_block}=(m$blockGivenBool(arguments[arguments.length-1])?c$Proc.m$new(arguments[arguments.length-1]):nil)" if block_arg_sexp && !splat_arg
134
+ defaults = defaults_sexp.red!(:as_argument_default => true) if defaults_sexp
135
+ arguments = args_array.join(",")
136
+ scope = scope_sexp.red!(:force_return => function != 'initialize')
137
+ contents = [splatten_args, block_arg, defaults, scope].compact.join(";")
138
+ self << "%s=function(%s){%s;}" % [singleton, arguments, contents]
139
+ @@red_block_arg = nil
140
+ @@red_function = nil
141
+ end
142
+ end
143
+ end
144
+
145
+ class Scope < DefinitionNode # :nodoc:
146
+ # [:scope, (expression | :block)]
147
+ def initialize(contents_sexp = nil, options = {})
148
+ (options = contents_sexp) && (contents_sexp = [:block]) if contents_sexp.is_a?(::Hash)
149
+ variables = []
150
+ contents_sexp.flatten.each_with_index do |x,i|
151
+ variables.push(contents_sexp.flatten[i + 1]) if [:lasgn,:vcall].include?(x)
152
+ end
153
+ variables -= (contents_sexp.delete(contents_sexp.assoc(:args)) || [])[1..-1] || [] # don't want to undefine the arguments in a method definition
154
+ declare = "var %s" % variables.map {|x| "%s=$u" % x.red! }.uniq.join(",") unless variables.empty?
155
+ contents = [declare, contents_sexp.red!(options)].compact.join(";#{options[:as_class_eval] ? "\n " : ''}")
156
+ self << "%s" % contents
157
+ end
158
+ end
159
+
160
+ class SingletonClass < DefinitionNode # :nodoc:
161
+ # [:sclass, {expression}, [:scope, (expression | :block)]]
162
+ #def initialize(receiver, scope)
163
+ # old_class = @@red_class
164
+ # @@red_class = @class = receiver.build_node.compile_node
165
+ # block_node = scope.assoc(:block) || scope
166
+ # properties = block_node.select {|node| (node.first == :cvdecl) rescue false }
167
+ # functions = block_node.select {|node| ![:block, :scope].include?(node) }
168
+ # @slots = (properties | functions).build_nodes
169
+ # @@red_class = old_class
170
+ #end
171
+ #
172
+ #def compile_node(options = {})
173
+ # old_class = @@red_class
174
+ # @@red_class = @class
175
+ # slots = @slots.compile_nodes(:as_property => true).compact.join(', ')
176
+ # @@red_class = old_class
177
+ # return "{ %s }" % [slots]
178
+ #end
179
+ end
180
+
181
+ class Undef < DefinitionNode # :nodoc:
182
+ # [:undef, {expression}]
183
+ def initialize(function_name_sexp, options)
184
+ return if @@red_import && !@@red_methods.include?(function_name_sexp)
185
+ function_sexp = function_name_sexp.last.red!
186
+ namespaced_function = @@namespace_stack.empty? ? function_sexp : (@@namespace_stack + ['prototype', "m$%s" % function_sexp]).join('.')
187
+ self << "delete %s" % [namespaced_function]
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,33 @@
1
+ module Red
2
+ class IllegalNode # :nodoc:
3
+ class FlipflopNode < IllegalNode # :nodoc:
4
+ def initialize(*args)
5
+ raise(BuildError::NoFlipflops, "Flip-flop operators are not supported")
6
+ end
7
+ end
8
+
9
+ class MatchNode < IllegalNode # :nodoc:
10
+ def initialize(*args)
11
+ raise(BuildError::NoArbitraryMatch, "Boolean matching is not supported")
12
+ end
13
+ end
14
+
15
+ class PostexeNode < IllegalNode # :nodoc:
16
+ def initialize(*args)
17
+ raise(BuildError::NoBEGINorEND, "BEGIN and END blocks are not supported")
18
+ end
19
+ end
20
+
21
+ class RegexEvaluationNode < IllegalNode # :nodoc:
22
+ def initialize(*args)
23
+ raise(BuildError::NoRegexEvaluation, "Construction of regular expressions with evaluated content is not supported")
24
+ end
25
+ end
26
+
27
+ class RetryNode < IllegalNode # :nodoc:
28
+ def initialize(*args)
29
+ raise(BuildError::NoRetry, "Retry is not supported")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,148 @@
1
+ module Red
2
+ class LiteralNode < String # :nodoc:
3
+ class Array < LiteralNode # :nodoc:
4
+ # [:zarray]
5
+ # [:to_ary, {expression}]
6
+ # [:array, {expression}, {expression}, ...]
7
+ def initialize(*element_sexps)
8
+ options = element_sexps.pop
9
+ elements = element_sexps.map {|element_sexp| element_sexp.red!(:as_argument => true)}.join(",")
10
+ self << "[%s]" % [elements]
11
+ end
12
+ end
13
+
14
+ class Hash < LiteralNode # :nodoc:
15
+ # [:hash, ({expression->key}, {expression->value}, ...)]
16
+ def initialize(*element_sexps)
17
+ options = element_sexps.pop
18
+ elements = element_sexps.map {|element_sexp| element_sexp.red!(:as_argument => true)}.join(",")
19
+ self << "c$Hash.m$_brkt(%s)" % [elements]
20
+ end
21
+ end
22
+
23
+ class Multiline < LiteralNode # :nodoc:
24
+ # [:block, {expression}, {expression}, ...]
25
+ def initialize(*expression_sexps)
26
+ # force_return: changes final expression to "return <expression>",
27
+ # unless there is already return anywhere inside <expression>.
28
+ # as_argument: duplicates :force_return and adds "function() {
29
+ # <multiline block>; }()" wrapper to the entire block.
30
+ options = expression_sexps.pop
31
+ if options[:as_argument] || options[:as_assignment] || options[:force_return] && expression_sexps.last.is_a?(::Array) && !expression_sexps.last.is_sexp?(:rescue, :ensure, :begin) && (expression_sexps.last.first == :iter ? true : !expression_sexps.last.flatten.include?(:return))
32
+ returner = "return %s" % [expression_sexps.pop.red!(:as_argument => true)]
33
+ end
34
+ string = options[:as_argument] || options[:as_assignment] ? "function(){%s;}.m$(this)()" : "%s"
35
+ lines = (expression_sexps.map {|line| line.red!(options)} + [returner]).compact.reject {|x| x == '' }.join(";#{options[:as_class_eval] ? "\n " : ''}")
36
+ self << string % [lines]
37
+ end
38
+ end
39
+
40
+ class Namespace < LiteralNode # :nodoc:
41
+ # [:colon2, {expression}, :Foo]
42
+ def initialize(namespace_sexp, class_name_sexp, options)
43
+ namespace = namespace_sexp.red!(:as_receiver => true)
44
+ class_name = class_name_sexp.red!
45
+ self << "%s.c$%s" % [namespace, class_name]
46
+ end
47
+
48
+ # [:colon3, :Foo]
49
+ class TopLevel < LiteralNode # :nodoc:
50
+ def initialize(class_name_sexp, options)
51
+ class_name = class_name_sexp.red!
52
+ self << "c$%s" % [class_name]
53
+ end
54
+ end
55
+ end
56
+
57
+ class Other < LiteralNode # :nodoc:
58
+ # [:lit, {number | regexp | range}]
59
+ # [:svalue, [:array, {expression}, {expression}, ...]]
60
+ # [:to_ary, {expression}] => right side of :masgn when arguments are too few
61
+ def initialize(value_sexp = nil, options = {})
62
+ (options = value_sexp) && (value_sexp = nil) if value_sexp.is_a?(::Hash)
63
+ symbol_sexp = [:sym, value_sexp] if value_sexp.is_a?(::Symbol)
64
+ regexp_sexp = [:regex, value_sexp] if value_sexp.is_a?(::Regexp)
65
+ value = (regexp_sexp || symbol_sexp || value_sexp).red!(options)
66
+ self << "%s" % [value]
67
+ end
68
+ end
69
+
70
+ class Range < LiteralNode # :nodoc:
71
+ # [:dot2, {expression}, {expression}]
72
+ def initialize(start_sexp, finish_sexp, options)
73
+ start = start_sexp.red!(:as_argument => true)
74
+ finish = finish_sexp.red!(:as_argument => true)
75
+ self << "c$Range.m$new(%s,%s,false)" % [start, finish]
76
+ end
77
+
78
+ class Exclusive < Range # :nodoc:
79
+ # [:dot3, {expression}, {expression}]
80
+ def initialize(start_sexp, finish_sexp, options)
81
+ start = start_sexp.red!(:as_argument => true)
82
+ finish = finish_sexp.red!(:as_argument => true)
83
+ self << "c$Range.m$new(%s,%s,true)" % [start, finish]
84
+ end
85
+ end
86
+ end
87
+
88
+ class Regexp < LiteralNode # :nodoc:
89
+ # [:lit, {regexp}]
90
+ # ### [:dregex, "foo", {expression}, {expression}, ...]
91
+ def initialize(regexp_sexp, options)
92
+ regexp = regexp_sexp.red!(:as_argument => true)
93
+ self << "$r(%s)" % [regexp]
94
+ end
95
+ end
96
+
97
+ class Splat < LiteralNode # :nodoc:
98
+ # [:splat, {expression}]
99
+ #def initialize(*args)
100
+ # case @@red_library
101
+ # when :Prototype : super(*args)
102
+ # else raise(BuildError::NoSplatConstructor, "Splat array constructor not supported for #{@@red_library} JavaScript library")
103
+ # end
104
+ #end
105
+ #
106
+ #def compile_node(options = {})
107
+ # initial = @initial.compile_node
108
+ # case @@red_library
109
+ # when :Prototype : return "$A(%s)" % [initial]
110
+ # else ""
111
+ # end
112
+ #end
113
+ end
114
+
115
+ class String < LiteralNode # :nodoc:
116
+ # [:str, "foo"]
117
+ # [:dstr, "foo", {expression}, {expression}, ...]
118
+ # [:evstr, {expression}]
119
+ def initialize(*element_sexps)
120
+ options = element_sexps.pop
121
+ elements = element_sexps.map {|element_sexp| element_sexp.red!(options.merge(:as_argument => true, :as_string_element => true)) }.join(",")
122
+ string = options[:unquoted] || options[:as_string_element] ? "%s" : element_sexps.size > 1 ? "$Q(%s)" : "$q(%s)"
123
+ self << string % [elements]
124
+ end
125
+ end
126
+
127
+ class Symbol < LiteralNode # :nodoc:
128
+ # [:lit, {symbol}]
129
+ # [:dsym, "foo", {expression}, {expression}, ...]
130
+ def initialize(*element_sexps)
131
+ options = element_sexps.pop
132
+ elements = element_sexps.map {|element_sexp| element_sexp.red!(options.merge(:as_argument => true, :as_string_element => true)) }.join(",")
133
+ string = element_sexps.size > 1 ? "$S(%s)" : "$s(%s)"
134
+ self << string % [elements]
135
+ end
136
+ end
137
+
138
+ class Uninterpreted < LiteralNode # :nodoc:
139
+ # [:xstr, "foo"]
140
+ # [:dxstr, "foo", {expression}, {expression}, ...]
141
+ def initialize(*element_sexps)
142
+ options = element_sexps.pop
143
+ elements = element_sexps.map {|element_sexp| element_sexp.red!(:unquoted => true, :no_escape => true) }.join
144
+ self << "%s" % [elements]
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,89 @@
1
+ module Red
2
+ class LogicNode < String # :nodoc:
3
+ class Boolean < LogicNode # :nodoc:
4
+ # [:false]
5
+ # [:true]
6
+ def initialize(options)
7
+ string = case self when False : "false" when True : "true" end
8
+ self << string
9
+ end
10
+
11
+ class False < Boolean # :nodoc:
12
+ end
13
+
14
+ class True < Boolean # :nodoc:
15
+ end
16
+ end
17
+
18
+ class Case < LogicNode # :nodoc:
19
+ # [:case, {expression}, {:when}, {:when}, ..., {expression | :block}]
20
+ def initialize(switch_sexp, *case_sexps)
21
+ options = case_sexps.pop
22
+ switch = switch_sexp.red!(:as_argument => true)
23
+ else_case = case_sexps.pop.red!(:as_argument => options[:as_argument])
24
+ string = "var _switch=(%s);%s" % [switch, '%s']
25
+ case_string = case_sexps.inject(string) do |cases,case_sexp|
26
+ cases %= case_sexp.red!(:as_argument => options[:as_argument])
27
+ end
28
+ self << case_string % [else_case]
29
+ end
30
+
31
+ class When < Case # :nodoc:
32
+ # [:when, [:array, {expression}, {expression}, ...], {expression | :block}]
33
+ def initialize(condition_sexps, expression_sexp, options)
34
+ conditions = condition_sexps[1..-1].map {|condition_sexp| "%s.m$_eql3(_switch)" % [condition_sexp.red!(:as_receiver => true)] }.join("||")
35
+ expression = expression_sexp.red!(:as_argument => options[:as_argument])
36
+ string = options[:as_argument] ? "(%s?%s:%s)" : "if(%s){%s;}else{%s;}"
37
+ self << string % [conditions, expression, '%s']
38
+ end
39
+ end
40
+ end
41
+
42
+ class Conjunction < LogicNode # :nodoc:
43
+ # [:and, {expression}, {expression}]
44
+ # [:or, {expression}, {expression}]
45
+ def initialize(expression_a_sexp, expression_b_sexp, options)
46
+ a = expression_a_sexp.red!(:as_argument => true)
47
+ b = expression_b_sexp.red!(:as_argument => true)
48
+ string = self.class::STRING
49
+ self << string % [a,b]
50
+ end
51
+
52
+ class And < Conjunction # :nodoc:
53
+ # FIX: nil && obj produces false instead of nil
54
+ STRING = "(_a=$T(%s)?(_c=$T(_b=%s)?_b:_c):_a)"
55
+ end
56
+
57
+ class Or < Conjunction # :nodoc:
58
+ STRING = "($T(_a=%s)?_a:%s)"
59
+ end
60
+ end
61
+
62
+ class If < LogicNode # :nodoc:
63
+ # [:if, {expression}, {expression | :block}, {expression | :block}]
64
+ def initialize(condition_sexp, true_case_sexp, else_case_sexp, options)
65
+ # ... each_with_index {|x,i| b << a.flatten[i+1] if x == :lasgn}
66
+ if options[:as_argument] || options[:as_receiver] || options[:as_assignment]
67
+ condition = condition_sexp.red!(:as_argument => true)
68
+ true_case = true_case_sexp.nil? ? "nil" : true_case_sexp.red!(:as_argument => true)
69
+ else_case = else_case_sexp.nil? ? "nil" : else_case_sexp.red!(:as_argument => true)
70
+ self << "($T(%s)?%s:%s)" % [condition, true_case, else_case]
71
+ else
72
+ condition = (true_case_sexp.nil? ? "!$T(%s)" : "$T(%s)") % [condition_sexp.red!(:as_argument => true)]
73
+ true_case = "{%s;}" % [true_case_sexp.red!] unless true_case_sexp.nil?
74
+ join = "else" unless true_case_sexp.nil? || else_case_sexp.nil?
75
+ else_case = "{%s;}" % [else_case_sexp.red!] unless else_case_sexp.nil?
76
+ self << "if(%s)%s%s%s" % [condition, true_case, join, else_case]
77
+ end
78
+ end
79
+ end
80
+
81
+ class Not < LogicNode # :nodoc:
82
+ # [:not, {expression}]
83
+ def initialize(expression_sexp, options)
84
+ expression = expression_sexp.red!(:as_argument => true)
85
+ self << "!$T(%s)" % [expression]
86
+ end
87
+ end
88
+ end
89
+ end