code-ruby 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.github/workflows/rspec.yml +14 -0
  4. data/.gitignore +2 -0
  5. data/.prettierrc +3 -0
  6. data/.rspec +1 -0
  7. data/CHANGELOG.md +31 -0
  8. data/Gemfile +3 -0
  9. data/Gemfile.lock +70 -0
  10. data/LICENSE +7 -0
  11. data/README.md +103 -0
  12. data/TODO.md +1 -0
  13. data/bin/template +39 -0
  14. data/code-ruby.gemspec +22 -0
  15. data/docs/euler/1.template +14 -0
  16. data/docs/euler/2.template +16 -0
  17. data/docs/euler/3.template +16 -0
  18. data/docs/euler/4.template +11 -0
  19. data/docs/euler/5.template +14 -0
  20. data/docs/precedence.template +94 -0
  21. data/lib/code/error.rb +15 -0
  22. data/lib/code/node/base_10_decimal.rb +32 -0
  23. data/lib/code/node/base_10_integer.rb +32 -0
  24. data/lib/code/node/base_10_number.rb +19 -0
  25. data/lib/code/node/base_16_number.rb +19 -0
  26. data/lib/code/node/base_2_number.rb +19 -0
  27. data/lib/code/node/base_8_number.rb +19 -0
  28. data/lib/code/node/block.rb +17 -0
  29. data/lib/code/node/boolean.rb +22 -0
  30. data/lib/code/node/call.rb +52 -0
  31. data/lib/code/node/call_argument.rb +37 -0
  32. data/lib/code/node/chained_call.rb +38 -0
  33. data/lib/code/node/code.rb +16 -0
  34. data/lib/code/node/defined.rb +19 -0
  35. data/lib/code/node/dictionnary.rb +22 -0
  36. data/lib/code/node/dictionnary_key_value.rb +23 -0
  37. data/lib/code/node/equal.rb +36 -0
  38. data/lib/code/node/function.rb +17 -0
  39. data/lib/code/node/function_argument.rb +45 -0
  40. data/lib/code/node/group.rb +13 -0
  41. data/lib/code/node/if.rb +55 -0
  42. data/lib/code/node/if_modifier.rb +48 -0
  43. data/lib/code/node/keyword_call_argument.rb +30 -0
  44. data/lib/code/node/keyword_function_argument.rb +33 -0
  45. data/lib/code/node/list.rb +19 -0
  46. data/lib/code/node/name.rb +50 -0
  47. data/lib/code/node/negation.rb +33 -0
  48. data/lib/code/node/not_keyword.rb +13 -0
  49. data/lib/code/node/nothing.rb +12 -0
  50. data/lib/code/node/number.rb +23 -0
  51. data/lib/code/node/operation.rb +33 -0
  52. data/lib/code/node/or_keyword.rb +34 -0
  53. data/lib/code/node/power.rb +16 -0
  54. data/lib/code/node/range.rb +31 -0
  55. data/lib/code/node/regular_call_argument.rb +34 -0
  56. data/lib/code/node/regular_function_argument.rb +36 -0
  57. data/lib/code/node/rescue.rb +16 -0
  58. data/lib/code/node/statement.rb +81 -0
  59. data/lib/code/node/string.rb +17 -0
  60. data/lib/code/node/ternary.rb +26 -0
  61. data/lib/code/node/unary_minus.rb +22 -0
  62. data/lib/code/node/while.rb +42 -0
  63. data/lib/code/node.rb +14 -0
  64. data/lib/code/object/argument.rb +41 -0
  65. data/lib/code/object/boolean.rb +27 -0
  66. data/lib/code/object/decimal.rb +54 -0
  67. data/lib/code/object/dictionnary.rb +55 -0
  68. data/lib/code/object/function.rb +64 -0
  69. data/lib/code/object/integer.rb +116 -0
  70. data/lib/code/object/list.rb +217 -0
  71. data/lib/code/object/nothing.rb +23 -0
  72. data/lib/code/object/number.rb +6 -0
  73. data/lib/code/object/range.rb +158 -0
  74. data/lib/code/object/string.rb +68 -0
  75. data/lib/code/object.rb +130 -0
  76. data/lib/code/parser/addition.rb +29 -0
  77. data/lib/code/parser/and_operator.rb +28 -0
  78. data/lib/code/parser/bitwise_and.rb +28 -0
  79. data/lib/code/parser/bitwise_or.rb +29 -0
  80. data/lib/code/parser/boolean.rb +14 -0
  81. data/lib/code/parser/call.rb +90 -0
  82. data/lib/code/parser/code.rb +19 -0
  83. data/lib/code/parser/defined.rb +20 -0
  84. data/lib/code/parser/dictionnary.rb +41 -0
  85. data/lib/code/parser/equal.rb +42 -0
  86. data/lib/code/parser/equality.rb +36 -0
  87. data/lib/code/parser/function.rb +57 -0
  88. data/lib/code/parser/greater_than.rb +33 -0
  89. data/lib/code/parser/group.rb +17 -0
  90. data/lib/code/parser/if.rb +33 -0
  91. data/lib/code/parser/if_modifier.rb +28 -0
  92. data/lib/code/parser/list.rb +29 -0
  93. data/lib/code/parser/multiplication.rb +30 -0
  94. data/lib/code/parser/name.rb +89 -0
  95. data/lib/code/parser/negation.rb +19 -0
  96. data/lib/code/parser/not_keyword.rb +21 -0
  97. data/lib/code/parser/nothing.rb +17 -0
  98. data/lib/code/parser/number.rb +98 -0
  99. data/lib/code/parser/or_keyword.rb +29 -0
  100. data/lib/code/parser/or_operator.rb +28 -0
  101. data/lib/code/parser/power.rb +25 -0
  102. data/lib/code/parser/range.rb +25 -0
  103. data/lib/code/parser/rescue.rb +23 -0
  104. data/lib/code/parser/shift.rb +31 -0
  105. data/lib/code/parser/statement.rb +8 -0
  106. data/lib/code/parser/string.rb +72 -0
  107. data/lib/code/parser/ternary.rb +25 -0
  108. data/lib/code/parser/unary_minus.rb +13 -0
  109. data/lib/code/parser/while.rb +25 -0
  110. data/lib/code/parser.rb +4 -0
  111. data/lib/code-ruby.rb +11 -0
  112. data/lib/code.rb +29 -0
  113. data/lib/template/node/code_part.rb +13 -0
  114. data/lib/template/node/part.rb +19 -0
  115. data/lib/template/node/template.rb +15 -0
  116. data/lib/template/node/text_part.rb +13 -0
  117. data/lib/template/node.rb +4 -0
  118. data/lib/template/parser/template.rb +30 -0
  119. data/lib/template/parser.rb +4 -0
  120. data/lib/template/version.rb +3 -0
  121. data/lib/template-ruby.rb +11 -0
  122. data/lib/template.rb +34 -0
  123. data/spec/call_spec.rb +22 -0
  124. data/spec/code/error/type_error_spec.rb +65 -0
  125. data/spec/code/parser/boolean_spec.rb +18 -0
  126. data/spec/code/parser/call_spec.rb +66 -0
  127. data/spec/code/parser/dictionnary_spec.rb +46 -0
  128. data/spec/code/parser/function_spec.rb +32 -0
  129. data/spec/code/parser/list_spec.rb +29 -0
  130. data/spec/code/parser/name_spec.rb +15 -0
  131. data/spec/code/parser/nothing_spec.rb +19 -0
  132. data/spec/code/parser/number_spec.rb +117 -0
  133. data/spec/code/parser/string_spec.rb +30 -0
  134. data/spec/code_spec.rb +108 -0
  135. data/spec/function_spec.rb +26 -0
  136. data/spec/spec_helper.rb +3 -0
  137. data/spec/template/parser/template_spec.rb +19 -0
  138. data/spec/template_spec.rb +27 -0
  139. data/template-ruby.gemspec +24 -0
  140. metadata +266 -0
