opal 0.3.10 → 0.3.11
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.
- data/README.md +47 -46
- data/lib/opal.rb +11 -3
- data/lib/opal/builder.rb +4 -46
- data/lib/opal/bundle.rb +11 -25
- data/lib/opal/command.rb +101 -22
- data/lib/opal/context.rb +16 -50
- data/lib/opal/lexer.rb +21 -2
- data/lib/opal/nodes.rb +134 -20
- data/lib/opal/parser.rb +7 -7
- data/lib/opal/parser.y +7 -7
- data/lib/opal/rake/bundle_task.rb +24 -23
- data/lib/opal/version.rb +3 -0
- data/opal-parser.js +8343 -0
- data/opal.js +5685 -0
- data/stdlib/dev.rb +6 -4
- data/templates/init/Rakefile +7 -0
- data/templates/init/index.html +17 -0
- data/templates/init/lib/__NAME__.rb +2 -0
- metadata +9 -32
- data/corelib/array.rb +0 -1424
- data/corelib/boolean.rb +0 -20
- data/corelib/class.rb +0 -58
- data/corelib/core.rb +0 -66
- data/corelib/dir.rb +0 -22
- data/corelib/enumerable.rb +0 -33
- data/corelib/error.rb +0 -19
- data/corelib/file.rb +0 -60
- data/corelib/hash.rb +0 -729
- data/corelib/kernel.rb +0 -251
- data/corelib/load_order +0 -21
- data/corelib/match_data.rb +0 -33
- data/corelib/module.rb +0 -101
- data/corelib/nil_class.rb +0 -54
- data/corelib/numeric.rb +0 -352
- data/corelib/object.rb +0 -37
- data/corelib/proc.rb +0 -55
- data/corelib/range.rb +0 -27
- data/corelib/regexp.rb +0 -69
- data/corelib/string.rb +0 -300
- data/corelib/top_self.rb +0 -8
- data/runtime/class.js +0 -386
- data/runtime/fs.js +0 -199
- data/runtime/init.js +0 -556
- data/runtime/loader.js +0 -330
- data/runtime/module.js +0 -103
- data/runtime/post.js +0 -10
- data/runtime/pre.js +0 -7
- data/runtime/runtime.js +0 -345
data/lib/opal/context.rb
CHANGED
@@ -1,38 +1,15 @@
|
|
1
1
|
module Opal
|
2
2
|
class Context
|
3
|
-
|
4
|
-
def initialize(
|
5
|
-
@
|
6
|
-
@
|
3
|
+
# Options are mainly just passed onto the builder/parser.
|
4
|
+
def initialize(options = {})
|
5
|
+
@options = options
|
6
|
+
@root_dir = options[:dir] || Dir.getwd
|
7
|
+
@builder = Opal::Builder.new
|
7
8
|
@loaded_paths = false
|
8
9
|
|
9
|
-
# special case: if we are running in opal root, then we dont want
|
10
|
-
# setup.rb to load the opal lib itself, so we do some "magic"
|
11
|
-
if @root_dir == OPAL_DIR
|
12
|
-
def self.setup_load_paths
|
13
|
-
return if @loaded_paths
|
14
|
-
Dir['packages/*/package.yml'].map do |package|
|
15
|
-
path = File.expand_path File.join(File.dirname(package), 'lib')
|
16
|
-
@v8.eval "opal.loader.paths.push('#{path}')"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
10
|
setup_v8
|
22
11
|
end
|
23
12
|
|
24
|
-
##
|
25
|
-
# Looks through vendor/ directory and adds all relevant load paths
|
26
|
-
|
27
|
-
def setup_load_paths
|
28
|
-
return if @loaded_paths
|
29
|
-
|
30
|
-
setup = File.join @root_dir, 'packages', 'init.rb'
|
31
|
-
return [] unless File.exists? setup
|
32
|
-
|
33
|
-
@v8.eval "opal.run(function() {opal.require('#{setup}');});", setup
|
34
|
-
end
|
35
|
-
|
36
13
|
##
|
37
14
|
# Require the given id as if it was required in the context. This simply
|
38
15
|
# passes the require through to the underlying context.
|
@@ -43,17 +20,14 @@ module Opal
|
|
43
20
|
finish
|
44
21
|
end
|
45
22
|
|
46
|
-
|
47
|
-
#
|
48
|
-
|
23
|
+
# Set ARGV for the context.
|
24
|
+
# @param [Array<String>] args
|
49
25
|
def argv=(args)
|
50
26
|
puts "setting argv to #{args.inspect}"
|
51
27
|
@v8.eval "opal.runtime.cs(opal.runtime.Object, 'ARGV', #{args.inspect});"
|
52
28
|
end
|
53
29
|
|
54
|
-
##
|
55
30
|
# Start normal js repl
|
56
|
-
|
57
31
|
def start_repl
|
58
32
|
require 'readline'
|
59
33
|
setup_v8
|
@@ -74,26 +48,20 @@ module Opal
|
|
74
48
|
finish
|
75
49
|
end
|
76
50
|
|
77
|
-
def eval(content, file =
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
rescue => e
|
86
|
-
puts e
|
87
|
-
puts("\t" + e.backtrace.join("\n\t"))
|
88
|
-
end
|
51
|
+
def eval(content, file = "(opal)", line = "")
|
52
|
+
js = @builder.parse content, @options
|
53
|
+
code = "opal.run(function() { var result = (#{js})(opal.runtime, "
|
54
|
+
code += "opal.runtime.top, '(opal)'); if (result == null || !result"
|
55
|
+
code += ".m$inspect) { return '(Object does not support #inspect)'; }"
|
56
|
+
code += "else { return result.m$inspect() } });"
|
57
|
+
|
58
|
+
@v8.eval code, file
|
89
59
|
end
|
90
60
|
|
91
|
-
##
|
92
61
|
# Finishes the context, i.e. tidy everything up. This will cause
|
93
62
|
# the opal runtime to do it's at_exit() calls (if applicable) and
|
94
63
|
# then the v8 context will de removed. It can be reset by calling
|
95
64
|
# #setup_v8
|
96
|
-
|
97
65
|
def finish
|
98
66
|
return unless @v8
|
99
67
|
@v8.eval "opal.runtime.do_at_exit()", "(opal)"
|
@@ -116,14 +84,12 @@ module Opal
|
|
116
84
|
@v8 = V8::Context.new
|
117
85
|
@v8['console'] = Console.new
|
118
86
|
|
119
|
-
@v8.eval
|
87
|
+
@v8.eval File.read(OPAL_JS_PATH), "(opal)"
|
120
88
|
opal = @v8['opal']
|
121
89
|
opal['fs'] = FileSystem.new self
|
122
90
|
|
123
91
|
# FIXME: we cant use a ruby array as a js array :(
|
124
92
|
opal['loader'] = Loader.new self, @v8.eval("[]")
|
125
|
-
|
126
|
-
setup_load_paths
|
127
93
|
end
|
128
94
|
|
129
95
|
##
|
data/lib/opal/lexer.rb
CHANGED
@@ -12,7 +12,7 @@ module Opal
|
|
12
12
|
# parser = Opal::Parser.new
|
13
13
|
#
|
14
14
|
# parser.parse "self.do_something 1, 2, 3"
|
15
|
-
# # => "
|
15
|
+
# # => "compiled javascript"
|
16
16
|
class Parser < Racc::Parser
|
17
17
|
|
18
18
|
# Thrown on parsing error
|
@@ -34,6 +34,25 @@ module Opal
|
|
34
34
|
# in future bindings. `false` means its just a normal scope,
|
35
35
|
# i.e. top. This is only needed in [Context] for irb.
|
36
36
|
#
|
37
|
+
# `:overload_arithmetic` - whether to overload arithmetic operators
|
38
|
+
# or not. This defaults to `false` so that all method calls for
|
39
|
+
# `+`, `-`, `*`, `/`, `%`, `-@`, `-@` are just compiled directly
|
40
|
+
# into their javascript ops. Set to `true` to use ruby style
|
41
|
+
# operator overloading.
|
42
|
+
#
|
43
|
+
# `:overload_bitwise` - whether to overload bitwise operators. This
|
44
|
+
# applies to `&`, `|`, `^` and `~`. Defaults to `false`.
|
45
|
+
#
|
46
|
+
# `:overload_shift` - whether to overload shift bitwise operators.
|
47
|
+
# This applies to `<<` and `>>`. `<<` is generally useful for
|
48
|
+
# arrays so we keep it seperate. Defaults to `true`.
|
49
|
+
#
|
50
|
+
# `:overload_equal` - whether to overload `==` and `!==` operators.
|
51
|
+
# This defaults to `false`.
|
52
|
+
#
|
53
|
+
# `:overload_comparison` - whether to overload `<`, `<=`, `>` and
|
54
|
+
# `>=` operators. Defaults to `false`.
|
55
|
+
#
|
37
56
|
# @param [String] source ruby source code to parse
|
38
57
|
# @param [Hash] options parsing options to use
|
39
58
|
def parse(source, options = {})
|
@@ -45,7 +64,7 @@ module Opal
|
|
45
64
|
@scanner = StringScanner.new source
|
46
65
|
nodes = do_parse
|
47
66
|
|
48
|
-
return nodes.generate_top
|
67
|
+
return nodes.generate_top(options)
|
49
68
|
end
|
50
69
|
|
51
70
|
def next_token
|
data/lib/opal/nodes.rb
CHANGED
@@ -80,7 +80,7 @@ module Opal
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def generate_truthy_test(expr, opts)
|
83
|
-
if expr.is_a? ComparisonNode
|
83
|
+
if expr.is_a?(EqualNode) || expr.is_a?(ComparisonNode)
|
84
84
|
expr.generate opts, LEVEL_EXPR
|
85
85
|
else
|
86
86
|
tmp = opts[:scope].temp_local
|
@@ -218,6 +218,28 @@ module Opal
|
|
218
218
|
@line = 1
|
219
219
|
end
|
220
220
|
|
221
|
+
# [Parser] options
|
222
|
+
def options=(opts)
|
223
|
+
@overload_arithmetic = opts[:overload_arithmetic] || false
|
224
|
+
@overload_comparison = opts[:overload_comparison] || false
|
225
|
+
@overload_bitwise = opts[:overload_bitwise] || false
|
226
|
+
@overload_shift = opts[:overload_shift] || true
|
227
|
+
@overload_equal = opts[:overload_equal] || false
|
228
|
+
@method_missing = opts[:method_missing] || false
|
229
|
+
end
|
230
|
+
|
231
|
+
def overload_arithmetic?; @overload_arithmetic; end
|
232
|
+
|
233
|
+
def overload_comparison?; @overload_comparison; end
|
234
|
+
|
235
|
+
def overload_bitwise?; @overload_bitwise; end
|
236
|
+
|
237
|
+
def overload_shift?; @overload_shift; end
|
238
|
+
|
239
|
+
def overload_equal?; @overload_equal; end
|
240
|
+
|
241
|
+
def method_missing?; @method_missing; end
|
242
|
+
|
221
243
|
def generate(opts, level)
|
222
244
|
@opts = opts
|
223
245
|
code = []
|
@@ -235,7 +257,7 @@ module Opal
|
|
235
257
|
|
236
258
|
post += 'var nil = $rb.Qnil, $super = $rb.S, $break = $rb.B, '
|
237
259
|
post += '$class = $rb.dc, $defn = $rb.dm, $defs = $rb.ds, $cg = $rb.cg, '
|
238
|
-
post += '$range = $rb.G, $hash = $rb.H, $B = $rb.P'
|
260
|
+
post += '$range = $rb.G, $hash = $rb.H, $B = $rb.P, $rb_send = $rb.sm'
|
239
261
|
|
240
262
|
post += ';'
|
241
263
|
|
@@ -315,12 +337,17 @@ module Opal
|
|
315
337
|
end
|
316
338
|
|
317
339
|
# Generate statements for top level. Generally used for files
|
318
|
-
def generate_top(
|
340
|
+
def generate_top(parser_options = {})
|
319
341
|
scope = TopScopeNode.new self
|
320
|
-
opts
|
321
|
-
|
322
|
-
|
323
|
-
|
342
|
+
opts = {}
|
343
|
+
|
344
|
+
scope.options = parser_options
|
345
|
+
|
346
|
+
opts[:scope] = scope
|
347
|
+
opts[:indent] = ''
|
348
|
+
opts[:top] = scope
|
349
|
+
|
350
|
+
return scope.generate opts, LEVEL_TOP
|
324
351
|
end
|
325
352
|
end
|
326
353
|
|
@@ -398,9 +425,16 @@ module Opal
|
|
398
425
|
recv = "self"
|
399
426
|
end
|
400
427
|
|
401
|
-
|
428
|
+
# dispatch is true if we use the dispatch method (i.e. we want
|
429
|
+
# to support method missing).
|
430
|
+
dispatch = opts[:top].method_missing?
|
431
|
+
|
432
|
+
unless dispatch
|
433
|
+
mid = mid_to_jsid mid
|
434
|
+
end
|
402
435
|
|
403
436
|
args = @args
|
437
|
+
|
404
438
|
# normal args
|
405
439
|
if args[0]
|
406
440
|
args[0].each do |arg|
|
@@ -443,19 +477,34 @@ module Opal
|
|
443
477
|
else
|
444
478
|
# splat args
|
445
479
|
if args[1]
|
446
|
-
tmp_recv = opts[:scope].temp_local
|
447
480
|
splat = args[1].generate(opts, LEVEL_EXPR)
|
448
|
-
splat_args = arg_res.empty? ? "#{splat}" : "[#{arg_res.join ', '}].concat(#{splat})"
|
449
|
-
# when using splat, our this val for apply may need a tmp var
|
450
|
-
# to save just outputting it twice (have to follow recv path twice)
|
451
|
-
splat_recv = recv
|
452
|
-
result = "(#{tmp_recv} = #{recv})" + mid + ".apply(#{tmp_recv}, #{splat_args})"
|
453
481
|
|
482
|
+
if dispatch
|
483
|
+
arg_res.unshift recv, "'#{mid}'"
|
484
|
+
splat_args = "[#{arg_res.join ', '}].concat(#{splat})"
|
485
|
+
|
486
|
+
return "$rb_send.apply(null, #{splat_args})"
|
487
|
+
end
|
488
|
+
|
489
|
+
# non-disptach
|
490
|
+
tmp_recv = opts[:scope].temp_local
|
491
|
+
splat_args = arg_res.empty? ? "#{splat}" :
|
492
|
+
"[#{arg_res.join ', '}].concat(#{splat})"
|
493
|
+
|
494
|
+
result = "(#{tmp_recv} = #{recv})" + mid + ".apply("
|
495
|
+
result += "#{tmp_recv}, #{splat_args})"
|
454
496
|
opts[:scope].queue_temp tmp_recv
|
455
|
-
|
497
|
+
|
498
|
+
return result
|
499
|
+
|
500
|
+
# not a block call, and not a &to_proc call
|
456
501
|
else
|
457
|
-
|
458
|
-
|
502
|
+
if dispatch
|
503
|
+
arg_res.unshift recv, "'#{mid}'"
|
504
|
+
"$rb_send(#{arg_res.join ', '})"
|
505
|
+
else
|
506
|
+
"#{recv}#{mid}(#{arg_res.join(', ')})"
|
507
|
+
end
|
459
508
|
end
|
460
509
|
end
|
461
510
|
end
|
@@ -1265,6 +1314,59 @@ module Opal
|
|
1265
1314
|
end
|
1266
1315
|
end
|
1267
1316
|
|
1317
|
+
class ArithmeticNode < BaseNode
|
1318
|
+
def initialize(lhs, op, rhs)
|
1319
|
+
@lhs = lhs
|
1320
|
+
@op = op[:value]
|
1321
|
+
@line = op[:line]
|
1322
|
+
@rhs = rhs
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
def generate(opts, level)
|
1326
|
+
lhs = @lhs.generate opts, LEVEL_EXPR
|
1327
|
+
rhs = @rhs.generate opts, LEVEL_EXPR
|
1328
|
+
|
1329
|
+
if opts[:top].overload_arithmetic?
|
1330
|
+
if opts[:top].method_missing?
|
1331
|
+
return "$rb_send(#{lhs}, 'm$#{@op}', #{rhs})"
|
1332
|
+
else
|
1333
|
+
lhs = "(#{lhs})" if @lhs.is_a? NumericNode
|
1334
|
+
return "#{lhs}['m$#{@op}'](#{rhs})"
|
1335
|
+
end
|
1336
|
+
else
|
1337
|
+
return "#{lhs} #{@op} #{rhs}"
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
class EqualNode < BaseNode
|
1343
|
+
def initialize(lhs, op, rhs)
|
1344
|
+
@line = op[:line]
|
1345
|
+
@op = op[:value]
|
1346
|
+
@lhs = lhs
|
1347
|
+
@rhs = rhs
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
def generate(opts, level)
|
1351
|
+
lhs = @lhs.generate opts, LEVEL_EXPR
|
1352
|
+
rhs = @rhs.generate opts, LEVEL_EXPR
|
1353
|
+
|
1354
|
+
if opts[:top].overload_equal?
|
1355
|
+
if opts[:top].method_missing?
|
1356
|
+
return "$rb_send(#{lhs}, 'm$#{@op}', #{rhs})"
|
1357
|
+
else
|
1358
|
+
lhs = "(#{lhs})" if @lhs.is_a? NumericNode
|
1359
|
+
return "#{lhs}['m$#{@op}'](#{rhs})"
|
1360
|
+
end
|
1361
|
+
else
|
1362
|
+
op = "#{@op}="
|
1363
|
+
lhs = "(#{lhs})" if @lhs.is_a? NumericNode
|
1364
|
+
rhs = "(#{rhs})" if @rhs.is_a? NumericNode
|
1365
|
+
return "#{lhs}.valueOf() #{op} #{rhs}.valueOf()"
|
1366
|
+
end
|
1367
|
+
end
|
1368
|
+
end
|
1369
|
+
|
1268
1370
|
class ComparisonNode < BaseNode
|
1269
1371
|
|
1270
1372
|
def initialize(op, lhs, rhs)
|
@@ -1279,10 +1381,22 @@ module Opal
|
|
1279
1381
|
lhs = "(#{lhs})" if @lhs.is_a? NumericNode
|
1280
1382
|
rhs = @rhs.generate opts, LEVEL_EXPR
|
1281
1383
|
|
1282
|
-
if
|
1283
|
-
|
1384
|
+
if opts[:top].overload_equal?
|
1385
|
+
if @op == '!='
|
1386
|
+
"!#{lhs}['m$=='](#{rhs})"
|
1387
|
+
else
|
1388
|
+
"#{lhs}['m$#{@op}'](#{rhs})"
|
1389
|
+
end
|
1284
1390
|
else
|
1285
|
-
|
1391
|
+
if @op == '!='
|
1392
|
+
rhs = "(#{rhs})" if @rhs.is_a? NumericNode
|
1393
|
+
"#{lhs}.valueOf() !== #{rhs}.valueOf()"
|
1394
|
+
elsif @op == '=='
|
1395
|
+
rhs = "(#{rhs})" if @rhs.is_a? NumericNode
|
1396
|
+
"#{lhs}.valueOf() === #{rhs}.valueOf()"
|
1397
|
+
else
|
1398
|
+
"#{lhs} #{@op} #{rhs}"
|
1399
|
+
end
|
1286
1400
|
end
|
1287
1401
|
end
|
1288
1402
|
end
|
data/lib/opal/parser.rb
CHANGED
@@ -3451,31 +3451,31 @@ def _reduce_178(val, _values, result)
|
|
3451
3451
|
end
|
3452
3452
|
|
3453
3453
|
def _reduce_179(val, _values, result)
|
3454
|
-
result =
|
3454
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
3455
3455
|
|
3456
3456
|
result
|
3457
3457
|
end
|
3458
3458
|
|
3459
3459
|
def _reduce_180(val, _values, result)
|
3460
|
-
result =
|
3460
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
3461
3461
|
|
3462
3462
|
result
|
3463
3463
|
end
|
3464
3464
|
|
3465
3465
|
def _reduce_181(val, _values, result)
|
3466
|
-
result =
|
3466
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
3467
3467
|
|
3468
3468
|
result
|
3469
3469
|
end
|
3470
3470
|
|
3471
3471
|
def _reduce_182(val, _values, result)
|
3472
|
-
result =
|
3472
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
3473
3473
|
|
3474
3474
|
result
|
3475
3475
|
end
|
3476
3476
|
|
3477
3477
|
def _reduce_183(val, _values, result)
|
3478
|
-
result =
|
3478
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
3479
3479
|
|
3480
3480
|
result
|
3481
3481
|
end
|
@@ -3547,7 +3547,7 @@ def _reduce_194(val, _values, result)
|
|
3547
3547
|
end
|
3548
3548
|
|
3549
3549
|
def _reduce_195(val, _values, result)
|
3550
|
-
result =
|
3550
|
+
result = EqualNode.new val[0], val[1], val[2]
|
3551
3551
|
|
3552
3552
|
result
|
3553
3553
|
end
|
@@ -3559,7 +3559,7 @@ def _reduce_196(val, _values, result)
|
|
3559
3559
|
end
|
3560
3560
|
|
3561
3561
|
def _reduce_197(val, _values, result)
|
3562
|
-
result =
|
3562
|
+
result = EqualNode.new val[0], val[1], val[2]
|
3563
3563
|
|
3564
3564
|
result
|
3565
3565
|
end
|
data/lib/opal/parser.y
CHANGED
@@ -377,23 +377,23 @@ arg:
|
|
377
377
|
}
|
378
378
|
| arg '+' arg
|
379
379
|
{
|
380
|
-
result =
|
380
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
381
381
|
}
|
382
382
|
| arg '-' arg
|
383
383
|
{
|
384
|
-
result =
|
384
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
385
385
|
}
|
386
386
|
| arg '*' arg
|
387
387
|
{
|
388
|
-
result =
|
388
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
389
389
|
}
|
390
390
|
| arg '/' arg
|
391
391
|
{
|
392
|
-
result =
|
392
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
393
393
|
}
|
394
394
|
| arg '%' arg
|
395
395
|
{
|
396
|
-
result =
|
396
|
+
result = ArithmeticNode.new val[0], val[1], val[2]
|
397
397
|
}
|
398
398
|
| arg '**' arg
|
399
399
|
{
|
@@ -441,7 +441,7 @@ arg:
|
|
441
441
|
}
|
442
442
|
| arg '==' arg
|
443
443
|
{
|
444
|
-
result =
|
444
|
+
result = EqualNode.new val[0], val[1], val[2]
|
445
445
|
}
|
446
446
|
| arg '===' arg
|
447
447
|
{
|
@@ -449,7 +449,7 @@ arg:
|
|
449
449
|
}
|
450
450
|
| arg '!=' arg
|
451
451
|
{
|
452
|
-
result =
|
452
|
+
result = EqualNode.new val[0], val[1], val[2]
|
453
453
|
}
|
454
454
|
| arg '=~' arg
|
455
455
|
{
|