code-ruby 0.2.4

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.
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