opal 0.7.0.beta3 → 0.7.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +4 -0
- data/.travis.yml +7 -3
- data/.yardopts +6 -0
- data/CHANGELOG.md +28 -0
- data/Gemfile +1 -1
- data/README.md +3 -12
- data/Rakefile +4 -150
- data/bin/opal-mspec +1 -1
- data/docs/compiler_directives.md +127 -0
- data/examples/rack/.gitignore +1 -0
- data/examples/rack/app/user.rb +1 -0
- data/lib/mspec/opal/special_calls.rb +15 -2
- data/lib/opal/builder.rb +15 -8
- data/lib/opal/compiler.rb +75 -4
- data/lib/opal/erb.rb +22 -2
- data/lib/opal/fragment.rb +17 -5
- data/lib/opal/nodes/def.rb +174 -53
- data/lib/opal/nodes/if.rb +14 -0
- data/lib/opal/nodes/module.rb +0 -1
- data/lib/opal/nodes/rescue.rb +10 -2
- data/lib/opal/nodes/scope.rb +0 -17
- data/lib/opal/parser.rb +83 -19
- data/lib/opal/parser/grammar.rb +2511 -2414
- data/lib/opal/parser/grammar.y +71 -9
- data/lib/opal/parser/lexer.rb +44 -12
- data/lib/opal/parser/parser_scope.rb +3 -0
- data/lib/opal/parser/sexp.rb +7 -1
- data/lib/opal/paths.rb +5 -5
- data/lib/opal/sprockets/environment.rb +2 -10
- data/lib/opal/sprockets/path_reader.rb +1 -1
- data/lib/opal/sprockets/processor.rb +1 -0
- data/lib/opal/sprockets/server.rb +2 -0
- data/lib/opal/util.rb +7 -2
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -0
- data/opal/README.md +1 -1
- data/opal/corelib/dir.rb +1 -1
- data/opal/corelib/enumerable.rb +3 -1
- data/opal/corelib/error.rb +3 -0
- data/opal/corelib/file.rb +2 -0
- data/opal/corelib/hash.rb +3 -0
- data/opal/corelib/io.rb +15 -1
- data/opal/corelib/kernel.rb +8 -0
- data/opal/corelib/module.rb +42 -17
- data/opal/corelib/runtime.js +223 -49
- data/opal/corelib/string.rb +1 -1
- data/opal/corelib/struct.rb +1 -7
- data/spec/README.md +8 -0
- data/spec/filters/bugs/language.rb +1 -0
- data/spec/filters/bugs/module.rb +4 -0
- data/spec/filters/unsupported/frozen.rb +2 -0
- data/spec/lib/compiler/pre_processed_conditionals_spec.rb +87 -0
- data/spec/lib/compiler_spec.rb +1 -67
- data/spec/lib/fixtures/file_with_directives.js +2 -0
- data/spec/lib/fixtures/required_file.js +1 -0
- data/spec/lib/parser/def_spec.rb +29 -16
- data/spec/lib/parser/variables_spec.rb +5 -5
- data/spec/lib/sprockets/path_reader_spec.rb +24 -8
- data/spec/lib/sprockets/server_spec.rb +10 -3
- data/spec/opal/core/date_spec.rb +14 -0
- data/spec/opal/core/language/versions/def_2_0_spec.rb +62 -0
- data/spec/opal/core/language_spec.rb +23 -0
- data/spec/opal/core/runtime/donate_spec.rb +53 -0
- data/spec/opal/stdlib/native/native_alias_spec.rb +19 -0
- data/spec/opal/stdlib/native/native_class_spec.rb +18 -0
- data/spec/opal/stdlib/native/native_module_spec.rb +13 -0
- data/spec/rubyspecs +2 -0
- data/stdlib/buffer.rb +1 -0
- data/stdlib/date.rb +18 -0
- data/stdlib/encoding.rb +3 -2
- data/stdlib/minitest.rb +780 -0
- data/stdlib/minitest/assertions.rb +662 -0
- data/stdlib/minitest/autorun.rb +12 -0
- data/stdlib/minitest/benchmark.rb +426 -0
- data/stdlib/minitest/expectations.rb +281 -0
- data/stdlib/minitest/hell.rb +11 -0
- data/stdlib/minitest/mock.rb +220 -0
- data/stdlib/minitest/parallel.rb +65 -0
- data/stdlib/minitest/pride.rb +4 -0
- data/stdlib/minitest/pride_plugin.rb +142 -0
- data/stdlib/minitest/spec.rb +310 -0
- data/stdlib/minitest/test.rb +293 -0
- data/stdlib/minitest/unit.rb +45 -0
- data/stdlib/native.rb +12 -3
- data/stdlib/nodejs/process.rb +16 -2
- data/stdlib/promise.rb +99 -0
- data/stdlib/test/unit.rb +10 -0
- data/stdlib/thread.rb +4 -0
- data/tasks/building.rake +58 -0
- data/tasks/documentation.rake +38 -0
- data/tasks/documenting.rake +37 -0
- data/tasks/testing.rake +102 -0
- metadata +57 -2
data/lib/opal/parser/grammar.y
CHANGED
@@ -15,7 +15,7 @@ token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS
|
|
15
15
|
tLCURLY tRCURLY tBACK_REF2 tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG
|
16
16
|
tWORDS_BEG tAWORDS_BEG tSTRING_DBEG tSTRING_DVAR tSTRING_END tSTRING
|
17
17
|
tSYMBOL tNL tEH tCOLON tCOMMA tSPACE tSEMI tLAMBDA tLAMBEG
|
18
|
-
tLBRACK2 tLBRACK
|
18
|
+
tLBRACK2 tLBRACK tDSTAR
|
19
19
|
|
20
20
|
prechigh
|
21
21
|
right tBANG tTILDE tUPLUS
|
@@ -1458,35 +1458,97 @@ xstring_contents: none
|
|
1458
1458
|
result = val[0]
|
1459
1459
|
}
|
1460
1460
|
|
1461
|
-
|
1461
|
+
kwrest_mark: tPOW
|
1462
|
+
| tDSTAR
|
1463
|
+
|
1464
|
+
f_kwrest: kwrest_mark tIDENTIFIER
|
1465
|
+
{
|
1466
|
+
result = new_kwrestarg(val[1])
|
1467
|
+
}
|
1468
|
+
| kwrest_mark
|
1469
|
+
{
|
1470
|
+
result = new_kwrestarg()
|
1471
|
+
}
|
1472
|
+
|
1473
|
+
f_label: tLABEL
|
1474
|
+
{
|
1475
|
+
result = new_sym(val[0])
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
f_kw: f_label arg_value
|
1479
|
+
{
|
1480
|
+
result = new_kwoptarg(val[0], val[1])
|
1481
|
+
}
|
1482
|
+
| f_label
|
1483
|
+
{
|
1484
|
+
result = new_kwarg(val[0])
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
f_kwarg: f_kw
|
1488
|
+
{
|
1489
|
+
result = [val[0]]
|
1490
|
+
}
|
1491
|
+
| f_kwarg tCOMMA f_kw
|
1492
|
+
{
|
1493
|
+
result = val[0]
|
1494
|
+
result << val[2]
|
1495
|
+
}
|
1496
|
+
|
1497
|
+
args_tail: f_kwarg tCOMMA f_kwrest opt_f_block_arg
|
1498
|
+
{
|
1499
|
+
result = new_args_tail(val[0], val[2], val[3])
|
1500
|
+
}
|
1501
|
+
| f_kwarg opt_f_block_arg
|
1502
|
+
{
|
1503
|
+
result = new_args_tail(val[0], nil, val[1])
|
1504
|
+
}
|
1505
|
+
| f_kwrest opt_f_block_arg
|
1506
|
+
{
|
1507
|
+
result = new_args_tail(nil, val[0], val[1])
|
1508
|
+
}
|
1509
|
+
| f_block_arg
|
1510
|
+
{
|
1511
|
+
result = new_args_tail(nil, nil, val[0])
|
1512
|
+
}
|
1513
|
+
|
1514
|
+
opt_args_tail: tCOMMA args_tail
|
1515
|
+
{
|
1516
|
+
result = val[1]
|
1517
|
+
}
|
1518
|
+
| # none
|
1519
|
+
{
|
1520
|
+
result = new_args_tail(nil, nil, nil)
|
1521
|
+
}
|
1522
|
+
|
1523
|
+
f_args: f_arg tCOMMA f_optarg tCOMMA f_rest_arg opt_args_tail
|
1462
1524
|
{
|
1463
1525
|
result = new_args(val[0], val[2], val[4], val[5])
|
1464
1526
|
}
|
1465
|
-
| f_arg tCOMMA f_optarg
|
1527
|
+
| f_arg tCOMMA f_optarg opt_args_tail
|
1466
1528
|
{
|
1467
1529
|
result = new_args(val[0], val[2], nil, val[3])
|
1468
1530
|
}
|
1469
|
-
| f_arg tCOMMA f_rest_arg
|
1531
|
+
| f_arg tCOMMA f_rest_arg opt_args_tail
|
1470
1532
|
{
|
1471
1533
|
result = new_args(val[0], nil, val[2], val[3])
|
1472
1534
|
}
|
1473
|
-
| f_arg
|
1535
|
+
| f_arg opt_args_tail
|
1474
1536
|
{
|
1475
1537
|
result = new_args(val[0], nil, nil, val[1])
|
1476
1538
|
}
|
1477
|
-
| f_optarg tCOMMA f_rest_arg
|
1539
|
+
| f_optarg tCOMMA f_rest_arg opt_args_tail
|
1478
1540
|
{
|
1479
1541
|
result = new_args(nil, val[0], val[2], val[3])
|
1480
1542
|
}
|
1481
|
-
| f_optarg
|
1543
|
+
| f_optarg opt_args_tail
|
1482
1544
|
{
|
1483
1545
|
result = new_args(nil, val[0], nil, val[1])
|
1484
1546
|
}
|
1485
|
-
| f_rest_arg
|
1547
|
+
| f_rest_arg opt_args_tail
|
1486
1548
|
{
|
1487
1549
|
result = new_args(nil, nil, val[0], val[1])
|
1488
1550
|
}
|
1489
|
-
|
|
1551
|
+
| args_tail
|
1490
1552
|
{
|
1491
1553
|
result = new_args(nil, nil, nil, val[0])
|
1492
1554
|
}
|
data/lib/opal/parser/lexer.rb
CHANGED
@@ -2,6 +2,23 @@ require 'strscan'
|
|
2
2
|
require 'opal/parser/keywords'
|
3
3
|
|
4
4
|
module Opal
|
5
|
+
# {Opal::Lexer} is used by {Opal::Parser} to step through ruby code, and
|
6
|
+
# returning tokens representing each chunk of ruby code.
|
7
|
+
#
|
8
|
+
# Tokens are in the form:
|
9
|
+
#
|
10
|
+
# [token, [value, location]]
|
11
|
+
#
|
12
|
+
# where `location` is in the form `[line_number, column_number]`. The location
|
13
|
+
# data can be used to produce source maps in the compiler. Tokens are
|
14
|
+
# generally ruby symbols, and the value will always be a string value.
|
15
|
+
#
|
16
|
+
# The main method used by the parser is {#next_token}, which is called
|
17
|
+
# repeatedly until a token of value `false` is returned, which indicated the
|
18
|
+
# EOF has been reached.
|
19
|
+
#
|
20
|
+
# Generally this class is only used by {Opal::Parser} directly.
|
21
|
+
#
|
5
22
|
class Lexer
|
6
23
|
|
7
24
|
STR_FUNC_ESCAPE = 0x01
|
@@ -31,6 +48,13 @@ module Opal
|
|
31
48
|
attr_accessor :yylval
|
32
49
|
attr_accessor :parser
|
33
50
|
|
51
|
+
# Create a new instance using the given ruby code and filename for
|
52
|
+
# reference.
|
53
|
+
#
|
54
|
+
# Opal::Lexer.new("ruby code", "my_file.rb")
|
55
|
+
#
|
56
|
+
# @param source [String] ruby code to lex
|
57
|
+
# @param file [String] filename of given ruby code
|
34
58
|
def initialize(source, file)
|
35
59
|
@lex_state = :expr_beg
|
36
60
|
@cond = 0
|
@@ -48,6 +72,25 @@ module Opal
|
|
48
72
|
@start_of_lambda = nil
|
49
73
|
end
|
50
74
|
|
75
|
+
# Returns next token from source input stream.
|
76
|
+
#
|
77
|
+
# Token in form:
|
78
|
+
#
|
79
|
+
# [token, [value, [source_line, source_column]]]
|
80
|
+
#
|
81
|
+
# @return [Array]
|
82
|
+
def next_token
|
83
|
+
token = self.yylex
|
84
|
+
value = self.yylval
|
85
|
+
location = [@tok_line, @tok_column]
|
86
|
+
|
87
|
+
# once location is stored, ensure next token starts in correct place
|
88
|
+
@tok_column = @column
|
89
|
+
@tok_line = @line
|
90
|
+
|
91
|
+
[token, [value, location]]
|
92
|
+
end
|
93
|
+
|
51
94
|
def has_local?(local)
|
52
95
|
parser.scope.has_local?(local.to_sym)
|
53
96
|
end
|
@@ -151,18 +194,6 @@ module Opal
|
|
151
194
|
@line = @tok_line = line
|
152
195
|
end
|
153
196
|
|
154
|
-
def next_token
|
155
|
-
token = self.yylex
|
156
|
-
value = self.yylval
|
157
|
-
location = [@tok_line, @tok_column]
|
158
|
-
|
159
|
-
# once location is stored, ensure next token starts in correct place
|
160
|
-
@tok_column = @column
|
161
|
-
@tok_line = @line
|
162
|
-
|
163
|
-
[token, [value, location]]
|
164
|
-
end
|
165
|
-
|
166
197
|
def new_strterm(func, term, paren)
|
167
198
|
{ :type => :string, :func => func, :term => term, :paren => paren }
|
168
199
|
end
|
@@ -600,6 +631,7 @@ module Opal
|
|
600
631
|
return matched =~ /^[A-Z]/ ? :tCONSTANT : :tIDENTIFIER
|
601
632
|
end
|
602
633
|
|
634
|
+
# Does the heavy lifting for `next_token`.
|
603
635
|
def yylex
|
604
636
|
@yylval = ''
|
605
637
|
@space_seen = false
|
data/lib/opal/parser/sexp.rb
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
module Opal
|
2
|
+
# [Opal::Sexp] is used to build up the syntax tree inside [Opal::Parser]. The
|
3
|
+
# compiler then steps through the sexp trees to generate the javascript code.
|
4
|
+
#
|
5
|
+
# For example, an array of integers `[1, 2]` might be represented by:
|
6
|
+
#
|
7
|
+
# s(:array, s(:int, 1), s(:int, 2))
|
8
|
+
#
|
2
9
|
class Sexp
|
3
10
|
|
4
11
|
attr_reader :array
|
@@ -72,4 +79,3 @@ module Opal
|
|
72
79
|
alias to_s inspect
|
73
80
|
end
|
74
81
|
end
|
75
|
-
|
data/lib/opal/paths.rb
CHANGED
@@ -19,19 +19,19 @@ module Opal
|
|
19
19
|
paths << path
|
20
20
|
end
|
21
21
|
|
22
|
-
def self.use_gem(gem_name,
|
23
|
-
require_paths_for_gem(gem_name,
|
22
|
+
def self.use_gem(gem_name, include_dependencies = true)
|
23
|
+
require_paths_for_gem(gem_name, include_dependencies).each do |path|
|
24
24
|
append_path path
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.require_paths_for_gem(gem_name,
|
28
|
+
def self.require_paths_for_gem(gem_name, include_dependencies)
|
29
29
|
paths = []
|
30
30
|
spec = Gem::Specification.find_by_name(gem_name)
|
31
31
|
|
32
32
|
spec.runtime_dependencies.each do |dependency|
|
33
|
-
paths += require_paths_for_gem(dependency.name,
|
34
|
-
end if
|
33
|
+
paths += require_paths_for_gem(dependency.name, include_dependencies)
|
34
|
+
end if include_dependencies
|
35
35
|
|
36
36
|
gem_dir = spec.gem_dir
|
37
37
|
spec.require_paths.map do |path|
|
@@ -3,20 +3,12 @@ require 'opal/sprockets/processor'
|
|
3
3
|
require 'opal/sprockets/erb'
|
4
4
|
|
5
5
|
module Opal
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# Opal.process('opal-jquery') # => String
|
6
|
+
# @deprecated
|
9
7
|
def self.process asset
|
10
8
|
Environment.new[asset].to_s
|
11
9
|
end
|
12
10
|
|
13
|
-
#
|
14
|
-
# load paths loaded. This makes it easy for stand-alone rack apps, or test runners
|
15
|
-
# that have opal load paths ready to use. You can also add an existing gem's lib
|
16
|
-
# directory to our load path to use real gems inside your opal environment.
|
17
|
-
#
|
18
|
-
# If you are running rails, then you just need opal-rails instead, which will
|
19
|
-
# do this for you.
|
11
|
+
# @deprecated
|
20
12
|
class Environment < ::Sprockets::Environment
|
21
13
|
def initialize *args
|
22
14
|
warn "WARNING: Opal::Sprockets::Environment is deprecated. "\
|
@@ -36,6 +36,8 @@ module Opal
|
|
36
36
|
|
37
37
|
# "logical_name" of a BundledAsset keeps the .js extension
|
38
38
|
source = register[asset.logical_path.sub(/\.js$/, '')]
|
39
|
+
return not_found(asset) if source.nil?
|
40
|
+
|
39
41
|
map = JSON.parse(source)
|
40
42
|
map['sources'] = map['sources'].map {|s| "#{prefix}/#{s}"}
|
41
43
|
source = map.to_json
|
data/lib/opal/util.rb
CHANGED
@@ -2,13 +2,18 @@ module Opal
|
|
2
2
|
module Util
|
3
3
|
extend self
|
4
4
|
|
5
|
-
# Used for uglifying source to minify
|
5
|
+
# Used for uglifying source to minify.
|
6
|
+
#
|
7
|
+
# Opal::Util.uglify("javascript contents")
|
8
|
+
#
|
9
|
+
# @param str [String] string to minify
|
10
|
+
# @return [String]
|
6
11
|
def uglify(str)
|
7
12
|
uglifyjs = DigestSourceCommand.new(:uglifyjs, nil, ' (install with: "npm install -g uglify-js")')
|
8
13
|
uglifyjs.digest(str)
|
9
14
|
end
|
10
15
|
|
11
|
-
# Gzip code to check file size
|
16
|
+
# Gzip code to check file size.
|
12
17
|
def gzip(str)
|
13
18
|
gzip = DigestSourceCommand.new(:gzip, '-f', ', it is required to produce the .gz version')
|
14
19
|
gzip.digest(str)
|
data/lib/opal/version.rb
CHANGED
data/opal.gemspec
CHANGED
data/opal/README.md
CHANGED
data/opal/corelib/dir.rb
CHANGED
data/opal/corelib/enumerable.rb
CHANGED
data/opal/corelib/error.rb
CHANGED
@@ -48,6 +48,9 @@ class LoadError < ScriptError; end
|
|
48
48
|
class NotImplementedError < ScriptError; end
|
49
49
|
|
50
50
|
class SystemExit < Exception; end
|
51
|
+
class NoMemoryError < Exception; end
|
52
|
+
class SignalException < Exception; end
|
53
|
+
class Interrupt < Exception; end
|
51
54
|
|
52
55
|
class StandardError < Exception; end
|
53
56
|
class NameError < StandardError; end
|
data/opal/corelib/file.rb
CHANGED
data/opal/corelib/hash.rb
CHANGED
data/opal/corelib/io.rb
CHANGED
@@ -3,6 +3,14 @@ class IO
|
|
3
3
|
SEEK_CUR = 1
|
4
4
|
SEEK_END = 2
|
5
5
|
|
6
|
+
def tty?
|
7
|
+
@tty
|
8
|
+
end
|
9
|
+
|
10
|
+
def closed?
|
11
|
+
@closed
|
12
|
+
end
|
13
|
+
|
6
14
|
attr_accessor :write_proc
|
7
15
|
|
8
16
|
def write(string)
|
@@ -10,6 +18,8 @@ class IO
|
|
10
18
|
string.size
|
11
19
|
end
|
12
20
|
|
21
|
+
attr_accessor :sync
|
22
|
+
|
13
23
|
module Writable
|
14
24
|
def <<(string)
|
15
25
|
write(string)
|
@@ -23,7 +33,11 @@ class IO
|
|
23
33
|
|
24
34
|
def puts(*args)
|
25
35
|
newline = $/
|
26
|
-
|
36
|
+
if args.empty?
|
37
|
+
write $/
|
38
|
+
else
|
39
|
+
write args.map { |arg| String(arg).chomp }.concat([nil]).join(newline)
|
40
|
+
end
|
27
41
|
nil
|
28
42
|
end
|
29
43
|
end
|
data/opal/corelib/kernel.rb
CHANGED
@@ -71,6 +71,11 @@ module Kernel
|
|
71
71
|
}
|
72
72
|
end
|
73
73
|
|
74
|
+
def at_exit(&block)
|
75
|
+
$__at_exit__ ||= []
|
76
|
+
$__at_exit__ << block
|
77
|
+
end
|
78
|
+
|
74
79
|
# Opal does not support #caller, but we stub it as an empty array to not
|
75
80
|
# break dependant libs
|
76
81
|
def caller
|
@@ -405,6 +410,7 @@ module Kernel
|
|
405
410
|
end
|
406
411
|
|
407
412
|
def load(file)
|
413
|
+
file = Opal.coerce_to!(file, String, :to_str)
|
408
414
|
`Opal.load(Opal.normalize_loadable_path(#{file}))`
|
409
415
|
end
|
410
416
|
|
@@ -521,10 +527,12 @@ module Kernel
|
|
521
527
|
end
|
522
528
|
|
523
529
|
def require(file)
|
530
|
+
file = Opal.coerce_to!(file, String, :to_str)
|
524
531
|
`Opal.require(Opal.normalize_loadable_path(#{file}))`
|
525
532
|
end
|
526
533
|
|
527
534
|
def require_relative(file)
|
535
|
+
Opal.try_convert!(file, String, :to_str)
|
528
536
|
file = File.expand_path File.join(`Opal.current_file`, '..', file)
|
529
537
|
|
530
538
|
`Opal.require(Opal.normalize_loadable_path(#{file}))`
|