opal 1.4.1 → 1.5.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|