@@ -0,0 +1,22 @@
1
+ class Code
2
+ class Node
3
+ class Boolean < Node
4
+ TRUE = "true"
5
+ FALSE = "false"
6
+
7
+ def initialize(boolean)
8
+ @boolean = boolean
9
+ end
10
+
11
+ def evaluate(**args)
12
+ if @boolean == TRUE
13
+ ::Code::Object::Boolean.new(true)
14
+ elsif @boolean == FALSE
15
+ ::Code::Object::Boolean.new(false)
16
+ else
17
+ raise NotImplementedError, @boolean.inspect
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,52 @@
1
+ class Code
2
+ class Node
3
+ class Call < Node
4
+ def initialize(call)
5
+ @left = ::Code::Node::Statement.new(call.fetch(:left))
6
+
7
+ @arguments = call.fetch(:arguments, [])
8
+ @arguments.map! { |argument| ::Code::Node::CallArgument.new(argument) }
9
+
10
+ if call.key?(:right)
11
+ @right =
12
+ call
13
+ .fetch(:right)
14
+ .map { |right| ::Code::Node::ChainedCall.new(right) }
15
+ end
16
+
17
+ if call.key?(:block)
18
+ @block = ::Code::Node::Block.new(call.fetch(:block))
19
+ end
20
+ end
21
+
22
+ def evaluate(**args)
23
+ if @right
24
+ left = @left.evaluate(**args)
25
+ @right.reduce(left) do |acc, element|
26
+ element.evaluate(**args.merge(object: acc))
27
+ end
28
+ else
29
+ arguments =
30
+ @arguments.map do |argument|
31
+ ::Code::Object::Argument.new(
32
+ argument.evaluate(**args),
33
+ name: argument.name,
34
+ splat: argument.splat?,
35
+ keyword_splat: argument.keyword_splat?,
36
+ block: argument.block?,
37
+ )
38
+ end
39
+
40
+ if @block
41
+ arguments << ::Code::Object::Argument.new(
42
+ @block.evaluate(**args),
43
+ block: true,
44
+ )
45
+ end
46
+
47
+ @left.evaluate(**args.merge(arguments: arguments))
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ class Code
2
+ class Node
3
+ class CallArgument < Node
4
+ def initialize(argument)
5
+ if argument.key?(:regular)
6
+ @argument =
7
+ ::Code::Node::RegularCallArgument.new(argument.fetch(:regular))
8
+ elsif argument.key?(:keyword)
9
+ @argument =
10
+ ::Code::Node::KeywordCallArgument.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 name
21
+ @argument.name
22
+ end
23
+
24
+ def block?
25
+ @argument.block?
26
+ end
27
+
28
+ def splat?
29
+ @argument.splat?
30
+ end
31
+
32
+ def keyword_splat?
33
+ @argument.keyword_splat?
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ class Code
2
+ class Node
3
+ class ChainedCall < Node
4
+ def initialize(chained_call)
5
+ @name = ::Code::Node::Name.new(chained_call.fetch(:name))
6
+
7
+ @arguments = chained_call.fetch(:arguments, [])
8
+ @arguments.map! { |argument| ::Code::Node::CallArgument.new(argument) }
9
+
10
+ if chained_call.key?(:block)
11
+ @block = ::Code::Node::Block.new(chained_call.fetch(:block))
12
+ end
13
+ end
14
+
15
+ def evaluate(**args)
16
+ arguments =
17
+ @arguments.map do |argument|
18
+ ::Code::Object::Argument.new(
19
+ argument.evaluate(**args.merge(object: nil)),
20
+ name: argument.name,
21
+ splat: argument.splat?,
22
+ keyword_splat: argument.keyword_splat?,
23
+ block: argument.block?,
24
+ )
25
+ end
26
+
27
+ if @block
28
+ arguments << ::Code::Object::Argument.new(
29
+ @block.evaluate(**args.merge(object: nil)),
30
+ block: true,
31
+ )
32
+ end
33
+
34
+ @name.evaluate(**args.merge(arguments: arguments))
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ class Code
2
+ class Node
3
+ class Code < Node
4
+ def initialize(statements)
5
+ statements = [] if statements.to_s.blank?
6
+
7
+ @statements =
8
+ statements.map { |statement| ::Code::Node::Statement.new(statement) }
9
+ end
10
+
11
+ def evaluate(**args)
12
+ @statements.map { |statement| statement.evaluate(**args) }.last
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ class Code
2
+ class Node
3
+ class Defined < Node
4
+ def initialize(defined)
5
+ @name = defined.fetch(:name)
6
+ end
7
+
8
+ def evaluate(**args)
9
+ ::Code::Object::Boolean.new(args.fetch(:context).key?(name))
10
+ end
11
+
12
+ private
13
+
14
+ def name
15
+ ::Code::Object::String.new(@name.to_s)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ class Code
2
+ class Node
3
+ class Dictionnary < Node
4
+ def initialize(key_values)
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
13
+ end
14
+
15
+ def evaluate(**args)
16
+ ::Code::Object::Dictionnary.new(
17
+ @key_values.map { |key_value| key_value.evaluate(**args) }.to_h,
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ class Code
2
+ class Node
3
+ class DictionnaryKeyValue < Node
4
+ def initialize(key_value)
5
+ @key = key_value.fetch(:key)
6
+
7
+ if @key.is_a?(Array)
8
+ @key = ::Code::Node::Code.new(@key)
9
+ elsif @key.key?(:name)
10
+ @key = ::Code::Node::String.new(@key[:name])
11
+ else
12
+ @key = ::Code::Node::Statement.new(@key)
13
+ end
14
+
15
+ @value = ::Code::Node::Code.new(key_value.fetch(:value))
16
+ end
17
+
18
+ def evaluate(**args)
19
+ [@key.evaluate(**args), @value.evaluate(**args)]
20
+ end
21
+ end
22
+ end
23
+ 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
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Node
3
+ class Group < Node
4
+ def initialize(group)
5
+ @code = ::Code::Node::Code.new(group)
6
+ end
7
+
8
+ def evaluate(**args)
9
+ @code.evaluate(**args)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -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
@@ -0,0 +1,19 @@
1
+ class Code
2
+ class Node
3
+ class List < Node
4
+ def initialize(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
12
+ end
13
+
14
+ def evaluate(**args)
15
+ ::Code::Object::List.new(@codes.map { |code| code.evaluate(**args) })
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,50 @@
1
+ class Code
2
+ class Node
3
+ class Name < Node
4
+ def initialize(name)
5
+ @name = name
6
+ end
7
+
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
41
+ end
42
+
43
+ private
44
+
45
+ def name
46
+ ::Code::Object::String.new(@name.to_s)
47
+ end
48
+ end
49
+ end
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
@@ -0,0 +1,12 @@
1
+ class Code
2
+ class Node
3
+ class Nothing < Node
4
+ def initialize
5
+ end
6
+
7
+ def evaluate(**args)
8
+ ::Code::Object::Nothing.new
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ class Code
2
+ class Node
3
+ class Number < Node
4
+ def initialize(number)
5
+ if number.key?(:base_2)
6
+ @number = ::Code::Node::Base2Number.new(number[:base_2])
7
+ elsif number.key?(:base_8)
8
+ @number = ::Code::Node::Base8Number.new(number[:base_8])
9
+ elsif number.key?(:base_10)
10
+ @number = ::Code::Node::Base10Number.new(number[:base_10])
11
+ elsif number.key?(:base_16)
12
+ @number = ::Code::Node::Base16Number.new(number[:base_16])
13
+ else
14
+ raise NotImplementedErorr.new(number.inspect)
15
+ end
16
+ end
17
+
18
+ def evaluate(**args)
19
+ @number.evaluate(**args)
20
+ end
21
+ end
22
+ end
23
+ end