opal 0.9.4 → 0.10.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitattributes +1 -0
- data/.gitignore +2 -3
- data/.gitmodules +5 -2
- data/.jshintrc +1 -8
- data/.rspec +1 -1
- data/.travis.yml +15 -23
- data/CHANGELOG.md +511 -326
- data/CODE_OF_CONDUCT.md +13 -15
- data/CONTRIBUTING.md +26 -216
- data/Gemfile +20 -12
- data/Guardfile +2 -2
- data/HACKING.md +230 -0
- data/README.md +6 -7
- data/bin/opal-mspec +1 -1
- data/config.ru +2 -2
- data/docs/faq.md +1 -1
- data/docs/source_maps.md +1 -1
- data/lib/opal.rb +1 -0
- data/lib/opal/builder.rb +1 -1
- data/lib/opal/cli.rb +30 -28
- data/lib/opal/cli_options.rb +3 -0
- data/lib/opal/cli_runners.rb +14 -1
- data/lib/opal/cli_runners/{apple_script.rb → applescript.rb} +3 -3
- data/lib/opal/cli_runners/nashorn.rb +2 -2
- data/lib/opal/cli_runners/nodejs.rb +2 -2
- data/lib/opal/cli_runners/phantom.js +24 -0
- data/lib/opal/cli_runners/phantomjs.rb +10 -10
- data/lib/opal/cli_runners/server.rb +3 -3
- data/lib/opal/compiler.rb +43 -4
- data/lib/opal/config.rb +3 -1
- data/lib/opal/errors.rb +13 -0
- data/lib/opal/fragment.rb +0 -13
- data/lib/opal/nodes.rb +10 -0
- data/lib/opal/nodes/args/initialize_kwargs.rb +28 -0
- data/lib/opal/nodes/args/kwarg.rb +29 -0
- data/lib/opal/nodes/args/kwoptarg.rb +29 -0
- data/lib/opal/nodes/args/kwrestarg.rb +39 -0
- data/lib/opal/nodes/args/mlhsarg.rb +79 -0
- data/lib/opal/nodes/args/normarg.rb +26 -0
- data/lib/opal/nodes/args/optarg.rb +27 -0
- data/lib/opal/nodes/args/post_args.rb +200 -0
- data/lib/opal/nodes/args/post_kwargs.rb +31 -0
- data/lib/opal/nodes/args/restarg.rb +33 -0
- data/lib/opal/nodes/base.rb +12 -0
- data/lib/opal/nodes/call.rb +92 -33
- data/lib/opal/nodes/def.rb +26 -169
- data/lib/opal/nodes/hash.rb +10 -4
- data/lib/opal/nodes/helpers.rb +6 -3
- data/lib/opal/nodes/inline_args.rb +61 -0
- data/lib/opal/nodes/iter.rb +73 -82
- data/lib/opal/nodes/logic.rb +12 -2
- data/lib/opal/nodes/masgn.rb +1 -2
- data/lib/opal/nodes/node_with_args.rb +141 -0
- data/lib/opal/nodes/rescue.rb +121 -43
- data/lib/opal/nodes/scope.rb +24 -5
- data/lib/opal/nodes/super.rb +122 -54
- data/lib/opal/nodes/top.rb +0 -12
- data/lib/opal/nodes/yield.rb +2 -13
- data/lib/opal/parser.rb +67 -39
- data/lib/opal/parser/grammar.rb +3319 -2961
- data/lib/opal/parser/grammar.y +234 -46
- data/lib/opal/parser/lexer.rb +105 -17
- data/lib/opal/parser/sexp.rb +4 -0
- data/lib/opal/paths.rb +4 -0
- data/lib/opal/regexp_anchors.rb +19 -1
- data/lib/opal/sprockets.rb +21 -18
- data/lib/opal/sprockets/environment.rb +0 -8
- data/lib/opal/sprockets/processor.rb +13 -16
- data/lib/opal/sprockets/server.rb +6 -12
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -0
- data/opal/corelib/array.rb +209 -131
- data/opal/corelib/basic_object.rb +7 -3
- data/opal/corelib/class.rb +11 -17
- data/opal/corelib/constants.rb +2 -2
- data/opal/corelib/enumerable.rb +178 -355
- data/opal/corelib/enumerator.rb +3 -46
- data/opal/corelib/error.rb +2 -2
- data/opal/corelib/file.rb +13 -1
- data/opal/corelib/hash.rb +26 -56
- data/opal/corelib/helpers.rb +10 -0
- data/opal/corelib/kernel.rb +6 -3
- data/opal/corelib/module.rb +62 -31
- data/opal/corelib/number.rb +7 -16
- data/opal/corelib/proc.rb +24 -9
- data/opal/corelib/range.rb +4 -13
- data/opal/corelib/runtime.js +515 -378
- data/opal/corelib/string.rb +21 -49
- data/opal/corelib/struct.rb +50 -35
- data/opal/corelib/unsupported.rb +18 -30
- data/opal/opal.rb +0 -1
- data/opal/opal/mini.rb +1 -0
- data/spec/README.md +6 -4
- data/spec/filters/bugs/array.rb +0 -42
- data/spec/filters/bugs/basicobject.rb +0 -2
- data/spec/filters/bugs/bigdecimal.rb +160 -0
- data/spec/filters/bugs/class.rb +0 -5
- data/spec/filters/bugs/date.rb +1 -48
- data/spec/filters/bugs/enumerable.rb +4 -12
- data/spec/filters/bugs/enumerator.rb +0 -1
- data/spec/filters/bugs/exception.rb +4 -3
- data/spec/filters/bugs/float.rb +4 -2
- data/spec/filters/bugs/kernel.rb +25 -10
- data/spec/filters/bugs/language.rb +119 -68
- data/spec/filters/bugs/method.rb +135 -0
- data/spec/filters/bugs/module.rb +13 -28
- data/spec/filters/bugs/proc.rb +18 -8
- data/spec/filters/bugs/range.rb +0 -3
- data/spec/filters/bugs/rational.rb +4 -0
- data/spec/filters/bugs/regexp.rb +68 -36
- data/spec/filters/bugs/string.rb +1 -1
- data/spec/filters/bugs/struct.rb +0 -12
- data/spec/filters/bugs/time.rb +1 -0
- data/spec/filters/bugs/unboundmethod.rb +2 -1
- data/spec/filters/unsupported/freeze.rb +3 -1
- data/spec/filters/unsupported/language.rb +0 -7
- data/spec/filters/unsupported/privacy.rb +7 -6
- data/spec/filters/unsupported/string.rb +10 -0
- data/spec/filters/unsupported/struct.rb +3 -0
- data/spec/filters/unsupported/symbol.rb +9 -0
- data/spec/filters/unsupported/taint.rb +0 -3
- data/spec/filters/unsupported/thread.rb +1 -0
- data/spec/lib/cli_runners/phantomjs_spec.rb +39 -0
- data/spec/lib/cli_spec.rb +42 -1
- data/spec/lib/compiler/call_spec.rb +700 -0
- data/spec/lib/compiler_spec.rb +46 -28
- data/spec/lib/config_spec.rb +13 -0
- data/spec/lib/parser/call_spec.rb +18 -0
- data/spec/lib/parser/def_spec.rb +29 -0
- data/spec/lib/parser/iter_spec.rb +15 -15
- data/spec/lib/parser/lambda_spec.rb +153 -12
- data/spec/lib/parser/string_spec.rb +5 -0
- data/spec/lib/parser/undef_spec.rb +1 -1
- data/spec/lib/parser/variables_spec.rb +24 -0
- data/spec/lib/paths_spec.rb +12 -5
- data/spec/lib/spec_helper.rb +5 -0
- data/spec/lib/sprockets/processor_spec.rb +6 -5
- data/spec/lib/sprockets_spec.rb +8 -0
- data/spec/mspec-opal/formatters.rb +188 -0
- data/spec/mspec-opal/runner.rb +193 -0
- data/spec/opal/core/enumerator/with_index_spec.rb +6 -0
- data/spec/opal/core/kernel/define_singleton_method_spec.rb +1 -1
- data/spec/opal/core/kernel/instance_variables_spec.rb +14 -0
- data/spec/opal/core/kernel/loop_spec.rb +1 -1
- data/spec/opal/core/kernel/raise_spec.rb +1 -1
- data/spec/opal/core/language/heredoc_spec.rb +42 -0
- data/spec/opal/core/language/rescue_spec.rb +18 -0
- data/spec/opal/core/language_spec.rb +22 -0
- data/spec/opal/core/module/const_defined_spec.rb +1 -2
- data/spec/opal/core/module/name_spec.rb +6 -0
- data/spec/opal/core/runtime/bridged_classes_spec.rb +14 -2
- data/spec/opal/core/runtime/rescue_spec.rb +12 -2
- data/spec/opal/core/runtime/super_spec.rb +1 -0
- data/spec/opal/core/string_spec.rb +21 -0
- data/spec/opal/stdlib/js_spec.rb +1 -1
- data/spec/opal/stdlib/native/hash_spec.rb +7 -0
- data/spec/opal/stdlib/promise/always_spec.rb +24 -5
- data/spec/opal/stdlib/promise/rescue_spec.rb +15 -6
- data/spec/opal/stdlib/promise/then_spec.rb +13 -5
- data/spec/opal/stdlib/promise/trace_spec.rb +5 -6
- data/spec/opal/stdlib/strscan/scan_spec.rb +1 -1
- data/spec/ruby_specs +122 -0
- data/spec/spec_helper.rb +3 -15
- data/stdlib/base64.rb +51 -121
- data/stdlib/bigdecimal.rb +231 -0
- data/stdlib/bigdecimal/bignumber.js.rb +11 -0
- data/stdlib/bigdecimal/kernel.rb +5 -0
- data/stdlib/date.rb +252 -10
- data/stdlib/native.rb +38 -38
- data/stdlib/nodejs/dir.rb +8 -6
- data/stdlib/nodejs/file.rb +28 -3
- data/stdlib/nodejs/node_modules/.bin/js-yaml +1 -0
- data/stdlib/nodejs/node_modules/js-yaml/node_modules/.bin/esparse +1 -0
- data/stdlib/nodejs/node_modules/js-yaml/node_modules/.bin/esvalidate +1 -0
- data/stdlib/nodejs/require.rb +1 -1
- data/stdlib/nodejs/yaml.rb +3 -2
- data/stdlib/opal-parser.rb +7 -2
- data/stdlib/pathname.rb +23 -1
- data/stdlib/phantomjs.rb +10 -0
- data/stdlib/promise.rb +38 -23
- data/tasks/building.rake +3 -3
- data/tasks/testing.rake +27 -14
- data/tasks/testing/mspec_special_calls.rb +1 -1
- data/tasks/testing/sprockets-phantomjs.js +4 -0
- data/test/opal/test_keyword.rb +110 -110
- data/test/opal/unsupported_and_bugs.rb +30 -0
- data/vendored-minitest/minitest/assertions.rb +1 -1
- metadata +65 -15
- data/.spectator +0 -2
- data/.spectator-mspec +0 -3
- data/opal/corelib/array/inheritance.rb +0 -127
- data/spec/rubyspecs +0 -139
data/lib/opal/errors.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Opal
|
2
|
+
# raised if Gem not found in Opal#use_gem
|
3
|
+
class GemNotFound < StandardError
|
4
|
+
# name of gem that not found
|
5
|
+
attr_reader :gem_name
|
6
|
+
|
7
|
+
# @param gem_name [String] name of gem that not found
|
8
|
+
def initialize(gem_name)
|
9
|
+
@gem_name = gem_name
|
10
|
+
super("can't find gem #{gem_name}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/opal/fragment.rb
CHANGED
@@ -20,19 +20,6 @@ module Opal
|
|
20
20
|
@sexp = sexp
|
21
21
|
end
|
22
22
|
|
23
|
-
# In debug mode we may wish to include the original line and comment in
|
24
|
-
# a javascript comment.
|
25
|
-
#
|
26
|
-
# @deprecated
|
27
|
-
#
|
28
|
-
def to_code
|
29
|
-
if @sexp
|
30
|
-
"/*:#{@sexp.line}:#{@sexp.column}*/#{@code}"
|
31
|
-
else
|
32
|
-
@code
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
23
|
# Inspect the contents of this fragment, f("fooo")
|
37
24
|
def inspect
|
38
25
|
"f(#{@code.inspect})"
|
data/lib/opal/nodes.rb
CHANGED
@@ -7,6 +7,16 @@ require 'opal/nodes/call_special'
|
|
7
7
|
require 'opal/nodes/module'
|
8
8
|
require 'opal/nodes/class'
|
9
9
|
require 'opal/nodes/singleton_class'
|
10
|
+
require 'opal/nodes/inline_args'
|
11
|
+
require 'opal/nodes/args/normarg'
|
12
|
+
require 'opal/nodes/args/optarg'
|
13
|
+
require 'opal/nodes/args/mlhsarg'
|
14
|
+
require 'opal/nodes/args/restarg'
|
15
|
+
require 'opal/nodes/args/kwarg'
|
16
|
+
require 'opal/nodes/args/kwoptarg'
|
17
|
+
require 'opal/nodes/args/kwrestarg'
|
18
|
+
require 'opal/nodes/args/post_kwargs'
|
19
|
+
require 'opal/nodes/args/post_args'
|
10
20
|
require 'opal/nodes/iter'
|
11
21
|
require 'opal/nodes/def'
|
12
22
|
require 'opal/nodes/if'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'opal/nodes/base'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# An abstract node responsible for validating
|
6
|
+
# keyword arguments in the post-splat list of arguments.
|
7
|
+
#
|
8
|
+
# @see PostArgsNode
|
9
|
+
#
|
10
|
+
class InitializeKwargsNode < Base
|
11
|
+
def initialize_kw_args_if_needed
|
12
|
+
return if scope.kwargs_initialized
|
13
|
+
|
14
|
+
helper :hash2
|
15
|
+
|
16
|
+
line "if ($kwargs == null || !$kwargs.$$is_hash) {"
|
17
|
+
line " if ($kwargs == null) {"
|
18
|
+
line " $kwargs = $hash2([], {});"
|
19
|
+
line " } else {"
|
20
|
+
line " throw Opal.ArgumentError.$new('expected kwargs');"
|
21
|
+
line " }"
|
22
|
+
line "}"
|
23
|
+
|
24
|
+
scope.kwargs_initialized = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'opal/nodes/args/initialize_kwargs'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# A node responsible for extracting a
|
6
|
+
# single *required* keyword argument
|
7
|
+
#
|
8
|
+
# def m(kw: )
|
9
|
+
#
|
10
|
+
class KwargNode < InitializeKwargsNode
|
11
|
+
handle :kwarg
|
12
|
+
|
13
|
+
def compile
|
14
|
+
initialize_kw_args_if_needed
|
15
|
+
|
16
|
+
kwarg_name = @sexp[1].to_sym
|
17
|
+
var_name = variable(kwarg_name)
|
18
|
+
add_temp var_name
|
19
|
+
|
20
|
+
line "if (!$kwargs.$$smap.hasOwnProperty('#{kwarg_name}')) {"
|
21
|
+
line " throw Opal.ArgumentError.$new('missing keyword: #{kwarg_name}');"
|
22
|
+
line "}"
|
23
|
+
line "#{var_name} = $kwargs.$$smap['#{kwarg_name}'];"
|
24
|
+
|
25
|
+
scope.used_kwargs << kwarg_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'opal/nodes/args/initialize_kwargs'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# A node responsible for extracting a
|
6
|
+
# single *optional* keyword argument
|
7
|
+
#
|
8
|
+
# def m(kw: 1)
|
9
|
+
#
|
10
|
+
class KwoptArgNode < InitializeKwargsNode
|
11
|
+
handle :kwoptarg
|
12
|
+
|
13
|
+
def compile
|
14
|
+
initialize_kw_args_if_needed
|
15
|
+
|
16
|
+
kwoptarg_name = @sexp[1].to_sym
|
17
|
+
default_value = @sexp[2]
|
18
|
+
var_name = variable(kwoptarg_name)
|
19
|
+
add_temp var_name
|
20
|
+
|
21
|
+
line "if ((#{var_name} = $kwargs.$$smap['#{kwoptarg_name}']) == null) {"
|
22
|
+
line " #{var_name} = ", expr(default_value)
|
23
|
+
line "}"
|
24
|
+
|
25
|
+
scope.used_kwargs << kwoptarg_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'opal/nodes/args/initialize_kwargs'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# A node responsible for extracting a
|
6
|
+
# keyword splat argument
|
7
|
+
#
|
8
|
+
# def m(**kwrest)
|
9
|
+
# def m(**)
|
10
|
+
#
|
11
|
+
class KwrestArgNode < InitializeKwargsNode
|
12
|
+
handle :kwrestarg
|
13
|
+
|
14
|
+
def compile
|
15
|
+
initialize_kw_args_if_needed
|
16
|
+
|
17
|
+
kwrestarg_name = @sexp[1]
|
18
|
+
extract_code = "Opal.kwrestargs($kwargs, #{used_kwargs});"
|
19
|
+
|
20
|
+
# kwrestarg can be blank def m(**) end
|
21
|
+
# we need to perform assignment only for named kwrestarg
|
22
|
+
if kwrestarg_name
|
23
|
+
var_name = variable(kwrestarg_name.to_sym)
|
24
|
+
add_temp var_name
|
25
|
+
|
26
|
+
line "#{var_name} = #{extract_code}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def used_kwargs
|
31
|
+
args = scope.used_kwargs.map do |arg_name|
|
32
|
+
"'#{arg_name}': true"
|
33
|
+
end
|
34
|
+
|
35
|
+
"{#{args.join ','}}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'opal/nodes/base'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# A node responsible for extracting a
|
6
|
+
# single MLHS argument
|
7
|
+
#
|
8
|
+
# MLHS argument is the left hand side
|
9
|
+
# of a multiple assignment (Multiple Left Hand Side)
|
10
|
+
#
|
11
|
+
# def m((a, b))
|
12
|
+
# def m((a, *b))
|
13
|
+
#
|
14
|
+
# MLHS can include simple arguments (see NormargNode)
|
15
|
+
# and rest arguments (see RestargNode)
|
16
|
+
#
|
17
|
+
class MlhsArgNode < Base
|
18
|
+
handle :mlhs
|
19
|
+
|
20
|
+
def compile
|
21
|
+
args_sexp = s(:post_args, *children)
|
22
|
+
|
23
|
+
if @sexp.meta[:post]
|
24
|
+
# In this case source is an item in the current scope.working_arguments
|
25
|
+
# First we should extract mlhs as a simple argument
|
26
|
+
mlhs_sexp = s(:arg, mlhs_name)
|
27
|
+
mlhs_sexp.meta[:post] = true
|
28
|
+
scope.with_inline_args([]) do
|
29
|
+
push process(mlhs_sexp)
|
30
|
+
end
|
31
|
+
var_name = args_sexp.meta[:js_source] = mlhs_name
|
32
|
+
else
|
33
|
+
# Otherwise we already have it in our scope.working_arguments
|
34
|
+
# (of course, in this case scope.working_arguments = 'arguments')
|
35
|
+
var_name = args_sexp.meta[:js_source] = scope.mlhs_mapping[@sexp]
|
36
|
+
end
|
37
|
+
|
38
|
+
line "if (#{var_name} == null) {"
|
39
|
+
line " #{var_name} = nil;"
|
40
|
+
line "}"
|
41
|
+
|
42
|
+
line "if (!#{var_name}.$$is_array) {"
|
43
|
+
line " #{var_name} = [#{var_name}];"
|
44
|
+
line "}"
|
45
|
+
|
46
|
+
scope.with_inline_args([]) do
|
47
|
+
scope.in_mlhs do
|
48
|
+
push process(args_sexp)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def mlhs_name
|
54
|
+
@mlhs_name ||= begin
|
55
|
+
if @sexp.meta[:post]
|
56
|
+
result = ["$mlhs_of"]
|
57
|
+
|
58
|
+
children.each do |child|
|
59
|
+
case child.type
|
60
|
+
when :arg
|
61
|
+
result << child[1]
|
62
|
+
when :mlhs
|
63
|
+
result << 'mlhs'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
result.join("_")
|
68
|
+
else
|
69
|
+
@sexp[1].to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def inline_args
|
75
|
+
@inline_args ||= children.take_while { |arg| arg.type != :restarg && arg.type != :optarg }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'opal/nodes/base'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# A ndoe responsible for extracting
|
6
|
+
# a single argument
|
7
|
+
#
|
8
|
+
# def m(a)
|
9
|
+
#
|
10
|
+
class NormargNode < Base
|
11
|
+
handle :arg
|
12
|
+
|
13
|
+
def compile
|
14
|
+
arg_name = @sexp[1].to_sym
|
15
|
+
var_name = variable(arg_name)
|
16
|
+
|
17
|
+
default_value = scope.in_mlhs? ? "|| nil" : ""
|
18
|
+
|
19
|
+
if @sexp.meta[:post]
|
20
|
+
add_temp var_name
|
21
|
+
line "#{var_name} = #{scope.working_arguments}.splice(0,1)[0] #{default_value};"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'opal/nodes/base'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# A node responsible for extracting a single
|
6
|
+
# optional argument
|
7
|
+
#
|
8
|
+
# def m(a=1)
|
9
|
+
#
|
10
|
+
class OptargNode < Base
|
11
|
+
handle :optarg
|
12
|
+
|
13
|
+
def compile
|
14
|
+
optarg_name = @sexp[1].to_sym
|
15
|
+
default_value = @sexp[2]
|
16
|
+
var_name = variable(optarg_name)
|
17
|
+
|
18
|
+
return if default_value[2] == :undefined
|
19
|
+
|
20
|
+
line "if (#{var_name} == null) {"
|
21
|
+
line " #{var_name} = ", expr(default_value)
|
22
|
+
push ";"
|
23
|
+
line "}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'opal/nodes/base'
|
2
|
+
|
3
|
+
module Opal
|
4
|
+
module Nodes
|
5
|
+
# Node responsible for extracting post-splat args
|
6
|
+
# 1. There can be some arguments after the splat, this is why this node exist.
|
7
|
+
# In this case if:
|
8
|
+
# a. JS arguments length > args sexp length - then our splat has some items
|
9
|
+
# and we know how many of them should come to splat
|
10
|
+
# b. JS arguments length < args sexp length - then our splat is blank
|
11
|
+
#
|
12
|
+
# 2. Super important:
|
13
|
+
# a) optional arg always goes BEFORE the rest arg
|
14
|
+
# b) optional args always appear in the sequence (i.e. you can't have def m(a=1,b,c=1))
|
15
|
+
# c) precedence order:
|
16
|
+
# 1. required arg (norm arg, mlhs arg)
|
17
|
+
# 2. optional argument (optarg)
|
18
|
+
# 3. splat/rest argument (restarg)
|
19
|
+
# These statements simplify everything, keep them in mind.
|
20
|
+
# 3. post_args here _always_ have the same structure:
|
21
|
+
# 1. list of required arguments (only for mlhs, can be blank)
|
22
|
+
# 2. list of optargs (only for post-args, can be blank)
|
23
|
+
# 3. restarg (for both mlhs/post-args, can be nil)
|
24
|
+
# 4. list of required args (for both mlhs/post-args, can be blank)
|
25
|
+
#
|
26
|
+
class PostArgsNode < Base
|
27
|
+
handle :post_args
|
28
|
+
|
29
|
+
# kwargs contains the list of all post-kw* arguments
|
30
|
+
# all of them can be processed in the first oder
|
31
|
+
attr_reader :kwargs
|
32
|
+
|
33
|
+
# required_left_args contains the list of required post args
|
34
|
+
# like normarg or mlhs
|
35
|
+
# For post-args: always blank (post args always start with optarg/restarg)
|
36
|
+
# For mlhs: can be provided from
|
37
|
+
# mlhs = (a, b, c)
|
38
|
+
# required_left_args = [(:arg, :a), (:arg, :b)]
|
39
|
+
attr_reader :required_left_args
|
40
|
+
|
41
|
+
# optargs contains the list of optarg arguments
|
42
|
+
# all of them must be populated depending on the "arguments.length"
|
43
|
+
# if we have enough arguments - we fill them,
|
44
|
+
# if not - we populate it with its default value
|
45
|
+
# For post-args: can be provided from
|
46
|
+
# def m(a=1, *b)
|
47
|
+
# post-args = [(:optarg, :a, (:int, 1)), (:restarg, :b)]
|
48
|
+
# optargs = [(:optarg, :a, (:int, 1))]
|
49
|
+
# For mlhs: always blank
|
50
|
+
attr_reader :optargs
|
51
|
+
|
52
|
+
# returns a restarg sexp
|
53
|
+
# if we have enough "arguments" - we fill it
|
54
|
+
# if not - we populate it with "[]"
|
55
|
+
# For post-args: can be provided from
|
56
|
+
# def m(a=1, *b)
|
57
|
+
# post-args = [(:optarg, :a, (:int, 1)), (:restarg, :b)]
|
58
|
+
# restarg (:restarg, :b)
|
59
|
+
attr_reader :restarg
|
60
|
+
|
61
|
+
# required_right_args contains the list of required post args
|
62
|
+
# like normarg and mlhs arg
|
63
|
+
# For post-args: can be provided from
|
64
|
+
# def m(a=1,*b,c)
|
65
|
+
# post-args = [(:optarg, :a, (:int, 1)), (:restarg, :b), (:arg, :c)]
|
66
|
+
# required_right_args = [(:arg, :c)]
|
67
|
+
# For mlhs: can be provided from
|
68
|
+
# (*a, b)
|
69
|
+
# required_right_args = [(:arg, :b)]
|
70
|
+
attr_reader :required_right_args
|
71
|
+
|
72
|
+
def initialize(*)
|
73
|
+
super
|
74
|
+
|
75
|
+
@kwargs = []
|
76
|
+
@required_left_args = []
|
77
|
+
@optargs = []
|
78
|
+
@restarg = nil
|
79
|
+
@required_right_args = []
|
80
|
+
end
|
81
|
+
|
82
|
+
def extract_arguments
|
83
|
+
found_opt_or_rest = false
|
84
|
+
|
85
|
+
children.each do |arg|
|
86
|
+
arg.meta[:post] = true
|
87
|
+
|
88
|
+
case arg.type
|
89
|
+
when :kwarg, :kwoptarg, :kwrestarg
|
90
|
+
@kwargs << arg
|
91
|
+
when :restarg
|
92
|
+
@restarg = arg
|
93
|
+
found_opt_or_rest = true
|
94
|
+
when :optarg
|
95
|
+
@optargs << arg
|
96
|
+
found_opt_or_rest = true
|
97
|
+
when :arg, :mlhs
|
98
|
+
if found_opt_or_rest
|
99
|
+
@required_right_args << arg
|
100
|
+
else
|
101
|
+
@required_left_args << arg
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def compile
|
108
|
+
return if children.empty?
|
109
|
+
|
110
|
+
old_working_arguments = scope.working_arguments
|
111
|
+
|
112
|
+
if @sexp.meta[:js_source]
|
113
|
+
js_source = @sexp.meta[:js_source]
|
114
|
+
scope.working_arguments = "#{js_source}_args"
|
115
|
+
else
|
116
|
+
js_source = "arguments"
|
117
|
+
scope.working_arguments = "$post_args"
|
118
|
+
end
|
119
|
+
|
120
|
+
add_temp "#{scope.working_arguments}"
|
121
|
+
line "#{scope.working_arguments} = Opal.slice.call(#{js_source}, #{scope.inline_args.size}, #{js_source}.length);"
|
122
|
+
|
123
|
+
extract_arguments
|
124
|
+
|
125
|
+
push process(kwargs_sexp)
|
126
|
+
|
127
|
+
required_left_args.each do |arg|
|
128
|
+
compile_required_arg(arg)
|
129
|
+
end
|
130
|
+
|
131
|
+
optargs.each do |optarg|
|
132
|
+
compile_optarg(optarg)
|
133
|
+
end
|
134
|
+
|
135
|
+
compile_restarg
|
136
|
+
|
137
|
+
required_right_args.each do |arg|
|
138
|
+
compile_required_arg(arg)
|
139
|
+
end
|
140
|
+
|
141
|
+
scope.working_arguments = old_working_arguments
|
142
|
+
end
|
143
|
+
|
144
|
+
def compile_optarg(optarg)
|
145
|
+
var_name = variable(optarg[1].to_sym)
|
146
|
+
add_temp var_name
|
147
|
+
|
148
|
+
line "if (#{required_right_args.size} < #{scope.working_arguments}.length) {"
|
149
|
+
indent do
|
150
|
+
line "#{var_name} = #{scope.working_arguments}.splice(0,1)[0];"
|
151
|
+
end
|
152
|
+
line "}"
|
153
|
+
push process(optarg)
|
154
|
+
end
|
155
|
+
|
156
|
+
def compile_required_arg(arg)
|
157
|
+
push process(arg)
|
158
|
+
end
|
159
|
+
|
160
|
+
def compile_restarg
|
161
|
+
return unless restarg
|
162
|
+
|
163
|
+
line "if (#{required_right_args.size} < #{scope.working_arguments}.length) {"
|
164
|
+
indent do
|
165
|
+
# there are some items coming to the splat, extracting them
|
166
|
+
extract_restarg
|
167
|
+
end
|
168
|
+
line "} else {"
|
169
|
+
indent do
|
170
|
+
# splat is empty
|
171
|
+
extract_blank_restarg
|
172
|
+
end
|
173
|
+
line "}"
|
174
|
+
end
|
175
|
+
|
176
|
+
def extract_restarg
|
177
|
+
extract_code = "#{scope.working_arguments}.splice(0, #{scope.working_arguments}.length - #{required_right_args.size});"
|
178
|
+
if restarg[1]
|
179
|
+
var_name = variable(restarg[1].to_sym)
|
180
|
+
add_temp var_name
|
181
|
+
line "#{var_name} = #{extract_code}"
|
182
|
+
else
|
183
|
+
line extract_code
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def extract_blank_restarg
|
188
|
+
if restarg[1]
|
189
|
+
var_name = variable(restarg[1].to_sym)
|
190
|
+
add_temp var_name
|
191
|
+
line "#{var_name} = [];"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def kwargs_sexp
|
196
|
+
s(:post_kwargs, *kwargs)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|