opal 1.4.1 → 1.5.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.eslintrc.js +5 -3
- data/.rubocop.yml +1 -0
- data/UNRELEASED.md +37 -2
- data/benchmark-ips/bm_js_symbols_vs_strings.rb +39 -14
- data/docs/releasing.md +10 -2
- data/lib/opal/ast/matcher.rb +77 -0
- data/lib/opal/cache.rb +1 -1
- data/lib/opal/cli_runners/applescript.rb +2 -0
- data/lib/opal/compiler.rb +18 -9
- data/lib/opal/nodes/call.rb +73 -28
- data/lib/opal/nodes/def.rb +31 -27
- data/lib/opal/nodes/definitions.rb +2 -0
- data/lib/opal/nodes/helpers.rb +4 -23
- data/lib/opal/nodes/if.rb +222 -0
- data/lib/opal/nodes/iter.rb +41 -37
- data/lib/opal/nodes/literal.rb +2 -2
- data/lib/opal/nodes/masgn.rb +15 -17
- data/lib/opal/nodes/node_with_args/shortcuts.rb +100 -0
- data/lib/opal/nodes/node_with_args.rb +1 -0
- data/lib/opal/nodes/top.rb +26 -10
- data/lib/opal/nodes.rb +0 -1
- data/lib/opal/parser/default_config.rb +3 -2
- data/lib/opal/repl.rb +1 -1
- data/lib/opal/rewriter.rb +13 -6
- data/lib/opal/rewriters/base.rb +12 -1
- data/lib/opal/rewriters/rubyspec/filters_rewriter.rb +1 -0
- data/lib/opal/version.rb +1 -1
- data/opal/corelib/array.rb +23 -28
- data/opal/corelib/binding.rb +14 -4
- data/opal/corelib/constants.rb +3 -3
- data/opal/corelib/hash.rb +2 -2
- data/opal/corelib/irb.rb +192 -0
- data/opal/corelib/math/polyfills.rb +127 -0
- data/opal/corelib/math.rb +14 -194
- data/opal/corelib/module.rb +23 -25
- data/opal/corelib/number.rb +63 -14
- data/opal/corelib/regexp.rb +2 -0
- data/opal/corelib/runtime.js +56 -20
- data/opal/corelib/string.rb +38 -59
- data/opal/corelib/time.rb +106 -68
- data/opal/opal/full.rb +0 -1
- data/opal/opal.rb +4 -1
- data/spec/filters/bugs/date.rb +0 -3
- data/spec/filters/bugs/datetime.rb +65 -0
- data/spec/filters/bugs/float.rb +0 -18
- data/spec/filters/bugs/hash.rb +0 -2
- data/spec/filters/bugs/language.rb +0 -3
- data/spec/filters/bugs/marshal.rb +0 -1
- data/spec/filters/bugs/string.rb +0 -30
- data/spec/filters/bugs/time.rb +18 -8
- data/spec/lib/cli_spec.rb +2 -2
- data/spec/lib/compiler_spec.rb +8 -8
- data/spec/lib/rewriters/base_spec.rb +1 -1
- data/spec/lib/rewriters/binary_operator_assignment_spec.rb +34 -59
- data/spec/lib/rewriters/block_to_iter_spec.rb +3 -6
- data/spec/lib/rewriters/dot_js_syntax_spec.rb +2 -5
- data/spec/lib/rewriters/for_rewriter_spec.rb +0 -1
- data/spec/lib/rewriters/forward_args_spec.rb +2 -3
- data/spec/lib/rewriters/js_reserved_words_spec.rb +2 -15
- data/spec/lib/rewriters/logical_operator_assignment_spec.rb +64 -89
- data/spec/lib/rewriters/numblocks_spec.rb +3 -5
- data/spec/lib/rewriters/opal_engine_check_spec.rb +2 -14
- data/spec/lib/rewriters/rubyspec/filters_rewriter_spec.rb +10 -2
- data/spec/opal/compiler/irb_spec.rb +4 -0
- data/spec/opal/core/language/super_spec.rb +26 -0
- data/spec/opal/core/regexp/assertions_spec.rb +19 -0
- data/spec/opal/core/string/to_proc_spec.rb +19 -0
- data/spec/ruby_specs +4 -0
- data/spec/support/rewriters_helper.rb +43 -23
- data/stdlib/date/date_time.rb +71 -0
- data/stdlib/date/formatters.rb +28 -0
- data/stdlib/date/infinity.rb +73 -0
- data/stdlib/date.rb +77 -214
- data/stdlib/opal/repl_js.rb +1 -1
- data/stdlib/{opal/replutils.rb → opal-replutils.rb} +3 -3
- data/stdlib/time.rb +39 -2
- data/stdlib/uri.rb +53 -0
- data/tasks/performance/asciidoctor_test.rb.erb +3 -1
- data/tasks/performance/optimization_status.rb +3 -2
- data/tasks/performance.rake +69 -35
- data/tasks/testing.rake +1 -0
- data/test/opal/test_uri.rb +35 -0
- data/yarn.lock +27 -5
- metadata +31 -18
- data/lib/opal/nodes/csend.rb +0 -24
- data/lib/opal/rewriters/explicit_writer_return.rb +0 -59
- data/spec/lib/rewriters/explicit_writer_return_spec.rb +0 -186
- data/stdlib/nodejs/irb.rb +0 -43
data/lib/opal/rewriters/base.rb
CHANGED
@@ -51,7 +51,6 @@ module Opal
|
|
51
51
|
end
|
52
52
|
|
53
53
|
alias on_iter process_regular_node
|
54
|
-
alias on_top process_regular_node
|
55
54
|
alias on_zsuper process_regular_node
|
56
55
|
alias on_jscall on_send
|
57
56
|
alias on_jsattr process_regular_node
|
@@ -124,6 +123,18 @@ module Opal
|
|
124
123
|
error.location = current_node.loc if current_node
|
125
124
|
raise error
|
126
125
|
end
|
126
|
+
|
127
|
+
def on_top(node)
|
128
|
+
node = process_regular_node(node)
|
129
|
+
node.meta[:dynamic_cache_result] = true if @dynamic_cache_result
|
130
|
+
node
|
131
|
+
end
|
132
|
+
|
133
|
+
# Called when a given transformation is deemed to be dynamic, so
|
134
|
+
# that cache is conditionally disabled for a given file.
|
135
|
+
def dynamic!
|
136
|
+
@dynamic_cache_result = true
|
137
|
+
end
|
127
138
|
end
|
128
139
|
end
|
129
140
|
end
|
data/lib/opal/version.rb
CHANGED
data/opal/corelib/array.rb
CHANGED
@@ -441,20 +441,18 @@ class ::Array < `Array`
|
|
441
441
|
end
|
442
442
|
|
443
443
|
def []=(index, value, extra = undefined)
|
444
|
+
data = nil
|
444
445
|
%x{
|
445
446
|
var i, size = self.length;
|
446
|
-
}
|
447
447
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
end
|
448
|
+
if (index.$$is_range) {
|
449
|
+
if (value.$$is_array)
|
450
|
+
data = #{value.to_a};
|
451
|
+
else if (#{value.respond_to? :to_ary})
|
452
|
+
data = #{value.to_ary.to_a};
|
453
|
+
else
|
454
|
+
data = [value];
|
456
455
|
|
457
|
-
%x{
|
458
456
|
var exclude = index.excl,
|
459
457
|
from = index.begin === nil ? 0 : $coerce_to(index.begin, Opal.Integer, 'to_int'),
|
460
458
|
to = index.end === nil ? -1 : $coerce_to(index.end, Opal.Integer, 'to_int');
|
@@ -489,24 +487,21 @@ class ::Array < `Array`
|
|
489
487
|
}
|
490
488
|
|
491
489
|
return value;
|
492
|
-
}
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
end
|
507
|
-
end
|
490
|
+
} else {
|
491
|
+
if (extra === undefined) {
|
492
|
+
#{length = 1}
|
493
|
+
} else {
|
494
|
+
length = value;
|
495
|
+
value = extra;
|
496
|
+
|
497
|
+
if (value.$$is_array)
|
498
|
+
data = #{value.to_a};
|
499
|
+
else if (#{value.respond_to? :to_ary})
|
500
|
+
data = #{value.to_ary.to_a};
|
501
|
+
else
|
502
|
+
data = [value];
|
503
|
+
}
|
508
504
|
|
509
|
-
%x{
|
510
505
|
var old;
|
511
506
|
|
512
507
|
index = $coerce_to(index, #{::Integer}, 'to_int');
|
@@ -540,7 +535,7 @@ class ::Array < `Array`
|
|
540
535
|
|
541
536
|
return value;
|
542
537
|
}
|
543
|
-
|
538
|
+
}
|
544
539
|
end
|
545
540
|
|
546
541
|
def any?(pattern = undefined, &block)
|
data/opal/corelib/binding.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
class ::Binding
|
2
2
|
# @private
|
3
|
-
def initialize(jseval, scope_variables, receiver, source_location)
|
3
|
+
def initialize(jseval, scope_variables = [], receiver = undefined, source_location = nil)
|
4
4
|
@jseval, @scope_variables, @receiver, @source_location = \
|
5
5
|
jseval, scope_variables, receiver, source_location
|
6
|
+
receiver = js_eval('self') unless `typeof receiver !== undefined`
|
6
7
|
end
|
7
8
|
|
8
9
|
def js_eval(*args)
|
@@ -20,7 +21,10 @@ class ::Binding
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def local_variable_set(symbol, value)
|
23
|
-
|
24
|
+
`Opal.Binding.tmp_value = value`
|
25
|
+
js_eval("#{symbol} = Opal.Binding.tmp_value")
|
26
|
+
`delete Opal.Binding.tmp_value`
|
27
|
+
value
|
24
28
|
end
|
25
29
|
|
26
30
|
def local_variables
|
@@ -46,5 +50,11 @@ module ::Kernel
|
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
|
-
TOPLEVEL_BINDING =
|
50
|
-
|
53
|
+
TOPLEVEL_BINDING = ::Binding.new(
|
54
|
+
%x{
|
55
|
+
function(js) {
|
56
|
+
return (new Function("self", "return " + js))(self);
|
57
|
+
}
|
58
|
+
},
|
59
|
+
[], self, ['<main>', 0]
|
60
|
+
)
|
data/opal/corelib/constants.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
::RUBY_PLATFORM = 'opal'
|
2
2
|
::RUBY_ENGINE = 'opal'
|
3
3
|
::RUBY_VERSION = '3.1.0'
|
4
|
-
::RUBY_ENGINE_VERSION = '1.
|
5
|
-
::RUBY_RELEASE_DATE = '2022-
|
4
|
+
::RUBY_ENGINE_VERSION = '1.5.0.rc1'
|
5
|
+
::RUBY_RELEASE_DATE = '2022-04-06'
|
6
6
|
::RUBY_PATCHLEVEL = 0
|
7
7
|
::RUBY_REVISION = '0'
|
8
|
-
::RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-
|
8
|
+
::RUBY_COPYRIGHT = 'opal - Copyright (C) 2013-2022 Adam Beynon and the Opal contributors'
|
9
9
|
::RUBY_DESCRIPTION = "opal #{::RUBY_ENGINE_VERSION} (#{::RUBY_RELEASE_DATE} revision #{::RUBY_REVISION})"
|
data/opal/corelib/hash.rb
CHANGED
@@ -423,7 +423,7 @@ class ::Hash
|
|
423
423
|
return enum_for(:each) { size } unless block
|
424
424
|
|
425
425
|
%x{
|
426
|
-
for (var i = 0, keys = self.$$keys, length = keys.length, key, value; i < length; i++) {
|
426
|
+
for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key, value; i < length; i++) {
|
427
427
|
key = keys[i];
|
428
428
|
|
429
429
|
if (key.$$is_string) {
|
@@ -444,7 +444,7 @@ class ::Hash
|
|
444
444
|
return enum_for(:each_key) { size } unless block
|
445
445
|
|
446
446
|
%x{
|
447
|
-
for (var i = 0, keys = self.$$keys, length = keys.length, key; i < length; i++) {
|
447
|
+
for (var i = 0, keys = self.$$keys.slice(), length = keys.length, key; i < length; i++) {
|
448
448
|
key = keys[i];
|
449
449
|
|
450
450
|
block(key.$$is_string ? key : key.key);
|
data/opal/corelib/irb.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
# Debug is a helper module that allows us to conduct some debugging on
|
2
|
+
# a live codebase. It goes with an assumption, that opal-parser or
|
3
|
+
# opal-replutils will not be loaded, in which case we will do what we can
|
4
|
+
# to provision it.
|
5
|
+
|
6
|
+
module Opal
|
7
|
+
module IRB
|
8
|
+
def self.ensure_loaded(library)
|
9
|
+
return if `Opal.loaded_features`.include? library
|
10
|
+
|
11
|
+
version = if RUBY_ENGINE_VERSION.include? 'dev'
|
12
|
+
'master'
|
13
|
+
else
|
14
|
+
RUBY_ENGINE_VERSION
|
15
|
+
end
|
16
|
+
|
17
|
+
url = "https://cdn.opalrb.com/opal/#{version}/#{library}.js"
|
18
|
+
|
19
|
+
%x{
|
20
|
+
var libcode;
|
21
|
+
|
22
|
+
if (typeof XMLHttpRequest !== 'undefined') { // Browser
|
23
|
+
var r = new XMLHttpRequest();
|
24
|
+
r.open("GET", url, false);
|
25
|
+
r.send('');
|
26
|
+
libcode = r.responseText;
|
27
|
+
}
|
28
|
+
else {
|
29
|
+
#{::Kernel.raise "You need to provision #{library} yourself in this environment"}
|
30
|
+
}
|
31
|
+
|
32
|
+
(new Function('Opal', libcode))(Opal);
|
33
|
+
|
34
|
+
Opal.require(library);
|
35
|
+
}
|
36
|
+
|
37
|
+
::Kernel.raise "Could not load #{library} for some reason" unless `Opal.loaded_features`.include? library
|
38
|
+
end
|
39
|
+
|
40
|
+
singleton_class.attr_accessor :output
|
41
|
+
|
42
|
+
def self.prepare_console(&block)
|
43
|
+
self.output = ''
|
44
|
+
|
45
|
+
original = {
|
46
|
+
$stdout => ->(i) { $stdout = i },
|
47
|
+
$stderr => ->(i) { $stderr = i },
|
48
|
+
}
|
49
|
+
|
50
|
+
# Prepare a better prompt experience for a browser
|
51
|
+
if browser?
|
52
|
+
original.each do |pipe, pipe_setter|
|
53
|
+
new_pipe = pipe.dup
|
54
|
+
new_pipe.write_proc = proc do |str|
|
55
|
+
self.output += str
|
56
|
+
self.output = output.split("\n").last(30).join("\n")
|
57
|
+
self.output += "\n" if str.end_with? "\n"
|
58
|
+
|
59
|
+
pipe.write_proc.call(str)
|
60
|
+
end
|
61
|
+
new_pipe.tty = false
|
62
|
+
pipe_setter.call(new_pipe)
|
63
|
+
end
|
64
|
+
|
65
|
+
original_read_proc = $stdin.read_proc
|
66
|
+
$stdin.read_proc = `function(s) { var p = prompt(#{output}); if (p !== null) return p + "\n"; return nil; }`
|
67
|
+
end
|
68
|
+
|
69
|
+
yield
|
70
|
+
ensure
|
71
|
+
original.each do |pipe, pipe_setter|
|
72
|
+
pipe_setter.call(pipe)
|
73
|
+
end
|
74
|
+
$stdin.read_proc = original_read_proc
|
75
|
+
self.output = ''
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.browser?
|
79
|
+
`typeof(document) !== 'undefined' && typeof(prompt) !== 'undefined'`
|
80
|
+
end
|
81
|
+
|
82
|
+
LINEBREAKS = [
|
83
|
+
'unexpected token $end',
|
84
|
+
'unterminated string meets end of file'
|
85
|
+
].freeze
|
86
|
+
|
87
|
+
class Silencer
|
88
|
+
def initialize
|
89
|
+
@stderr = $stderr
|
90
|
+
end
|
91
|
+
|
92
|
+
def silence
|
93
|
+
@collector = ::StringIO.new
|
94
|
+
$stderr = @collector
|
95
|
+
yield
|
96
|
+
ensure
|
97
|
+
$stderr = @stderr
|
98
|
+
end
|
99
|
+
|
100
|
+
def warnings
|
101
|
+
@collector.string
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class ::Binding
|
108
|
+
def irb
|
109
|
+
::Opal::IRB.ensure_loaded('opal-replutils')
|
110
|
+
|
111
|
+
silencer = ::Opal::IRB::Silencer.new
|
112
|
+
|
113
|
+
::Opal::IRB.prepare_console do
|
114
|
+
loop do
|
115
|
+
print '>> '
|
116
|
+
line = gets
|
117
|
+
break unless line
|
118
|
+
code = ''
|
119
|
+
|
120
|
+
puts line if ::Opal::IRB.browser?
|
121
|
+
|
122
|
+
if line.start_with? 'ls '
|
123
|
+
code = line[3..-1]
|
124
|
+
mode = :ls
|
125
|
+
elsif line == "ls\n"
|
126
|
+
code = 'self'
|
127
|
+
mode = :ls
|
128
|
+
elsif line.start_with? 'show '
|
129
|
+
code = line[5..-1]
|
130
|
+
mode = :show
|
131
|
+
else
|
132
|
+
code = line
|
133
|
+
mode = :inspect
|
134
|
+
end
|
135
|
+
|
136
|
+
js_code = nil
|
137
|
+
|
138
|
+
begin
|
139
|
+
silencer.silence do
|
140
|
+
js_code = `Opal.compile(code, {irb: true})`
|
141
|
+
end
|
142
|
+
rescue SyntaxError => e
|
143
|
+
if ::Opal::IRB::LINEBREAKS.include?(e.message)
|
144
|
+
print '.. '
|
145
|
+
line = gets
|
146
|
+
return unless line
|
147
|
+
puts line if ::Opal::IRB.browser?
|
148
|
+
code += line
|
149
|
+
retry
|
150
|
+
elsif silencer.warnings.empty?
|
151
|
+
warn e.full_message
|
152
|
+
else
|
153
|
+
# Most likely a parser error
|
154
|
+
warn silencer.warnings
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
if mode == :show
|
159
|
+
puts js_code
|
160
|
+
return
|
161
|
+
end
|
162
|
+
|
163
|
+
puts ::REPLUtils.eval_and_print(js_code, mode, false, self)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
%x{
|
170
|
+
// Run in WebTools console with: Opal.irb(c => eval(c))
|
171
|
+
Opal.irb = function(fun) {
|
172
|
+
#{::Binding.new(`fun`).irb}
|
173
|
+
}
|
174
|
+
|
175
|
+
Opal.load_parser = function() {
|
176
|
+
Opal.Opal.IRB.$ensure_loaded('opal-parser');
|
177
|
+
}
|
178
|
+
|
179
|
+
if (typeof Opal.eval === 'undefined') {
|
180
|
+
Opal.eval = function(str) {
|
181
|
+
Opal.load_parser();
|
182
|
+
return Opal.eval(str);
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
if (typeof Opal.compile === 'undefined') {
|
187
|
+
Opal.compile = function(str, options) {
|
188
|
+
Opal.load_parser();
|
189
|
+
return Opal.compile(str, options);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# Polyfills for browsers in the age of IE11
|
2
|
+
|
3
|
+
unless defined?(`Math.acosh`)
|
4
|
+
%x{
|
5
|
+
Math.acosh = function(x) {
|
6
|
+
return Math.log(x + Math.sqrt(x * x - 1));
|
7
|
+
}
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
unless defined?(`Math.asinh`)
|
12
|
+
%x{
|
13
|
+
Math.asinh = function(x) {
|
14
|
+
return Math.log(x + Math.sqrt(x * x + 1))
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
unless defined?(`Math.atanh`)
|
20
|
+
%x{
|
21
|
+
Math.atanh = function(x) {
|
22
|
+
return 0.5 * Math.log((1 + x) / (1 - x));
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
unless defined?(`Math.cbrt`)
|
28
|
+
%x{
|
29
|
+
Math.cbrt = function(x) {
|
30
|
+
if (x == 0) {
|
31
|
+
return 0;
|
32
|
+
}
|
33
|
+
|
34
|
+
if (x < 0) {
|
35
|
+
return -Math.cbrt(-x);
|
36
|
+
}
|
37
|
+
|
38
|
+
var r = x,
|
39
|
+
ex = 0;
|
40
|
+
|
41
|
+
while (r < 0.125) {
|
42
|
+
r *= 8;
|
43
|
+
ex--;
|
44
|
+
}
|
45
|
+
|
46
|
+
while (r > 1.0) {
|
47
|
+
r *= 0.125;
|
48
|
+
ex++;
|
49
|
+
}
|
50
|
+
|
51
|
+
r = (-0.46946116 * r + 1.072302) * r + 0.3812513;
|
52
|
+
|
53
|
+
while (ex < 0) {
|
54
|
+
r *= 0.5;
|
55
|
+
ex++;
|
56
|
+
}
|
57
|
+
|
58
|
+
while (ex > 0) {
|
59
|
+
r *= 2;
|
60
|
+
ex--;
|
61
|
+
}
|
62
|
+
|
63
|
+
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
|
64
|
+
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
|
65
|
+
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
|
66
|
+
r = (2.0 / 3.0) * r + (1.0 / 3.0) * x / (r * r);
|
67
|
+
|
68
|
+
return r;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
unless defined?(`Math.cosh`)
|
74
|
+
%x{
|
75
|
+
Math.cosh = function(x) {
|
76
|
+
return (Math.exp(x) + Math.exp(-x)) / 2;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
unless defined?(`Math.hypot`)
|
82
|
+
%x{
|
83
|
+
Math.hypot = function(x, y) {
|
84
|
+
return Math.sqrt(x * x + y * y)
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
unless defined?(`Math.log2`)
|
90
|
+
%x{
|
91
|
+
Math.log2 = function(x) {
|
92
|
+
return Math.log(x) / Math.LN2;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
unless defined?(`Math.log10`)
|
98
|
+
%x{
|
99
|
+
Math.log10 = function(x) {
|
100
|
+
return Math.log(x) / Math.LN10;
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
unless defined?(`Math.sinh`)
|
106
|
+
%x{
|
107
|
+
Math.sinh = function(x) {
|
108
|
+
return (Math.exp(x) - Math.exp(-x)) / 2;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
unless defined?(`Math.tanh`)
|
114
|
+
%x{
|
115
|
+
Math.tanh = function(x) {
|
116
|
+
if (x == Infinity) {
|
117
|
+
return 1;
|
118
|
+
}
|
119
|
+
else if (x == -Infinity) {
|
120
|
+
return -1;
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x));
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
end
|