opal 0.5.2 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/lib/opal.rb +0 -5
- data/lib/opal/compiler.rb +24 -44
- data/lib/opal/nodes/base.rb +5 -8
- data/lib/opal/nodes/call.rb +4 -0
- data/lib/opal/nodes/class.rb +6 -7
- data/lib/opal/nodes/def.rb +4 -4
- data/lib/opal/nodes/definitions.rb +0 -14
- data/lib/opal/nodes/iter.rb +51 -38
- data/lib/opal/nodes/literal.rb +21 -24
- data/lib/opal/nodes/module.rb +4 -4
- data/lib/opal/nodes/runtime_helpers.rb +45 -0
- data/lib/opal/nodes/scope.rb +280 -0
- data/lib/opal/nodes/singleton_class.rb +4 -5
- data/lib/opal/nodes/super.rb +1 -1
- data/lib/opal/nodes/top.rb +9 -7
- data/lib/opal/nodes/yield.rb +14 -3
- data/lib/opal/parser.rb +4 -18
- data/lib/opal/parser/grammar.rb +3745 -3667
- data/lib/opal/parser/grammar.y +1692 -1778
- data/lib/opal/parser/keywords.rb +35 -35
- data/lib/opal/parser/lexer.rb +356 -325
- data/lib/opal/parser/sexp.rb +1 -1
- data/lib/opal/version.rb +1 -1
- data/opal.gemspec +1 -0
- data/opal/core/array.rb +320 -81
- data/opal/core/enumerable.rb +46 -5
- data/opal/core/hash.rb +6 -64
- data/opal/core/helpers.rb +67 -0
- data/opal/core/method.rb +1 -1
- data/opal/core/module.rb +4 -4
- data/opal/core/range.rb +1 -12
- data/opal/core/regexp.rb +2 -8
- data/opal/core/runtime.js +74 -3
- data/opal/core/string.rb +99 -74
- data/opal/opal.rb +3 -72
- data/spec/filters/bugs/array.rb +2 -30
- data/spec/filters/bugs/basic_object.rb +0 -1
- data/spec/filters/bugs/string.rb +26 -21
- data/spec/filters/unsupported/enumerator.rb +3 -0
- data/spec/filters/unsupported/float.rb +1 -0
- data/spec/filters/unsupported/immutable_strings.rb +15 -0
- data/spec/filters/unsupported/tainted.rb +58 -30
- data/spec/filters/unsupported/trusted.rb +35 -15
- data/spec/opal/parser/class_spec.rb +4 -4
- data/spec/opal/parser/def_spec.rb +4 -4
- data/spec/opal/parser/lvar_spec.rb +6 -6
- data/spec/opal/parser/module_spec.rb +4 -4
- data/spec/opal/parser/sclass_spec.rb +2 -2
- data/spec/stdlib/native/exposure_spec.rb +33 -0
- data/stdlib/buffer.rb +1 -1
- data/stdlib/buffer/view.rb +1 -1
- data/stdlib/native.rb +193 -174
- data/stdlib/opal-parser.rb +0 -6
- data/stdlib/pp.rb +9 -0
- data/tasks/mspec.rake +3 -1
- metadata +9 -9
- data/lib/opal/nodes/base_scope.rb +0 -11
- data/lib/opal/target_scope.rb +0 -281
- data/spec/filters/20.rb +0 -4
- data/spec/filters/unsupported/array_subclasses.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77632aecb99342d5830be4046997f6f1c4b57c5a
|
4
|
+
data.tar.gz: d0b98b8c4bb8a0cd0e047e45507c4edabdf5a504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 767a17fdba3738a6dadf6d3d567a5b695ec69bf540d70278af7b0ce1c8a8a529e4c90d1a2f1518486637857dfe8decc1c41ced22d7d99271c4a2b7f727be6db3
|
7
|
+
data.tar.gz: 1b17efbff47540101001edb95dc5190bcbf39218a47f4f8f983a4698c3dec4958e1149ba6ddb3e781b2131071dd8f42a04f0b41768ba7ff067c4079ef8c1b315
|
data/README.md
CHANGED
data/lib/opal.rb
CHANGED
@@ -6,11 +6,6 @@ require 'opal/version'
|
|
6
6
|
# Opal is a ruby to javascript compiler, with a runtime for running
|
7
7
|
# in any javascript environment.
|
8
8
|
module Opal
|
9
|
-
|
10
|
-
def self.compile(source, options = {})
|
11
|
-
Compiler.new.compile(source, options)
|
12
|
-
end
|
13
|
-
|
14
9
|
def self.gem_dir
|
15
10
|
File.expand_path('..', __FILE__.untaint)
|
16
11
|
end
|
data/lib/opal/compiler.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'opal/parser'
|
3
|
-
require 'opal/target_scope'
|
4
|
-
require 'opal/version'
|
5
3
|
require 'opal/fragment'
|
6
4
|
require 'opal/nodes'
|
7
5
|
|
8
6
|
module Opal
|
7
|
+
def self.compile(source, options = {})
|
8
|
+
Compiler.new.compile(source, options)
|
9
|
+
end
|
10
|
+
|
9
11
|
class Compiler
|
10
12
|
# Generated code gets indented with two spaces on each scope
|
11
13
|
INDENT = ' '
|
@@ -15,10 +17,8 @@ module Opal
|
|
15
17
|
COMPARE = %w[< > <= >=]
|
16
18
|
|
17
19
|
# defines a compiler option, also creating method of form 'name?'
|
18
|
-
def self.compiler_option(name, default_value)
|
19
|
-
mid
|
20
|
-
|
21
|
-
define_method(mid) do
|
20
|
+
def self.compiler_option(name, default_value, mid = nil)
|
21
|
+
define_method(mid || name) do
|
22
22
|
@options.fetch(name) { default_value }
|
23
23
|
end
|
24
24
|
end
|
@@ -27,16 +27,16 @@ module Opal
|
|
27
27
|
compiler_option :file, '(file)'
|
28
28
|
|
29
29
|
# adds method stubs for all used methods in file
|
30
|
-
compiler_option :method_missing, true
|
30
|
+
compiler_option :method_missing, true, :method_missing?
|
31
31
|
|
32
32
|
# adds an arity check to every method definition
|
33
|
-
compiler_option :arity_check, false
|
33
|
+
compiler_option :arity_check, false, :arity_check?
|
34
34
|
|
35
35
|
# checks every constant access, delagating to const_missing if needed
|
36
|
-
compiler_option :const_missing, false
|
36
|
+
compiler_option :const_missing, false, :const_missing?
|
37
37
|
|
38
38
|
# compile top level local vars with support for irb style vars
|
39
|
-
compiler_option :irb, false
|
39
|
+
compiler_option :irb, false, :irb?
|
40
40
|
|
41
41
|
# how to handle dynamic requires (:error, :warning, :ignore)
|
42
42
|
compiler_option :dynamic_require_severity, :error
|
@@ -44,13 +44,7 @@ module Opal
|
|
44
44
|
attr_reader :result, :fragments
|
45
45
|
|
46
46
|
# Current scope
|
47
|
-
|
48
|
-
|
49
|
-
# Any helpers required by this file
|
50
|
-
attr_reader :helpers
|
51
|
-
|
52
|
-
# Method calls made in this file
|
53
|
-
attr_reader :method_calls
|
47
|
+
attr_accessor :scope
|
54
48
|
|
55
49
|
# Current case_stmt
|
56
50
|
attr_reader :case_stmt
|
@@ -60,9 +54,6 @@ module Opal
|
|
60
54
|
@indent = ''
|
61
55
|
@unique = 0
|
62
56
|
@options = {}
|
63
|
-
|
64
|
-
@method_calls = Set.new
|
65
|
-
@helpers = Set.new([:breaker, :slice])
|
66
57
|
end
|
67
58
|
|
68
59
|
# Compile some ruby code to a string.
|
@@ -70,10 +61,9 @@ module Opal
|
|
70
61
|
@source = source
|
71
62
|
@options.update options
|
72
63
|
|
73
|
-
@sexp = Parser.new.parse(@source, self.file)
|
64
|
+
@sexp = s(:top, Parser.new.parse(@source, self.file) || s(:nil))
|
74
65
|
|
75
|
-
|
76
|
-
@fragments = top_node.compile_to_fragments.flatten
|
66
|
+
@fragments = process(@sexp).flatten
|
77
67
|
|
78
68
|
@result = @fragments.map(&:code).join('')
|
79
69
|
end
|
@@ -82,6 +72,16 @@ module Opal
|
|
82
72
|
Opal::SourceMap.new(@fragments, source_file || self.file)
|
83
73
|
end
|
84
74
|
|
75
|
+
# Any helpers required by this file
|
76
|
+
def helpers
|
77
|
+
@helpers ||= Set.new([:breaker, :slice])
|
78
|
+
end
|
79
|
+
|
80
|
+
# Method calls made in this file
|
81
|
+
def method_calls
|
82
|
+
@method_calls ||= Set.new
|
83
|
+
end
|
84
|
+
|
85
85
|
# This is called when a parsing/processing error occurs. This
|
86
86
|
# method simply appends the filename and curent line number onto
|
87
87
|
# the message and raises it.
|
@@ -124,27 +124,7 @@ module Opal
|
|
124
124
|
|
125
125
|
# Use the given helper
|
126
126
|
def helper(name)
|
127
|
-
|
128
|
-
end
|
129
|
-
|
130
|
-
# Every time the parser enters a new scope, this is called with
|
131
|
-
# the scope type as an argument. Valid types are `:top` for the
|
132
|
-
# top level/file scope; `:class`, `:module` and `:sclass` for the
|
133
|
-
# obvious ruby classes/modules; `:def` and `:iter` for methods
|
134
|
-
# and blocks respectively.
|
135
|
-
#
|
136
|
-
# This method just pushes a new instance of `Opal::Scope` onto the
|
137
|
-
# stack, sets the new scope as the `@scope` variable, and yields
|
138
|
-
# the given block. Once the block returns, the old scope is put
|
139
|
-
# back on top of the stack.
|
140
|
-
def in_scope(type)
|
141
|
-
return unless block_given?
|
142
|
-
|
143
|
-
parent = @scope
|
144
|
-
@scope = TargetScope.new(type, self).tap { |s| s.parent = parent }
|
145
|
-
yield @scope
|
146
|
-
|
147
|
-
@scope = parent
|
127
|
+
self.helpers << name
|
148
128
|
end
|
149
129
|
|
150
130
|
# To keep code blocks nicely indented, this will yield a block after
|
data/lib/opal/nodes/base.rb
CHANGED
@@ -23,18 +23,15 @@ module Opal
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
attr_reader :compiler
|
26
|
+
attr_reader :compiler, :type
|
27
27
|
|
28
28
|
def initialize(sexp, level, compiler)
|
29
29
|
@sexp = sexp
|
30
|
+
@type = sexp.type
|
30
31
|
@level = level
|
31
32
|
@compiler = compiler
|
32
33
|
end
|
33
34
|
|
34
|
-
def type
|
35
|
-
@sexp.type
|
36
|
-
end
|
37
|
-
|
38
35
|
def children
|
39
36
|
@sexp[1..-1]
|
40
37
|
end
|
@@ -119,15 +116,15 @@ module Opal
|
|
119
116
|
end
|
120
117
|
|
121
118
|
def add_local(name)
|
122
|
-
scope.
|
119
|
+
scope.add_scope_local name.to_sym
|
123
120
|
end
|
124
121
|
|
125
122
|
def add_ivar(name)
|
126
|
-
scope.
|
123
|
+
scope.add_scope_ivar name
|
127
124
|
end
|
128
125
|
|
129
126
|
def add_temp(temp)
|
130
|
-
scope.
|
127
|
+
scope.add_scope_temp temp
|
131
128
|
end
|
132
129
|
|
133
130
|
def helper(name)
|
data/lib/opal/nodes/call.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'opal/nodes/base'
|
3
|
+
require 'opal/nodes/runtime_helpers'
|
3
4
|
|
4
5
|
module Opal
|
5
6
|
module Nodes
|
@@ -99,6 +100,9 @@ module Opal
|
|
99
100
|
push result
|
100
101
|
return true
|
101
102
|
end
|
103
|
+
elsif RuntimeHelpers.compatible?(recvr, meth, arglist)
|
104
|
+
push(RuntimeHelpers.new(@sexp, @level, @compiler).compile)
|
105
|
+
return true
|
102
106
|
end
|
103
107
|
end
|
104
108
|
|
data/lib/opal/nodes/class.rb
CHANGED
@@ -12,13 +12,13 @@ module Opal
|
|
12
12
|
helper :klass
|
13
13
|
|
14
14
|
push "(function($base, $super) {"
|
15
|
-
line " function
|
16
|
-
line " var self =
|
15
|
+
line " function $#{name}(){};"
|
16
|
+
line " var self = $#{name} = $klass($base, $super, '#{name}', $#{name});"
|
17
17
|
|
18
|
-
in_scope
|
18
|
+
in_scope do
|
19
19
|
scope.name = name
|
20
|
-
add_temp "#{scope.proto} =
|
21
|
-
add_temp "$scope =
|
20
|
+
add_temp "#{scope.proto} = $#{name}._proto"
|
21
|
+
add_temp "$scope = $#{name}._scope"
|
22
22
|
|
23
23
|
body_code = self.body_code
|
24
24
|
empty_line
|
@@ -35,8 +35,7 @@ module Opal
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def body_code
|
38
|
-
body
|
39
|
-
stmt(compiler.returns(body))
|
38
|
+
stmt(compiler.returns(body || s(:nil)))
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
data/lib/opal/nodes/def.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'opal/nodes/
|
1
|
+
require 'opal/nodes/scope'
|
2
2
|
|
3
3
|
module Opal
|
4
4
|
module Nodes
|
5
5
|
# FIXME: needs rewrite
|
6
|
-
class DefNode <
|
6
|
+
class DefNode < ScopeNode
|
7
7
|
handle :def
|
8
8
|
|
9
9
|
children :recvr, :mid, :args, :stmts
|
@@ -40,7 +40,7 @@ module Opal
|
|
40
40
|
arity_code = arity_check(args, opt, uses_splat, block_name, mid)
|
41
41
|
end
|
42
42
|
|
43
|
-
in_scope
|
43
|
+
in_scope do
|
44
44
|
scope.mid = mid
|
45
45
|
scope.defs = true if recvr
|
46
46
|
|
@@ -53,7 +53,7 @@ module Opal
|
|
53
53
|
scope.block_name = yielder
|
54
54
|
|
55
55
|
params = process(args)
|
56
|
-
stmt_code = stmt(stmts)
|
56
|
+
stmt_code = stmt(compiler.returns(stmts))
|
57
57
|
|
58
58
|
add_temp 'self = this'
|
59
59
|
|
@@ -13,20 +13,6 @@ module Opal
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
# :scope nodes are actually inside scopes (e.g. :module, :class).
|
17
|
-
# These are not actually the scopes themselves.
|
18
|
-
class ScopeNode < Base
|
19
|
-
handle :scope
|
20
|
-
|
21
|
-
children :body
|
22
|
-
|
23
|
-
def compile
|
24
|
-
body = self.body || s(:nil)
|
25
|
-
body = compiler.returns(body) unless scope.class_scope?
|
26
|
-
push stmt(body)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
16
|
class UndefNode < Base
|
31
17
|
handle :undef
|
32
18
|
|
data/lib/opal/nodes/iter.rb
CHANGED
@@ -1,25 +1,15 @@
|
|
1
|
-
require 'opal/nodes/
|
1
|
+
require 'opal/nodes/scope'
|
2
2
|
|
3
3
|
module Opal
|
4
4
|
module Nodes
|
5
|
-
|
6
|
-
class IterNode < BaseScopeNode
|
5
|
+
class IterNode < ScopeNode
|
7
6
|
handle :iter
|
8
7
|
|
9
8
|
children :args_sexp, :body_sexp
|
10
9
|
|
11
10
|
def compile
|
12
|
-
|
13
|
-
|
14
|
-
opt_args = args.pop
|
15
|
-
opt_args.shift
|
16
|
-
end
|
17
|
-
|
18
|
-
# does this iter define a block_pass
|
19
|
-
if args.last.is_a?(Sexp) and args.last.type == :block_pass
|
20
|
-
block_arg = args.pop
|
21
|
-
block_arg = block_arg[1][1].to_sym
|
22
|
-
end
|
11
|
+
opt_args = extract_opt_args
|
12
|
+
block_arg = extract_block_arg
|
23
13
|
|
24
14
|
# find any splat args
|
25
15
|
if args.last.is_a?(Sexp) and args.last.type == :splat
|
@@ -31,31 +21,13 @@ module Opal
|
|
31
21
|
params = args_to_params(args[1..-1])
|
32
22
|
params << splat if splat
|
33
23
|
|
34
|
-
to_vars = identity = nil
|
24
|
+
to_vars = identity = body_code = nil
|
35
25
|
|
36
|
-
in_scope
|
26
|
+
in_scope do
|
37
27
|
identity = scope.identify!
|
38
28
|
add_temp "self = #{identity}._s || this"
|
39
29
|
|
40
|
-
|
41
|
-
args[1..-1].each_with_index do |arg, idx|
|
42
|
-
if arg.type == :lasgn
|
43
|
-
arg = variable(arg[1])
|
44
|
-
|
45
|
-
if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
|
46
|
-
push "if (#{arg} == null) #{arg} = ", expr(current_opt[2]), ";"
|
47
|
-
else
|
48
|
-
push "if (#{arg} == null) #{arg} = nil;"
|
49
|
-
end
|
50
|
-
elsif arg.type == :array
|
51
|
-
arg[1..-1].each_with_index do |_arg, _idx|
|
52
|
-
_arg = variable(_arg[1])
|
53
|
-
push "#{_arg} = #{params[idx]}[#{_idx}];"
|
54
|
-
end
|
55
|
-
else
|
56
|
-
raise "Bad block arg type"
|
57
|
-
end
|
58
|
-
end
|
30
|
+
compile_args(args[1..-1], opt_args, params)
|
59
31
|
|
60
32
|
if splat
|
61
33
|
scope.add_arg splat
|
@@ -70,13 +42,54 @@ module Opal
|
|
70
42
|
line "#{block_arg} = #{scope_name}._p || nil, #{scope_name}._p = null;"
|
71
43
|
end
|
72
44
|
|
73
|
-
|
45
|
+
body_code = stmt(body)
|
74
46
|
to_vars = scope.to_vars
|
75
47
|
end
|
76
48
|
|
49
|
+
line body_code
|
50
|
+
|
77
51
|
unshift to_vars
|
78
|
-
|
79
|
-
|
52
|
+
|
53
|
+
unshift "(#{identity} = function(#{params.join ', '}){"
|
54
|
+
push "}, #{identity}._s = self, #{identity})"
|
55
|
+
end
|
56
|
+
|
57
|
+
def compile_args(args, opt_args, params)
|
58
|
+
args.each_with_index do |arg, idx|
|
59
|
+
if arg.type == :lasgn
|
60
|
+
arg = variable(arg[1])
|
61
|
+
|
62
|
+
if opt_args and current_opt = opt_args.find { |s| s[1] == arg.to_sym }
|
63
|
+
push "if (#{arg} == null) #{arg} = ", expr(current_opt[2]), ";"
|
64
|
+
else
|
65
|
+
push "if (#{arg} == null) #{arg} = nil;"
|
66
|
+
end
|
67
|
+
elsif arg.type == :array
|
68
|
+
arg[1..-1].each_with_index do |_arg, _idx|
|
69
|
+
_arg = variable(_arg[1])
|
70
|
+
push "#{_arg} = #{params[idx]}[#{_idx}];"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
raise "Bad block arg type"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# opt args are last (if present) and are a s(:block)
|
79
|
+
def extract_opt_args
|
80
|
+
if args.last.is_a?(Sexp) and args.last.type == :block
|
81
|
+
opt_args = args.pop
|
82
|
+
opt_args.shift
|
83
|
+
opt_args
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# does this iter define a block_pass
|
88
|
+
def extract_block_arg
|
89
|
+
if args.last.is_a?(Sexp) and args.last.type == :block_pass
|
90
|
+
block_arg = args.pop
|
91
|
+
block_arg = block_arg[1][1].to_sym
|
92
|
+
end
|
80
93
|
end
|
81
94
|
|
82
95
|
def args
|
data/lib/opal/nodes/literal.rb
CHANGED
@@ -6,51 +6,56 @@ module Opal
|
|
6
6
|
handle :true, :false, :self, :nil
|
7
7
|
|
8
8
|
def compile
|
9
|
-
# :self, :true, :false, :nil
|
10
9
|
push type.to_s
|
11
10
|
end
|
12
11
|
end
|
13
12
|
|
14
|
-
class
|
15
|
-
children :value
|
16
|
-
end
|
17
|
-
|
18
|
-
class NumericNode < LiteralNode
|
13
|
+
class NumericNode < Base
|
19
14
|
handle :int, :float
|
20
15
|
|
16
|
+
children :value
|
17
|
+
|
21
18
|
def compile
|
22
19
|
push value.to_s
|
23
20
|
wrap '(', ')' if recv?
|
24
21
|
end
|
25
22
|
end
|
26
23
|
|
27
|
-
class StringNode <
|
24
|
+
class StringNode < Base
|
28
25
|
handle :str
|
29
26
|
|
27
|
+
children :value
|
28
|
+
|
30
29
|
def compile
|
31
30
|
push value.inspect
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
class SymbolNode <
|
34
|
+
class SymbolNode < Base
|
36
35
|
handle :sym
|
37
36
|
|
37
|
+
children :value
|
38
|
+
|
38
39
|
def compile
|
39
40
|
push value.to_s.inspect
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
class RegexpNode <
|
44
|
+
class RegexpNode < Base
|
44
45
|
handle :regexp
|
45
46
|
|
47
|
+
children :value
|
48
|
+
|
46
49
|
def compile
|
47
50
|
push((value == // ? /^/ : value).inspect)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
|
-
class XStringNode <
|
54
|
+
class XStringNode < Base
|
52
55
|
handle :xstr
|
53
56
|
|
57
|
+
children :value
|
58
|
+
|
54
59
|
def needs_semicolon?
|
55
60
|
stmt? and !value.to_s.include?(';')
|
56
61
|
end
|
@@ -158,35 +163,27 @@ module Opal
|
|
158
163
|
end
|
159
164
|
end
|
160
165
|
|
161
|
-
class
|
162
|
-
handle :
|
166
|
+
class InclusiveRangeNode < Base
|
167
|
+
handle :irange
|
163
168
|
|
164
169
|
children :start, :finish
|
165
170
|
|
166
171
|
def compile
|
167
172
|
helper :range
|
168
173
|
|
169
|
-
push
|
170
|
-
push expr(start)
|
171
|
-
push ", "
|
172
|
-
push expr(finish)
|
173
|
-
push ", false)"
|
174
|
+
push '$range(', expr(start), ', ', expr(finish), ', false)'
|
174
175
|
end
|
175
176
|
end
|
176
177
|
|
177
|
-
class
|
178
|
-
handle :
|
178
|
+
class ExclusiveRangeNode < Base
|
179
|
+
handle :erange
|
179
180
|
|
180
181
|
children :start, :finish
|
181
182
|
|
182
183
|
def compile
|
183
184
|
helper :range
|
184
185
|
|
185
|
-
push
|
186
|
-
push expr(start)
|
187
|
-
push ", "
|
188
|
-
push expr(finish)
|
189
|
-
push ", true)"
|
186
|
+
push '$range(', expr(start), ', ', expr(finish), ', true)'
|
190
187
|
end
|
191
188
|
end
|
192
189
|
end
|