template-ruby 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +9 -0
- data/.gitignore +1 -0
- data/.prettierrc +3 -0
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/README.md +10 -0
- data/bin/template +39 -0
- data/docs/euler/1.template +14 -0
- data/docs/euler/2.template +16 -0
- data/docs/euler/3.template +16 -0
- data/docs/euler/4.template +11 -0
- data/docs/euler/5.template +14 -0
- data/docs/precedence.template +94 -0
- data/lib/code/error.rb +15 -0
- data/lib/code/node/base_10_decimal.rb +12 -7
- data/lib/code/node/base_10_integer.rb +13 -4
- data/lib/code/node/base_10_number.rb +3 -3
- data/lib/code/node/base_16_number.rb +2 -2
- data/lib/code/node/base_2_number.rb +2 -2
- data/lib/code/node/base_8_number.rb +2 -2
- data/lib/code/node/block.rb +17 -0
- data/lib/code/node/boolean.rb +13 -4
- data/lib/code/node/call.rb +40 -8
- data/lib/code/node/call_argument.rb +37 -0
- data/lib/code/node/chained_call.rb +38 -0
- data/lib/code/node/code.rb +4 -7
- data/lib/code/node/defined.rb +19 -0
- data/lib/code/node/dictionnary.rb +11 -7
- data/lib/code/node/dictionnary_key_value.rb +3 -3
- data/lib/code/node/equal.rb +36 -0
- data/lib/code/node/function.rb +17 -0
- data/lib/code/node/function_argument.rb +45 -0
- data/lib/code/node/group.rb +13 -0
- data/lib/code/node/if.rb +55 -0
- data/lib/code/node/if_modifier.rb +48 -0
- data/lib/code/node/keyword_call_argument.rb +30 -0
- data/lib/code/node/keyword_function_argument.rb +33 -0
- data/lib/code/node/list.rb +10 -4
- data/lib/code/node/name.rb +37 -4
- data/lib/code/node/negation.rb +33 -0
- data/lib/code/node/not_keyword.rb +13 -0
- data/lib/code/node/nothing.rb +2 -2
- data/lib/code/node/number.rb +3 -3
- data/lib/code/node/operation.rb +33 -0
- data/lib/code/node/or_keyword.rb +34 -0
- data/lib/code/node/power.rb +16 -0
- data/lib/code/node/range.rb +31 -0
- data/lib/code/node/regular_call_argument.rb +34 -0
- data/lib/code/node/regular_function_argument.rb +36 -0
- data/lib/code/node/rescue.rb +16 -0
- data/lib/code/node/statement.rb +53 -3
- data/lib/code/node/string.rb +2 -2
- data/lib/code/node/ternary.rb +26 -0
- data/lib/code/node/unary_minus.rb +22 -0
- data/lib/code/node/while.rb +42 -0
- data/lib/code/node.rb +10 -0
- data/lib/code/object/argument.rb +41 -0
- data/lib/code/object/boolean.rb +8 -9
- data/lib/code/object/decimal.rb +32 -9
- data/lib/code/object/dictionnary.rb +33 -10
- data/lib/code/object/function.rb +64 -0
- data/lib/code/object/integer.rb +94 -7
- data/lib/code/object/list.rb +190 -10
- data/lib/code/object/nothing.rb +10 -9
- data/lib/code/object/number.rb +6 -0
- data/lib/code/object/range.rb +158 -0
- data/lib/code/object/string.rb +37 -7
- data/lib/code/object.rb +129 -2
- data/lib/code/parser/addition.rb +29 -0
- data/lib/code/parser/and_operator.rb +28 -0
- data/lib/code/parser/bitwise_and.rb +28 -0
- data/lib/code/parser/bitwise_or.rb +29 -0
- data/lib/code/parser/call.rb +77 -3
- data/lib/code/parser/defined.rb +20 -0
- data/lib/code/parser/equal.rb +42 -0
- data/lib/code/parser/equality.rb +36 -0
- data/lib/code/parser/function.rb +57 -0
- data/lib/code/parser/greater_than.rb +33 -0
- data/lib/code/parser/group.rb +17 -0
- data/lib/code/parser/if.rb +33 -0
- data/lib/code/parser/if_modifier.rb +28 -0
- data/lib/code/parser/multiplication.rb +30 -0
- data/lib/code/parser/name.rb +44 -4
- data/lib/code/parser/negation.rb +19 -0
- data/lib/code/parser/not_keyword.rb +21 -0
- data/lib/code/parser/nothing.rb +2 -2
- data/lib/code/parser/or_keyword.rb +29 -0
- data/lib/code/parser/or_operator.rb +28 -0
- data/lib/code/parser/power.rb +25 -0
- data/lib/code/parser/range.rb +25 -0
- data/lib/code/parser/rescue.rb +23 -0
- data/lib/code/parser/shift.rb +31 -0
- data/lib/code/parser/statement.rb +1 -4
- data/lib/code/parser/string.rb +7 -1
- data/lib/code/parser/ternary.rb +25 -0
- data/lib/code/parser/unary_minus.rb +13 -0
- data/lib/code/parser/while.rb +25 -0
- data/lib/code.rb +5 -7
- data/lib/template/node/code_part.rb +2 -2
- data/lib/template/node/part.rb +2 -2
- data/lib/template/node/template.rb +4 -2
- data/lib/template/node/text_part.rb +1 -1
- data/lib/template-ruby.rb +4 -0
- data/lib/template.rb +9 -4
- data/spec/call_spec.rb +22 -0
- data/spec/code/error/type_error_spec.rb +65 -0
- data/spec/code/parser/boolean_spec.rb +1 -1
- data/spec/code/parser/call_spec.rb +40 -11
- data/spec/code/parser/dictionnary_spec.rb +11 -11
- data/spec/code/parser/function_spec.rb +32 -0
- data/spec/code/parser/list_spec.rb +5 -5
- data/spec/code/parser/nothing_spec.rb +1 -1
- data/spec/code/parser/number_spec.rb +35 -35
- data/spec/code/parser/string_spec.rb +3 -2
- data/spec/code_spec.rb +75 -3
- data/spec/function_spec.rb +26 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/template/parser/template_spec.rb +1 -1
- data/spec/template_spec.rb +6 -6
- data/template-ruby.gemspec +6 -3
- metadata +76 -4
@@ -1,6 +1,6 @@
|
|
1
1
|
class Code
|
2
2
|
class Node
|
3
|
-
class DictionnaryKeyValue
|
3
|
+
class DictionnaryKeyValue < Node
|
4
4
|
def initialize(key_value)
|
5
5
|
@key = key_value.fetch(:key)
|
6
6
|
|
@@ -15,8 +15,8 @@ class Code
|
|
15
15
|
@value = ::Code::Node::Code.new(key_value.fetch(:value))
|
16
16
|
end
|
17
17
|
|
18
|
-
def evaluate(
|
19
|
-
[@key.evaluate(
|
18
|
+
def evaluate(**args)
|
19
|
+
[@key.evaluate(**args), @value.evaluate(**args)]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Equal < Node
|
4
|
+
def initialize(equal)
|
5
|
+
@left = equal.fetch(:left).fetch(:name)
|
6
|
+
@operator = equal.fetch(:operator)
|
7
|
+
@right = ::Code::Node::Statement.new(equal.fetch(:right))
|
8
|
+
end
|
9
|
+
|
10
|
+
def evaluate(**args)
|
11
|
+
right = @right.evaluate(**args)
|
12
|
+
context = args.fetch(:context)
|
13
|
+
|
14
|
+
if operator
|
15
|
+
if context[left]
|
16
|
+
context[left] = simple_call(context[left], operator, right, **args)
|
17
|
+
else
|
18
|
+
raise ::Code::Error::UndefinedVariable.new("#{left} is undefined")
|
19
|
+
end
|
20
|
+
else
|
21
|
+
context[left] = right
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def operator
|
28
|
+
@operator.to_s[0...-1].to_sym.presence
|
29
|
+
end
|
30
|
+
|
31
|
+
def left
|
32
|
+
::Code::Object::String.new(@left.to_s)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Function < Node
|
4
|
+
def initialize(function)
|
5
|
+
@body = ::Code::Node::Code.new(function.fetch(:body))
|
6
|
+
@arguments = function.fetch(:arguments, [])
|
7
|
+
@arguments.map! do |argument|
|
8
|
+
::Code::Node::FunctionArgument.new(argument)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def evaluate(**args)
|
13
|
+
::Code::Object::Function.new(arguments: @arguments, body: @body)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class FunctionArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
if argument.key?(:regular)
|
6
|
+
@argument =
|
7
|
+
::Code::Node::RegularFunctionArgument.new(argument.fetch(:regular))
|
8
|
+
elsif argument.key?(:keyword)
|
9
|
+
@argument =
|
10
|
+
::Code::Node::KeywordFunctionArgument.new(argument.fetch(:keyword))
|
11
|
+
else
|
12
|
+
raise NotImplementedError.new(argument.inspect)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def evaluate(**args)
|
17
|
+
@argument.evaluate(**args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def splat?
|
21
|
+
@argument.splat?
|
22
|
+
end
|
23
|
+
|
24
|
+
def keyword_splat?
|
25
|
+
@argument.keyword_splat?
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
@argument.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def block?
|
33
|
+
@argument.block?
|
34
|
+
end
|
35
|
+
|
36
|
+
def regular?
|
37
|
+
@argument.is_a?(::Code::Node::RegularFunctionArgument)
|
38
|
+
end
|
39
|
+
|
40
|
+
def keyword?
|
41
|
+
@argument.is_a?(::Code::Node::KeywordFunctionArgument)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/code/node/if.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class If < Node
|
4
|
+
IF_KEYWORD = "if"
|
5
|
+
UNLESS_KEYWORD = "unless"
|
6
|
+
|
7
|
+
class Else
|
8
|
+
def initialize(else_parsed)
|
9
|
+
if else_parsed.key?(:operator)
|
10
|
+
@operator = else_parsed.fetch(:operator)
|
11
|
+
@statement =
|
12
|
+
::Code::Node::Statement.new(else_parsed.fetch(:statement))
|
13
|
+
end
|
14
|
+
|
15
|
+
@body = ::Code::Node::Code.new(else_parsed.fetch(:body))
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :operator, :body, :statement
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(if_parsed)
|
22
|
+
@if_operator = if_parsed.fetch(:if_operator)
|
23
|
+
@if_statement =
|
24
|
+
::Code::Node::Statement.new(if_parsed.fetch(:if_statement))
|
25
|
+
@if_body = ::Code::Node::Code.new(if_parsed.fetch(:if_body))
|
26
|
+
@elses = if_parsed.fetch(:elses, [])
|
27
|
+
@elses.map! { |else_parsed| ::Code::Node::If::Else.new(else_parsed) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def evaluate(**args)
|
31
|
+
if_object = @if_statement.evaluate(**args)
|
32
|
+
|
33
|
+
if @if_operator == IF_KEYWORD && if_object.truthy?
|
34
|
+
@if_body.evaluate(**args)
|
35
|
+
elsif @if_operator == UNLESS_KEYWORD && if_object.falsy?
|
36
|
+
@if_body.evaluate(**args)
|
37
|
+
else
|
38
|
+
@elses.each do |else_node|
|
39
|
+
if else_node.operator == IF_KEYWORD
|
40
|
+
else_object = else_node.statement.evaluate(**args)
|
41
|
+
return else_node.body.evaluate(**args) if else_object.truthy?
|
42
|
+
elsif else_node.operator == UNLESS_KEYWORD
|
43
|
+
else_object = else_node.statement.evaluate(**args)
|
44
|
+
return else_node.body.evaluate(**args) if else_object.falsy?
|
45
|
+
elsif else_node.operator.nil?
|
46
|
+
return else_node.body.evaluate(**args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
::Code::Object::Nothing.new
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class IfModifier < Node
|
4
|
+
IF_KEYWORD = :if
|
5
|
+
UNLESS_KEYWORD = :unless
|
6
|
+
WHILE_KEYWORD = :while
|
7
|
+
UNTIL_KEYWORD = :until
|
8
|
+
|
9
|
+
def initialize(if_modifier)
|
10
|
+
@left = ::Code::Node::Statement.new(if_modifier.fetch(:left))
|
11
|
+
@operator = if_modifier.fetch(:operator)
|
12
|
+
@right = ::Code::Node::Statement.new(if_modifier.fetch(:right))
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate(**args)
|
16
|
+
if operator == IF_KEYWORD
|
17
|
+
right = @right.evaluate(**args)
|
18
|
+
|
19
|
+
right.truthy? ? @left.evaluate(**args) : ::Code::Object::Nothing.new
|
20
|
+
elsif operator == UNLESS_KEYWORD
|
21
|
+
right = @right.evaluate(**args)
|
22
|
+
|
23
|
+
right.truthy? ? ::Code::Object::Nothing.new : @left.evaluate(**args)
|
24
|
+
elsif operator == WHILE_KEYWORD
|
25
|
+
left = ::Code::Object::Nothing.new
|
26
|
+
|
27
|
+
left = @left.evaluate(**args) while @right.evaluate(**args).truthy?
|
28
|
+
|
29
|
+
left
|
30
|
+
elsif operator == UNTIL_KEYWORD
|
31
|
+
left = ::Code::Object::Nothing.new
|
32
|
+
|
33
|
+
left = @left.evaluate(**args) until @right.evaluate(**args).truthy?
|
34
|
+
|
35
|
+
left
|
36
|
+
else
|
37
|
+
raise NotImplementedError.new(operator.inspect)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def operator
|
44
|
+
@operator.to_sym
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class KeywordCallArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
@name = argument.fetch(:name)
|
6
|
+
@value = ::Code::Node::Code.new(argument.fetch(:value))
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(**args)
|
10
|
+
@value.evaluate(**args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
::Code::Object::String.new(@name.to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def block?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def splat?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def keyword_splat?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class KeywordFunctionArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
@name = argument.fetch(:name)
|
6
|
+
|
7
|
+
if argument.key?(:default)
|
8
|
+
@default = ::Code::Node::Code.new(argument.fetch(:default))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def evaluate(**args)
|
13
|
+
@default ? @default.evaluate(**args) : ::Code::Object::Nothing.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
::Code::Object::String.new(@name.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def splat?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def keyword_splat?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def block?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/code/node/list.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
class Code
|
2
2
|
class Node
|
3
|
-
class List
|
3
|
+
class List < Node
|
4
4
|
def initialize(codes)
|
5
|
-
@codes =
|
5
|
+
@codes =
|
6
|
+
codes
|
7
|
+
.map do |code|
|
8
|
+
code.fetch(:code).presence &&
|
9
|
+
::Code::Node::Code.new(code.fetch(:code))
|
10
|
+
end
|
11
|
+
.compact
|
6
12
|
end
|
7
13
|
|
8
|
-
def evaluate(
|
9
|
-
::Code::Object::List.new(@codes.map { |code| code.evaluate(
|
14
|
+
def evaluate(**args)
|
15
|
+
::Code::Object::List.new(@codes.map { |code| code.evaluate(**args) })
|
10
16
|
end
|
11
17
|
end
|
12
18
|
end
|
data/lib/code/node/name.rb
CHANGED
@@ -1,17 +1,50 @@
|
|
1
1
|
class Code
|
2
2
|
class Node
|
3
|
-
class Name
|
3
|
+
class Name < Node
|
4
4
|
def initialize(name)
|
5
5
|
@name = name
|
6
6
|
end
|
7
7
|
|
8
|
-
def evaluate(
|
9
|
-
context.fetch(
|
8
|
+
def evaluate(**args)
|
9
|
+
context = args.fetch(:context)
|
10
|
+
arguments = args.fetch(:arguments, [])
|
11
|
+
object = args.fetch(:object, nil)
|
12
|
+
io = args.fetch(:io)
|
13
|
+
|
14
|
+
if object
|
15
|
+
object.call(
|
16
|
+
context: context,
|
17
|
+
operator: name,
|
18
|
+
arguments: arguments,
|
19
|
+
io: io,
|
20
|
+
)
|
21
|
+
elsif context.key?(name)
|
22
|
+
object = context[name]
|
23
|
+
|
24
|
+
if object.is_a?(::Code::Object::Function)
|
25
|
+
object.call(
|
26
|
+
context: context,
|
27
|
+
operator: nil,
|
28
|
+
arguments: arguments,
|
29
|
+
io: io,
|
30
|
+
)
|
31
|
+
else
|
32
|
+
object
|
33
|
+
end
|
34
|
+
elsif name == "puts"
|
35
|
+
arguments.each { |argument| io.puts argument.value }
|
36
|
+
|
37
|
+
::Code::Object::Nothing.new
|
38
|
+
else
|
39
|
+
raise ::Code::Error::Undefined.new("#{name} undefined")
|
40
|
+
end
|
10
41
|
end
|
11
42
|
|
12
43
|
private
|
13
44
|
|
14
|
-
|
45
|
+
def name
|
46
|
+
::Code::Object::String.new(@name.to_s)
|
47
|
+
end
|
15
48
|
end
|
16
49
|
end
|
17
50
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Negation < Node
|
4
|
+
EXCLAMATION_POINT = "!"
|
5
|
+
PLUS = "+"
|
6
|
+
|
7
|
+
def initialize(negation)
|
8
|
+
@operator = negation.fetch(:operator)
|
9
|
+
@statement = ::Code::Node::Statement.new(negation.fetch(:statement))
|
10
|
+
end
|
11
|
+
|
12
|
+
def evaluate(**args)
|
13
|
+
object = @statement.evaluate(**args)
|
14
|
+
|
15
|
+
if operator == EXCLAMATION_POINT
|
16
|
+
if object.truthy?
|
17
|
+
::Code::Object::Boolean.new(false)
|
18
|
+
else
|
19
|
+
::Code::Object::Boolean.new(true)
|
20
|
+
end
|
21
|
+
elsif operator == PLUS
|
22
|
+
object
|
23
|
+
else
|
24
|
+
raise NotImplementedError.new(operator)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :operator
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class NotKeyword < Node
|
4
|
+
def initialize(not_keyword)
|
5
|
+
@statement = ::Code::Node::Statement.new(not_keyword)
|
6
|
+
end
|
7
|
+
|
8
|
+
def evaluate(**args)
|
9
|
+
::Code::Object::Boolean.new(!@statement.evaluate(**args).truthy?)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/code/node/nothing.rb
CHANGED
data/lib/code/node/number.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Code
|
2
2
|
class Node
|
3
|
-
class Number
|
3
|
+
class Number < Node
|
4
4
|
def initialize(number)
|
5
5
|
if number.key?(:base_2)
|
6
6
|
@number = ::Code::Node::Base2Number.new(number[:base_2])
|
@@ -15,8 +15,8 @@ class Code
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def evaluate(
|
19
|
-
@number.evaluate(
|
18
|
+
def evaluate(**args)
|
19
|
+
@number.evaluate(**args)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Operation < Node
|
4
|
+
class Operation
|
5
|
+
attr_reader :operator, :statement
|
6
|
+
|
7
|
+
def initialize(operation)
|
8
|
+
@operator = operation.fetch(:operator).to_s
|
9
|
+
@statement = ::Code::Node::Statement.new(operation.fetch(:statement))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(operation)
|
14
|
+
@first = ::Code::Node::Statement.new(operation.fetch(:first))
|
15
|
+
@rest = operation.fetch(:rest)
|
16
|
+
@rest.map! do |operation|
|
17
|
+
::Code::Node::Operation::Operation.new(operation)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def evaluate(**args)
|
22
|
+
object = @first.evaluate(**args)
|
23
|
+
|
24
|
+
@rest.each do |operation|
|
25
|
+
other = operation.statement.evaluate(**args)
|
26
|
+
object = simple_call(object, operation.operator, other, **args)
|
27
|
+
end
|
28
|
+
|
29
|
+
object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class OrKeyword < Node
|
4
|
+
OR_KEYWORD = "or"
|
5
|
+
AND_KEYWORD = "and"
|
6
|
+
|
7
|
+
def initialize(or_keyword)
|
8
|
+
@first = ::Code::Node::Statement.new(or_keyword.fetch(:first))
|
9
|
+
@rest = or_keyword.fetch(:rest)
|
10
|
+
@rest.map! do |operation|
|
11
|
+
::Code::Node::Operation::Operation.new(operation)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate(**args)
|
16
|
+
object = @first.evaluate(**args)
|
17
|
+
|
18
|
+
@rest.each do |operation|
|
19
|
+
if operation.operator == OR_KEYWORD
|
20
|
+
return object if object.truthy?
|
21
|
+
elsif operation.operator == AND_KEYWORD
|
22
|
+
return object unless object.truthy?
|
23
|
+
else
|
24
|
+
raise NotImplementedError.new(operation.operator.inspect)
|
25
|
+
end
|
26
|
+
|
27
|
+
object = operation.statement.evaluate(**args)
|
28
|
+
end
|
29
|
+
|
30
|
+
object
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Power < Node
|
4
|
+
def initialize(power)
|
5
|
+
@left = ::Code::Node::Statement.new(power.fetch(:left))
|
6
|
+
@right = ::Code::Node::Statement.new(power.fetch(:right))
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(**args)
|
10
|
+
right = @right.evaluate(**args)
|
11
|
+
left = @left.evaluate(**args)
|
12
|
+
simple_call(left, :**, right, **args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Range < Node
|
4
|
+
INCLUSIVE_RANGE = ".."
|
5
|
+
EXCLUSIVE_RANGE = "..."
|
6
|
+
|
7
|
+
def initialize(range)
|
8
|
+
@left = ::Code::Node::Statement.new(range.fetch(:left))
|
9
|
+
@operator = range.fetch(:operator)
|
10
|
+
@right = ::Code::Node::Statement.new(range.fetch(:right))
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate(**args)
|
14
|
+
left = @left.evaluate(**args)
|
15
|
+
right = @right.evaluate(**args)
|
16
|
+
|
17
|
+
if operator == INCLUSIVE_RANGE
|
18
|
+
::Code::Object::Range.new(left, right, exclude_end: false)
|
19
|
+
elsif operator == EXCLUSIVE_RANGE
|
20
|
+
::Code::Object::Range.new(left, right, exclude_end: true)
|
21
|
+
else
|
22
|
+
raise NotImplementedError.new(operator)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :operator
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class RegularCallArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
@splat = argument.key?(:splat)
|
6
|
+
@keyword_splat = argument.key?(:keyword_splat)
|
7
|
+
@block = argument.key?(:block)
|
8
|
+
@value = ::Code::Node::Code.new(argument.fetch(:value))
|
9
|
+
end
|
10
|
+
|
11
|
+
def evaluate(**args)
|
12
|
+
object = @value.evaluate(**args)
|
13
|
+
|
14
|
+
block? ? simple_call(object, :to_function, **args) : object
|
15
|
+
end
|
16
|
+
|
17
|
+
def block?
|
18
|
+
@block
|
19
|
+
end
|
20
|
+
|
21
|
+
def splat?
|
22
|
+
@splat
|
23
|
+
end
|
24
|
+
|
25
|
+
def keyword_splat?
|
26
|
+
@keyword_splat
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class RegularFunctionArgument < Node
|
4
|
+
def initialize(argument)
|
5
|
+
@block = argument.key?(:block)
|
6
|
+
@splat = argument.key?(:splat)
|
7
|
+
@keyword_splat = argument.key?(:keyword_splat)
|
8
|
+
@name = argument.fetch(:name)
|
9
|
+
|
10
|
+
if argument.key?(:default)
|
11
|
+
@default = ::Code::Node::Code.new(argument.fetch(:default))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def evaluate(**args)
|
16
|
+
@default ? @default.evaluate(**args) : ::Code::Object::Nothing.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
::Code::Object::String.new(@name.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def splat?
|
24
|
+
@splat
|
25
|
+
end
|
26
|
+
|
27
|
+
def keyword_splat?
|
28
|
+
@keyword_splat
|
29
|
+
end
|
30
|
+
|
31
|
+
def block?
|
32
|
+
@block
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Code
|
2
|
+
class Node
|
3
|
+
class Rescue < Node
|
4
|
+
def initialize(power)
|
5
|
+
@left = ::Code::Node::Statement.new(power.fetch(:left))
|
6
|
+
@right = ::Code::Node::Statement.new(power.fetch(:right))
|
7
|
+
end
|
8
|
+
|
9
|
+
def evaluate(**args)
|
10
|
+
@left.evaluate(**args)
|
11
|
+
rescue ::Code::Error
|
12
|
+
@right.evaluate(**args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|