red 3.5.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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