red 3.5.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +10 -15
- data/README.txt +7 -50
- data/bin/red +12 -19
- data/config/hoe.rb +7 -6
- data/lib/red/errors.rb +2 -64
- data/lib/red/executable.rb +35 -34
- data/lib/red/nodes/assignment_nodes.rb +133 -0
- data/lib/red/nodes/call_nodes.rb +126 -0
- data/lib/red/nodes/control_nodes.rb +126 -0
- data/lib/red/nodes/data_nodes.rb +75 -0
- data/lib/red/nodes/definition_nodes.rb +191 -0
- data/lib/red/nodes/illegal_nodes.rb +33 -0
- data/lib/red/nodes/literal_nodes.rb +148 -0
- data/lib/red/nodes/logic_nodes.rb +89 -0
- data/lib/red/nodes/variable_nodes.rb +76 -0
- data/lib/red/plugin.rb +6 -7
- data/lib/red/version.rb +2 -2
- data/lib/red.rb +209 -131
- data/lib/source/ruby.rb +6744 -0
- metadata +14 -19
- data/lib/javascripts/_dom_ready.js +0 -249
- data/lib/javascripts/prototype_dom_ready.js +0 -1
- data/lib/javascripts/red/unobtrusive.red +0 -6
- data/lib/red/assignment_nodes.rb +0 -164
- data/lib/red/call_nodes.rb +0 -90
- data/lib/red/conditional_nodes.rb +0 -63
- data/lib/red/conjunction_nodes.rb +0 -23
- data/lib/red/constant_nodes.rb +0 -47
- data/lib/red/control_nodes.rb +0 -129
- data/lib/red/data_nodes.rb +0 -93
- data/lib/red/definition_nodes.rb +0 -177
- data/lib/red/illegal_nodes.rb +0 -63
- data/lib/red/literal_nodes.rb +0 -119
- data/lib/red/variable_nodes.rb +0 -37
- data/lib/red/wrap_nodes.rb +0 -51
@@ -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
|