opal 1.1.0.rc1 → 1.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +4 -4
- data/.github/ISSUE_TEMPLATE/bug-report.md +47 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/workflows/build.yml +11 -5
- data/.gitignore +1 -0
- data/.jshintrc +1 -1
- data/CHANGELOG.md +42 -1
- data/Gemfile +0 -4
- data/HACKING.md +1 -1
- data/LICENSE +1 -1
- data/README.md +20 -16
- data/UNRELEASED.md +32 -95
- data/benchmark-ips/bm_array_unshift.rb +7 -0
- data/benchmark-ips/bm_js_symbols_vs_strings.rb +7 -2
- data/bin/build-browser-source-map-support +2 -3
- data/bin/opal-mspec +2 -0
- data/docs/compiler.md +1 -1
- data/examples/rack/Gemfile +0 -1
- data/examples/rack/Gemfile.lock +0 -4
- data/lib/opal/cli.rb +1 -0
- data/lib/opal/cli_options.rb +4 -0
- data/lib/opal/cli_runners/nodejs.rb +5 -1
- data/lib/opal/cli_runners/source-map-support-browser.js +8 -2
- data/lib/opal/cli_runners/source-map-support-node.js +3706 -0
- data/lib/opal/cli_runners/source-map-support.js +3 -1
- data/lib/opal/compiler.rb +2 -2
- data/lib/opal/nodes/args/arity_check.rb +1 -0
- data/lib/opal/nodes/args/parameters.rb +6 -0
- data/lib/opal/nodes/class.rb +1 -13
- data/lib/opal/nodes/literal.rb +14 -7
- data/lib/opal/nodes/module.rb +13 -9
- data/lib/opal/nodes/variables.rb +13 -4
- data/lib/opal/nodes/while.rb +54 -17
- data/lib/opal/parser.rb +1 -5
- data/lib/opal/parser/patch.rb +34 -0
- data/lib/opal/repl.rb +7 -0
- data/lib/opal/rewriter.rb +2 -0
- data/lib/opal/rewriters/arguments.rb +4 -1
- data/lib/opal/rewriters/forward_args.rb +54 -0
- data/lib/opal/rewriters/logical_operator_assignment.rb +5 -2
- data/lib/opal/rewriters/opal_engine_check.rb +5 -7
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -1
- data/opal/corelib/array.rb +42 -20
- data/opal/corelib/array/pack.rb +6 -1
- data/opal/corelib/complex.rb +2 -0
- data/opal/corelib/constants.rb +3 -3
- data/opal/corelib/hash.rb +36 -38
- data/opal/corelib/module.rb +2 -7
- data/opal/corelib/number.rb +2 -180
- data/opal/corelib/numeric.rb +156 -0
- data/opal/corelib/object_space.rb +102 -0
- data/opal/corelib/random.rb +31 -66
- data/opal/corelib/random/formatter.rb +122 -0
- data/opal/corelib/range.rb +50 -19
- data/opal/corelib/runtime.js +82 -21
- data/opal/corelib/string.rb +86 -52
- data/opal/corelib/string/encoding.rb +140 -25
- data/opal/corelib/string/unpack.rb +26 -40
- data/opal/opal.rb +1 -0
- data/opal/opal/full.rb +1 -0
- data/package.json +1 -1
- data/spec/filters/bugs/array.rb +0 -22
- data/spec/filters/bugs/basicobject.rb +3 -0
- data/spec/filters/bugs/encoding.rb +0 -2
- data/spec/filters/bugs/exception.rb +1 -0
- data/spec/filters/bugs/float.rb +0 -2
- data/spec/filters/bugs/hash.rb +2 -7
- data/spec/filters/bugs/integer.rb +0 -2
- data/spec/filters/bugs/kernel.rb +16 -3
- data/spec/filters/bugs/language.rb +6 -14
- data/spec/filters/bugs/marshal.rb +1 -3
- data/spec/filters/bugs/module.rb +16 -1
- data/spec/filters/bugs/numeric.rb +4 -12
- data/spec/filters/bugs/objectspace.rb +67 -0
- data/spec/filters/bugs/pack_unpack.rb +0 -9
- data/spec/filters/bugs/pathname.rb +1 -0
- data/spec/filters/bugs/proc.rb +8 -0
- data/spec/filters/bugs/random.rb +3 -6
- data/spec/filters/bugs/range.rb +83 -113
- data/spec/filters/bugs/set.rb +2 -0
- data/spec/filters/bugs/string.rb +31 -70
- data/spec/filters/bugs/struct.rb +2 -0
- data/spec/filters/bugs/time.rb +8 -2
- data/spec/filters/unsupported/float.rb +3 -0
- data/spec/filters/unsupported/freeze.rb +1 -0
- data/spec/filters/unsupported/integer.rb +3 -0
- data/spec/filters/unsupported/refinements.rb +5 -0
- data/spec/filters/unsupported/string.rb +100 -95
- data/spec/filters/unsupported/time.rb +4 -0
- data/spec/lib/compiler_spec.rb +16 -0
- data/spec/lib/rewriters/forward_args_spec.rb +61 -0
- data/spec/lib/rewriters/logical_operator_assignment_spec.rb +1 -1
- data/spec/lib/rewriters/numblocks_spec.rb +44 -0
- data/spec/lib/rewriters/opal_engine_check_spec.rb +49 -4
- data/spec/opal/core/language/forward_args_spec.rb +53 -0
- data/spec/opal/core/language/infinite_range_spec.rb +13 -0
- data/spec/opal/core/language/memoization_spec.rb +16 -0
- data/spec/opal/core/module_spec.rb +38 -2
- data/spec/opal/core/number/to_i_spec.rb +28 -0
- data/spec/opal/core/runtime/bridged_classes_spec.rb +16 -0
- data/spec/opal/core/runtime/constants_spec.rb +20 -1
- data/spec/opal/core/string/subclassing_spec.rb +16 -0
- data/spec/opal/core/string/unpack_spec.rb +22 -0
- data/spec/opal/core/string_spec.rb +4 -4
- data/spec/ruby_specs +4 -1
- data/stdlib/json.rb +3 -1
- data/stdlib/securerandom.rb +55 -35
- data/tasks/testing.rake +6 -3
- data/test/nodejs/test_string.rb +25 -0
- data/vendored-minitest/minitest/assertions.rb +2 -0
- metadata +35 -12
- data/lib/opal/parser/with_c_lexer.rb +0 -15
@@ -341,7 +341,9 @@ function CallSiteToString() {
|
|
341
341
|
}
|
342
342
|
var methodName = this.getMethodName();
|
343
343
|
if (functionName) {
|
344
|
-
if (functionName.startsWith("
|
344
|
+
if (functionName.startsWith("$$")) {
|
345
|
+
functionName = functionName.slice(2);
|
346
|
+
} else if (functionName.startsWith("$")) {
|
345
347
|
functionName = functionName.slice(1);
|
346
348
|
}
|
347
349
|
if (typeName && functionName.indexOf(typeName) != 0) {
|
data/lib/opal/compiler.rb
CHANGED
@@ -151,7 +151,7 @@ module Opal
|
|
151
151
|
|
152
152
|
# @!method use_strict?
|
153
153
|
#
|
154
|
-
#
|
154
|
+
# Enables JavaScript's strict mode (i.e., adds 'use strict'; statement)
|
155
155
|
compiler_option :use_strict, default: false, as: :use_strict?, magic_comment: true
|
156
156
|
|
157
157
|
# @!method parse_comments?
|
@@ -358,7 +358,7 @@ module Opal
|
|
358
358
|
def in_while
|
359
359
|
return unless block_given?
|
360
360
|
@while_loop = @scope.push_while
|
361
|
-
result =
|
361
|
+
result = yield
|
362
362
|
@scope.pop_while
|
363
363
|
result
|
364
364
|
end
|
@@ -30,6 +30,7 @@ module Opal
|
|
30
30
|
|
31
31
|
def on_restarg(arg_name = nil)
|
32
32
|
if arg_name
|
33
|
+
arg_name = :* if arg_name == :fwd_rest_arg
|
33
34
|
%{['rest', '#{arg_name}']}
|
34
35
|
else
|
35
36
|
%{['rest']}
|
@@ -53,9 +54,14 @@ module Opal
|
|
53
54
|
end
|
54
55
|
|
55
56
|
def on_blockarg(arg_name)
|
57
|
+
arg_name = :& if arg_name == :fwd_block_arg
|
56
58
|
%{['block', '#{arg_name}']}
|
57
59
|
end
|
58
60
|
|
61
|
+
def on_kwnilarg
|
62
|
+
%{['nokey']}
|
63
|
+
end
|
64
|
+
|
59
65
|
def on_shadowarg(_arg_name); end
|
60
66
|
end
|
61
67
|
end
|
data/lib/opal/nodes/class.rb
CHANGED
@@ -15,28 +15,16 @@ module Opal
|
|
15
15
|
|
16
16
|
push '(function($base, $super, $parent_nesting) {'
|
17
17
|
line " var self = $klass($base, $super, '#{name}');"
|
18
|
-
|
19
18
|
in_scope do
|
20
19
|
scope.name = name
|
21
|
-
|
22
|
-
|
23
|
-
body_code = self.body_code
|
24
|
-
empty_line
|
25
|
-
|
26
|
-
line scope.to_vars
|
27
|
-
line body_code
|
20
|
+
compile_body
|
28
21
|
end
|
29
|
-
|
30
22
|
line '})(', base, ', ', super_code, ', $nesting)'
|
31
23
|
end
|
32
24
|
|
33
25
|
def super_code
|
34
26
|
sup ? expr(sup) : 'null'
|
35
27
|
end
|
36
|
-
|
37
|
-
def body_code
|
38
|
-
stmt(compiler.returns(body || s(:nil)))
|
39
|
-
end
|
40
28
|
end
|
41
29
|
end
|
42
30
|
end
|
data/lib/opal/nodes/literal.rb
CHANGED
@@ -70,6 +70,11 @@ module Opal
|
|
70
70
|
wrap "$enc(", ", \"#{encoding.name}\")"
|
71
71
|
end
|
72
72
|
end
|
73
|
+
|
74
|
+
unless value.valid_encoding?
|
75
|
+
helper :binary
|
76
|
+
wrap "$binary(", ")"
|
77
|
+
end
|
73
78
|
end
|
74
79
|
|
75
80
|
# http://www.2ality.com/2013/09/javascript-unicode.html
|
@@ -253,9 +258,11 @@ module Opal
|
|
253
258
|
end
|
254
259
|
|
255
260
|
def compile_inline?
|
256
|
-
|
257
|
-
SIMPLE_CHILDREN_TYPES.include?(start.type)
|
258
|
-
|
261
|
+
(
|
262
|
+
!start || (start.type && SIMPLE_CHILDREN_TYPES.include?(start.type))
|
263
|
+
) && (
|
264
|
+
!finish || (finish.type && SIMPLE_CHILDREN_TYPES.include?(finish.type))
|
265
|
+
)
|
259
266
|
end
|
260
267
|
|
261
268
|
def compile_inline
|
@@ -271,11 +278,11 @@ module Opal
|
|
271
278
|
handle :irange
|
272
279
|
|
273
280
|
def compile_inline
|
274
|
-
push '$range(',
|
281
|
+
push '$range(', expr_or_nil(start), ', ', expr_or_nil(finish), ', false)'
|
275
282
|
end
|
276
283
|
|
277
284
|
def compile_range_initialize
|
278
|
-
push 'Opal.Range.$new(',
|
285
|
+
push 'Opal.Range.$new(', expr_or_nil(start), ', ', expr_or_nil(finish), ', false)'
|
279
286
|
end
|
280
287
|
end
|
281
288
|
|
@@ -283,11 +290,11 @@ module Opal
|
|
283
290
|
handle :erange
|
284
291
|
|
285
292
|
def compile_inline
|
286
|
-
push '$range(',
|
293
|
+
push '$range(', expr_or_nil(start), ', ', expr_or_nil(finish), ', true)'
|
287
294
|
end
|
288
295
|
|
289
296
|
def compile_range_initialize
|
290
|
-
push 'Opal.Range.$new(',
|
297
|
+
push 'Opal.Range.$new(', expr_or_nil(start), ',', expr_or_nil(finish), ', true)'
|
291
298
|
end
|
292
299
|
end
|
293
300
|
|
data/lib/opal/nodes/module.rb
CHANGED
@@ -15,21 +15,15 @@ module Opal
|
|
15
15
|
|
16
16
|
push '(function($base, $parent_nesting) {'
|
17
17
|
line " var self = $module($base, '#{name}');"
|
18
|
-
|
19
18
|
in_scope do
|
20
19
|
scope.name = name
|
21
|
-
|
22
|
-
|
23
|
-
body_code = stmt(body || s(:nil))
|
24
|
-
empty_line
|
25
|
-
|
26
|
-
line scope.to_vars
|
27
|
-
line body_code
|
20
|
+
compile_body
|
28
21
|
end
|
29
|
-
|
30
22
|
line '})(', base, ', $nesting)'
|
31
23
|
end
|
32
24
|
|
25
|
+
private
|
26
|
+
|
33
27
|
# cid is always s(:const, scope_sexp_or_nil, :ConstName)
|
34
28
|
def name_and_base
|
35
29
|
base, name = cid.children
|
@@ -40,6 +34,16 @@ module Opal
|
|
40
34
|
[name, expr(base)]
|
41
35
|
end
|
42
36
|
end
|
37
|
+
|
38
|
+
def compile_body
|
39
|
+
add_temp '$nesting = [self].concat($parent_nesting)'
|
40
|
+
|
41
|
+
body_code = stmt(compiler.returns(body || s(:nil)))
|
42
|
+
empty_line
|
43
|
+
|
44
|
+
line scope.to_vars
|
45
|
+
line body_code
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
data/lib/opal/nodes/variables.rb
CHANGED
@@ -194,9 +194,16 @@ module Opal
|
|
194
194
|
children :name
|
195
195
|
|
196
196
|
def compile
|
197
|
-
|
198
|
-
|
199
|
-
|
197
|
+
helper :class_variable_get
|
198
|
+
|
199
|
+
tolerant = false
|
200
|
+
# We should be tolerant of expressions like: def x; @@notexist; 0; end
|
201
|
+
# (NB: Shouldn't we actually optimize them out?)
|
202
|
+
tolerant = true if stmt?
|
203
|
+
# We should be tolerant of expressions like: @@notexist ||= 6
|
204
|
+
# (those are handled with logical_operator_assignment)
|
205
|
+
|
206
|
+
push "$class_variable_get(#{class_variable_owner}, '#{name}', #{tolerant.inspect})"
|
200
207
|
end
|
201
208
|
end
|
202
209
|
|
@@ -206,7 +213,9 @@ module Opal
|
|
206
213
|
children :name, :value
|
207
214
|
|
208
215
|
def compile
|
209
|
-
|
216
|
+
helper :class_variable_set
|
217
|
+
|
218
|
+
push "$class_variable_set(#{class_variable_owner}, '#{name}', ", expr(value), ')'
|
210
219
|
end
|
211
220
|
end
|
212
221
|
end
|
data/lib/opal/nodes/while.rb
CHANGED
@@ -10,32 +10,45 @@ module Opal
|
|
10
10
|
children :test, :body
|
11
11
|
|
12
12
|
def compile
|
13
|
-
|
14
|
-
test_code = js_truthy(test)
|
13
|
+
test_code = js_truthy(test)
|
15
14
|
|
15
|
+
with_temp do |redo_var|
|
16
16
|
compiler.in_while do
|
17
17
|
while_loop[:closure] = true if wrap_in_closure?
|
18
18
|
while_loop[:redo_var] = redo_var
|
19
19
|
|
20
|
-
body_code = stmt(body)
|
21
|
-
|
20
|
+
body_code = indent { stmt(body) }
|
22
21
|
if uses_redo?
|
23
|
-
|
24
|
-
push test_code
|
25
|
-
push while_close
|
22
|
+
compile_with_redo(test_code, body_code, redo_var)
|
26
23
|
else
|
27
|
-
|
24
|
+
compile_without_redo(test_code, body_code)
|
28
25
|
end
|
29
|
-
|
30
|
-
push "#{redo_var} = false;" if uses_redo?
|
31
|
-
line body_code
|
32
26
|
end
|
33
|
-
line '}'
|
34
27
|
end
|
35
28
|
|
36
29
|
wrap '(function() {', '; return nil; })()' if wrap_in_closure?
|
37
30
|
end
|
38
31
|
|
32
|
+
private
|
33
|
+
|
34
|
+
def compile_with_redo(test_code, body_code, redo_var)
|
35
|
+
push "#{redo_var} = false; "
|
36
|
+
compile_while(
|
37
|
+
[redo_var, " || ", test_code],
|
38
|
+
["#{redo_var} = false;", body_code]
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def compile_without_redo(test_code, body_code)
|
43
|
+
compile_while([test_code], [body_code])
|
44
|
+
end
|
45
|
+
|
46
|
+
def compile_while(test_code, body_code)
|
47
|
+
push while_open, *test_code, while_close
|
48
|
+
indent { line(*body_code) }
|
49
|
+
line '}'
|
50
|
+
end
|
51
|
+
|
39
52
|
def while_open
|
40
53
|
'while ('
|
41
54
|
end
|
@@ -53,13 +66,11 @@ module Opal
|
|
53
66
|
end
|
54
67
|
end
|
55
68
|
|
56
|
-
class WhilePostNode < WhileNode
|
57
|
-
handle :while_post
|
58
|
-
end
|
59
|
-
|
60
69
|
class UntilNode < WhileNode
|
61
70
|
handle :until
|
62
71
|
|
72
|
+
private
|
73
|
+
|
63
74
|
def while_open
|
64
75
|
'while (!('
|
65
76
|
end
|
@@ -69,8 +80,34 @@ module Opal
|
|
69
80
|
end
|
70
81
|
end
|
71
82
|
|
72
|
-
class
|
83
|
+
class WhilePostNode < WhileNode
|
84
|
+
handle :while_post
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def compile_while(test_code, body_code)
|
89
|
+
push "do {"
|
90
|
+
indent { line(*body_code) }
|
91
|
+
line "} ", while_open, *test_code, while_close
|
92
|
+
end
|
93
|
+
|
94
|
+
def while_close
|
95
|
+
');'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class UntilPostNode < WhilePostNode
|
73
100
|
handle :until_post
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def while_open
|
105
|
+
'while(!('
|
106
|
+
end
|
107
|
+
|
108
|
+
def while_close
|
109
|
+
'));'
|
110
|
+
end
|
74
111
|
end
|
75
112
|
end
|
76
113
|
end
|
data/lib/opal/parser.rb
CHANGED
data/lib/opal/parser/patch.rb
CHANGED
@@ -39,3 +39,37 @@ if RUBY_ENGINE == 'opal'
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
|
+
|
43
|
+
module AST::Processor::Mixin
|
44
|
+
undef process
|
45
|
+
# This patch to #process removes a bit of dynamic abilities (removed
|
46
|
+
# call to node.to_ast) and it tries to optimize away the string
|
47
|
+
# operations and method existence check by caching them inside a
|
48
|
+
# processor.
|
49
|
+
#
|
50
|
+
# This is the second most inefficient call in the compilation phase
|
51
|
+
# so an optimization may be warranted.
|
52
|
+
def process(node)
|
53
|
+
return if node.nil?
|
54
|
+
|
55
|
+
@_on_handler_cache ||= {}
|
56
|
+
type = node.type
|
57
|
+
|
58
|
+
on_handler = @_on_handler_cache[type] ||= begin
|
59
|
+
handler = :"on_#{type}"
|
60
|
+
handler = :handler_missing unless respond_to?(handler)
|
61
|
+
handler
|
62
|
+
end
|
63
|
+
|
64
|
+
send(on_handler, node) || node
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class Parser::Builders::Default
|
69
|
+
# string_value raises on invalid UTF-8 strings, like "\x80",
|
70
|
+
# otherwise it's the same as value.
|
71
|
+
undef string_value
|
72
|
+
def string_value(token)
|
73
|
+
value(token)
|
74
|
+
end
|
75
|
+
end
|
data/lib/opal/repl.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'opal'
|
4
|
+
require 'securerandom'
|
4
5
|
|
5
6
|
module Opal
|
6
7
|
class REPL
|
@@ -38,9 +39,15 @@ module Opal
|
|
38
39
|
eval_ruby File.read(filename)
|
39
40
|
end
|
40
41
|
|
42
|
+
# A polyfill so that SecureRandom works in repl correctly.
|
43
|
+
def random_bytes(bytes)
|
44
|
+
::SecureRandom.bytes(bytes).split('').map(&:ord)
|
45
|
+
end
|
46
|
+
|
41
47
|
def load_opal
|
42
48
|
v8.attach('console.log', method(:puts).to_proc)
|
43
49
|
v8.attach('console.warn', method(:warn).to_proc)
|
50
|
+
v8.attach('crypto.randomBytes', method(:random_bytes).to_proc)
|
44
51
|
v8.eval Opal::Builder.new.build('opal').to_s
|
45
52
|
v8.attach('Opal.exit', method(:exit).to_proc)
|
46
53
|
end
|
data/lib/opal/rewriter.rb
CHANGED
@@ -14,6 +14,7 @@ require 'opal/rewriters/mlhs_args'
|
|
14
14
|
require 'opal/rewriters/inline_args'
|
15
15
|
require 'opal/rewriters/numblocks'
|
16
16
|
require 'opal/rewriters/returnable_logic'
|
17
|
+
require 'opal/rewriters/forward_args'
|
17
18
|
|
18
19
|
module Opal
|
19
20
|
class Rewriter
|
@@ -45,6 +46,7 @@ module Opal
|
|
45
46
|
use Rewriters::OpalEngineCheck
|
46
47
|
use Rewriters::ForRewriter
|
47
48
|
use Rewriters::Numblocks
|
49
|
+
use Rewriters::ForwardArgs
|
48
50
|
use Rewriters::BlockToIter
|
49
51
|
use Rewriters::DotJsSyntax
|
50
52
|
use Rewriters::JsReservedWords
|
@@ -4,7 +4,7 @@ module Opal
|
|
4
4
|
module Rewriters
|
5
5
|
class Arguments
|
6
6
|
attr_reader :args, :optargs, :restarg, :postargs,
|
7
|
-
:kwargs, :kwoptargs, :kwrestarg,
|
7
|
+
:kwargs, :kwoptargs, :kwrestarg, :kwnilarg,
|
8
8
|
:shadowargs, :blockarg
|
9
9
|
|
10
10
|
def initialize(args)
|
@@ -15,6 +15,7 @@ module Opal
|
|
15
15
|
@kwargs = []
|
16
16
|
@kwoptargs = []
|
17
17
|
@kwrestarg = nil
|
18
|
+
@kwnilarg = false
|
18
19
|
@shadowargs = []
|
19
20
|
@blockarg = nil
|
20
21
|
|
@@ -30,6 +31,8 @@ module Opal
|
|
30
31
|
@kwargs << arg
|
31
32
|
when :kwoptarg
|
32
33
|
@kwoptargs << arg
|
34
|
+
when :kwnilarg
|
35
|
+
@kwnilarg = true
|
33
36
|
when :kwrestarg
|
34
37
|
@kwrestarg = arg
|
35
38
|
when :shadowarg
|