template-ruby 0.1.0 → 0.2.2
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.
- checksums.yaml +4 -4
- data/.editorconfig +9 -0
- data/.gitignore +1 -0
- data/.prettierrc +3 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +5 -5
- 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 +41 -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 +121 -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/code.rb +2 -1
- 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/parser/template.rb +6 -2
- 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 +38 -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 +3 -6
- data/template-ruby.gemspec +6 -3
- metadata +76 -4
@@ -1,16 +1,20 @@
|
|
1
1
|
class Code
|
2
2
|
class Node
|
3
|
-
class Dictionnary
|
3
|
+
class Dictionnary < Node
|
4
4
|
def initialize(key_values)
|
5
|
-
|
6
|
-
key_values
|
7
|
-
|
8
|
-
|
5
|
+
if key_values.blank?
|
6
|
+
@key_values = []
|
7
|
+
else
|
8
|
+
@key_values =
|
9
|
+
key_values.map do |key_value|
|
10
|
+
::Code::Node::DictionnaryKeyValue.new(key_value)
|
11
|
+
end
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
|
-
def evaluate(
|
15
|
+
def evaluate(**args)
|
12
16
|
::Code::Object::Dictionnary.new(
|
13
|
-
@key_values.map { |key_value| key_value.evaluate(
|
17
|
+
@key_values.map { |key_value| key_value.evaluate(**args) }.to_h,
|
14
18
|
)
|
15
19
|
end
|
16
20
|
end
|
@@ -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
|